C笔试题之编程题一


1、编写一个简单函数检查处理器是 big-endian 还是 little-endian。

  定义:

  little-endian  就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;

  big-endian    就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端;

  网络字节序  TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

  思路:

  由于联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little- endian还是Big-endian模式读写。

 1 #include <stdio.h>
 2 
 3 int main(void)  4 {  5  union MyUnion  6  {  7         unsigned int a;  8         unsigned char b;  9  }; 10     
11  union MyUnion test; 12     test.a = 1; 13     printf("%d\n", test.b);//1:little-endian 0:big-endian
14 
15     return 0; 16 }

 

  如上图,我的处理器是 little-endian。

2、假设 x = 9999,求下面函数的返回值。—— 微软

 

 1 int func(x) 
 2 { 
 3     int countx =0; 
 4     while (x) 
 5     { 
 6           countx++; 
 7           x = x & (x - 1); 
 8     } 
 9     return countx; 
10 }

 

  思路:将 x 转换为二进制表示,看其中1的个数。如 x = 9999 = 0B0010 0111 0000 1111(对于二进制数前缀0B,有的编译器可能会出错),其中有8个1,则函数返回值 countx=8。

  原理:每执行一次 x  =  x & (x - 1),会将 x 用二进制表示时最右边的一个1变为0,因为 x - 1 将会将该位(x用二进制表示时最右边的一个1)变为0。

 

 1 #include <stdio.h>
 2 
 3 int func(int x);
 4 
 5 int main(void)
 6 {
 7     int x;
 8 
 9     printf("please enter a integer(>0):");
10     if ((1 == (scanf("%d", &x))) && (x > 0))
11         printf("%d\n",func(x));
12     else
13         printf("please enter a integer(>0)\n");
14 
15     return 0;
16 }
17 
18 int func(int x)
19 {
20     int countx = 0;
21     while (x)
22     {
23         countx++;
24         x = x & (x - 1);
25     }
26     return countx;
27 }

 

  验证代码如上,如键入9999,结果如下:

 3、请编写一个简单的函数判断一个数是否是2的n次方。

  思路:如果一个整数是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0。此题转变为判断一个整数用二进制数表示时最高位是否为1,用 (x = x & (x - 1))  == 0可判断,此题与例2均为巧用 x = x & (x - 1)。

 1 #include <stdio.h>
 2 
 3 void func(int x);
 4 
 5 int main(void)
 6 {
 7     int x;
 8 
 9     printf("please enter a integer(>=0):");
10     if (1 == scanf("%d", &x))
11         func(x);
12     else
13         printf("please ensure it's a integer.\n");
14 
15     return 0;
16 }
17 
18 void func(int x)
19 {
20     if (0 == (x = x & (x - 1)))
21         printf("Yes.\n");
22     else
23         printf("No.\n");
24 }

 4、下面关于“联合”的程序的输出是什么?

 1 #include <stdio.h>
 2 
 3 union
 4 {
 5     int i;
 6     char x[2];
 7 }a;
 8 
 9 void main(void)
10 {
11     a.x[0] = 10;
12     a.x[1] = 1;
13     printf("%d\n", a.i);
14 }

 

   思路:整型变量 i 和 char 型数组共享一个内存地址。值以数组形式存入,以整型变量读出。

  注意:x[0]内存低地址,x[1]内存高地址。当处理器为 little-endian 时,以整型变量读出为 0X010A;当处理器为 big-endian 时,以整型变量读出为 0X0A01。

   我的PC处理器为 little-endian ,所以程序输出为 0X010A,即266。

5、下面关于“联合”的程序的输出是什么?

 

 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5     union
 6     {
 7         int i;
 8         struct
 9         {
10             char first;
11             char second;
12         }half;
13     }number;
14 
15     number.i = 0x4241;
16     printf("%c%c\n", number.half.first, number.half.second);
17 
18     number.half.first = 'a';
19     number.half.second = 'b';
20     printf("%x\n", number.i);
21 
22     return 0;
23 }

  思路:1、联合体中各成员共享一块内存(内存地址相同),故整型变量 i 与结构体 half 内存地址相同;

        2、程序中动态变量存放在栈中,先定义先分配内存。对于单字节数据,很好理解;对于多字节数据,存在处理器是 big-endian 还是 little-endian 的问题。big-endian 的处理器存储时将多字节的高位放在低地址,低位放在高地址,读出时也将低地址的字节认为是高位,高地址的字节认为是高位;little-endian 的处理器存储时将多字节的高位放在高地址,低位放在低地址,读出时将低地址的字节认为是低位,高地址的字节认为是高位。

        3、我的PC处理器是 little-endian,故四字节 i 的高位放置在高地址、低位放置在低地址,number.half.first 对应 i 的低地址,number.half.second 对应 i 的次低地址。

        number.i = 0x4241,则 number.half.first = 0x41 = 'A' ; number.half.second = 0x42 = 'B' ; printf语句打印出 AB

        number.half.first = 'a', number.half.second = 'b', 则 i 的低地址存储 ‘a’ = 97 = 0x61,  i 的次低地址存储 'b' = 98 = 0x62; i 的高位及次高位为 0x0000;  printf 语句打印出6261,需要打印出 0x 则需要使用 %#x 格式控制符。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM