程序员笔试题集合

整理一下最近遇到的笔试题,希望能被offer砸死。

第一题 int **a[2][4]在32位的机器上占用多少内存?

这定义了一个2*4的指针数组,每个指针的大小是4字节,所以总共占用了 2*4*4=32字节。int* 是指向数组的指针,int**是指向指针的指针,所以都是4字节。

第二题 #ifdef #if defined #if的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define TEST1 1
#define TEST2 0
int main(){
int count=0;

#ifdef TEST2
count+=1;
#endif

#if defined TEST1
count+=2;
#endif

#if(TEST1)
count+=4;
#endif

#if(TEST2)
count+=8;
#endif

printf("count=%d\n",count);
return 0;
}

这段代码的输出是多少?

答案是count=7

  1. #ifdef和#if defined判断是否宏定义过,区别是#ifdef只能判断单个宏是否定义过,#if defined可以写一些复杂的语法,比如

    1
    #if defined (A) && defined (B)
  2. #if后面接表达式,表达式为真,编译器就会将后面的代码编译进去。

  3. 最后强调一点,这些宏定义都是决定代码是否会被编译,不是执行。

第三题 Union

1
2
3
4
5
6
7
8
9
10
11
12
int main(){
union{
int c;
struct{
int a;
int b;
}b;
int a;
}test;
test.b.a=1;
printf("%d %d %d\n",test.a,test.b.b,test.c);
}

运行后:test.a=1,test.b.b不确定,test.c=1;

Union的所有成员共用一个内存空间,内存空间以size最大的成员变量为准,所有成员从低地址开始对齐。一次只能访问一个成员变量,在对某个成员变量修改时也会改变其他成员变量的值,但当size不同时,只会覆盖相对应的内存部分。
在本题中,test.b.a的值修改后,test.a、test.c与其内存地址相同,也会被覆盖,test.b.b不会被修改,没有赋初值,所以是不确定。

大端模式和小端模式

  • 大端模式(Big endian):数据的高字节存储在低地址中。
  • 小端模式(Little endian):数据的低字节存储在低地址中。

union中的成员变量都是从低地址开始对齐的,所以,在不同的CPU下会有不同的结果,可以由union来判断CPU类型,看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(){
union{
struct{
char a;
char b;
char c;
char d;
}s;
int x;
}test;
test.s.a=1;
test.s.b=2;
test.s.c=3;
test.s.d=4;
printf("0X%08x",test.x);
}

char占1字节,int占4字节,由低地址开始对齐,每个地址存放一个字节(8位),在一个字节中的数是固定的,比如地址0x00存放的是01而不是10,与大小端无关。而int型占了4字节,如果是在小端模式下,低位地址存的是数据低位,test.x数据从高位到低位为04030201;在大端模式下,低位地址存的是数据高位,test.x为01020304,注意这个数是十六进制的。根据这个值就可以判断CPU是什么模式的了。一般的x86架构都是小端模式。

地址 0x00 0x01 0x02 0x03
test.s 01 02 03 04

主机序和网络序

  • 主机序:不同的CPU有不同的字节序类型,即整数在内存中保存的顺序,一般有两种,就是之前说的大端模式与小端模式。
  • 网络序:TCP/IP中定义的数据表示格式,保证数据在不同CPU类型的主机之间传输时能被正确解释。网络字节序采用大端模式。在数据传输时会进行主机序与网络序之间的转换,保证数据的正确性。

第四题 JavaScript 变量作用域

1
2
3
4
5
6
7
var s = "global";
function f(){
console.log(s);
var s = "local";
console.log(s);
}
f();

运行结果为:

undefined  
local

Javascript中没有块级作用域,只有函数作用域,var声明的变量都是局部变量,变量在声明它的函数体内是有定义的。第一句的console.log(s)在s未声明就使用了,这时s是未定义的,外面定义的变量并不能作用到函数内部。

第五题 sizeof strlen

1
2
3
4
5
6
7
int main(){
char str[10]="Hel\0lo\0";
int len1 = strlen(str);
int len2 = sizeof(str);
printf("%d %d",len1,len2);

}

运行结果为:3 10

  • sizeof 是运算符,其值在编译时就计算好了,获得能容纳实现所建立的最大对象的字节大小。
  • strlen 是函数,是在运行时计算的,返回字符串的长度,从第一个地址开始遍历,直到遇到字符串的结束符’\0’。