C谜题解释

看到了这个网址http://www.gowrikumar.com/c/,作者收集了一系列网上和自己所遇到的C语言有趣的东西,我感觉挺像<Java解惑>的风格,我下面就尝试解决一下作者提出的问题.

第一题

  1. The expected output of the following C program is to print the elements in the array. But when actually run, it doesn't do so.  
  2.   
  3. #include<stdio.h>  
  4.   
  5. #define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))  
  6. int array[] = {23,34,12,17,204,99,16};  
  7.   
  8. int main()  
  9. {  
  10.         int d;  
  11.   
  12.         for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)  
  13.                 printf("%d\n",array[d+1]);  
  14.   
  15.         return 0;  
  16. }  
  17.   
  18. Find out what's going wrong.  
这道题作者给出了提示,因为sizeof操作符返回的是size_t类型,一般情况下size_t是无符号类型,所以在for循环中当-1与(TOTAL_ELEMENTS-2)比较时,-1首先被转换成无符号数来进行比较,此时-1被解释为一个很大的整数,大于(TOTAL_ELEMENTS-2)的值,所以代码什么也不输出,与程序作者本意相违背.

第二题:

  1. I thought the following program was a perfect C program. But on compiling, I found a silly mistake. Can you find it out (without compiling the program :-) ?  
  2.   
  3. #include<stdio.h>  
  4.   
  5. void OS_Solaris_print()  
  6. {  
  7.     printf("Solaris - Sun Microsystems\n");  
  8. }  
  9.   
  10. void OS_Windows_print()  
  11. {  
  12.     printf("Windows - Microsoft\n");  
  13.   
  14. }  
  15. void OS_HP-UX_print()  
  16. {  
  17.     printf("HP-UX - Hewlett Packard\n");  
  18. }  
  19.   
  20. int main()  
  21. {  
  22.     int num;  
  23.     printf("Enter the number (1-3):\n");  
  24.     scanf("%d",&num);  
  25.     switch(num)  
  26.     {  
  27.         case 1:  
  28.             OS_Solaris_print();  
  29.             break;  
  30.         case 2:  
  31.             OS_Windows_print();  
  32.             break;  
  33.         case 3:  
  34.             OS_HP-UX_print();  
  35.             break;  
  36.         default:  
  37.             printf("Hmm! only 1-3 :-)\n");  
  38.             break;  
  39.     }  
  40.   
  41.     return 0;  
  42. }  
这道题比较简单,就是函数OS_HP-UX_print()中间不能有符号-,作者也给出了提示.

第三道题:

  1. What's the expected output for the following program and why?  
  2.   
  3. enum {false,true};  
  4.   
  5. int main()  
  6. {  
  7.         int i=1;  
  8.         do  
  9.         {  
  10.                 printf("%d\n",i);  
  11.                 i++;  
  12.                 if(i < 15)  
  13.                         continue;  
  14.         }while(false);  
  15.         return 0;  
  16. }  
作者也给出了提示,在K&R的书中提到,在while与do while语句中,continue语句的执行意味着立即执行测试部分.所以上述程序只输出1,同时要注意程序没有导入stdio.h头文件,在一些编译器上会出错.

第四道题:

  1. The following program doesn't "seem" to print "hello-out". (Try executing it)  
  2.   
  3.   #include <stdio.h>  
  4.   #include <unistd.h>  
  5.   int main()  
  6.   {  
  7.           while(1)  
  8.           {  
  9.                   fprintf(stdout,"hello-out");  
  10.                   fprintf(stderr,"hello-err");  
  11.                   sleep(1);  
  12.           }  
  13.           return 0;  
  14.   }  
  15.   
  16. What could be the reason?  
这道题我不明白,应该是与多线程之类的有关系(以后再弄)

第五道题:

  1.   #include <stdio.h>  
  2.   #define f(a,b) a##b  
  3.   #define g(a)   #a  
  4.   #define h(a) g(a)  
  5.   
  6.   int main()  
  7.   {  
  8.           printf("%s\n",h(f(1,2)));  
  9.           printf("%s\n",g(f(1,2)));  
  10.           return 0;  
  11.   }  
  12.   
  13. Just by looking at the program one "might" expect the output to be, the same for both the printf statements. But on running the program you get it as:  
  14. bash$ ./a.out  
  15. 12  
  16. f(1,2)  
  17. bash$  
  18.   
  19. Why is it so?  
这道题我也不明白,以后再做

第六道题:

  1. #include<stdio.h>  
  2. int main()  
  3. {  
  4.         int a=10;  
  5.         switch(a)  
  6.         {  
  7.                 case '1':  
  8.                     printf("ONE\n");  
  9.                     break;  
  10.                 case '2':  
  11.                     printf("TWO\n");  
  12.                     break;  
  13.                 defa1ut:  
  14.                     printf("NONE\n");  
  15.         }  
  16.         return 0;  
  17. }  
  18.   
  19.  you expect the output of the above program to be NONE, I would request you to check it out!!  
这道题需要细心观察,default在程序中被写成了defalut,而这在某些编译器是可以编译运行的(我在gcc,vc测过,是可以运行的),所以程序什么都不会输出.

第七道题:

  1. The following C program segfaults of IA-64, but works fine on IA-32.  
  2.   
  3.   int main()  
  4.   {  
  5.       int* p;  
  6.       p = (int*)malloc(sizeof(int));  
  7.       *p = 10;  
  8.       return 0;  
  9.   }  
  10.   
  11. Why does it happen so?  
注意这个程序没有引入malloc函数原型所在的头文件,在IA-32平台下,因为没有指定头文件,编译器默认返回了一个32位的指针类型,在IA-64的情况下,因为没有指定头文件编译器还是返回的32位的,这样在转换的过程中将64位的截断成了32位,所以就出现段错误了.

第八道题:

  1. Here is a small piece of program(again just 14 lines of program) which counts the number of bits set in a number.  
  2. Input   Output  
  3. 0   0(0000000)  
  4. 5   2(0000101)  
  5. 7   3(0000111)  
  6.   
  7.   int CountBits (unsigned int x )  
  8.   {  
  9.       static unsigned int mask[] = { 0x55555555,  
  10.           0x33333333,  
  11.           0x0F0F0F0F,  
  12.           0x00FF00FF,  
  13.           0x0000FFFF  
  14.           } ;  
  15.   
  16.           int i ;  
  17.           int shift ; /* Number of positions to shift to right*/  
  18.           for ( i =0, shift =1; i < 5; i ++, shift *= 2)  
  19.                   x = (x & mask[i ])+ ( ( x >> shift) & mask[i]);  
  20.           return x;  
  21.   }  
  22.   
  23. Find out the logic used in the above program.   
位运算技巧的运用,以后再弄

第九道题:

  1. What do you think would be the output of the following program and why? (If you are about to say "f is 1.0", I would say check it out again)  
  2.   
  3. #include <stdio.h>  
  4.   
  5. int main()  
  6. {  
  7.         float f=0.0f;  
  8.         int i;  
  9.   
  10.         for(i=0;i<10;i++)  
  11.                 f = f + 0.1f;  
  12.   
  13.         if(f == 1.0f)  
  14.                 printf("f is 1.0 \n");  
  15.         else  
  16.                 printf("f is NOT 1.0\n");  
  17.   
  18.         return 0;  
  19. }  
浮点数加减法有很多让人意想不到的东西,特别是大数与小数相加时,所以出书f is NOT 1.0就是不足为奇了.

第十道题:

  1. I thought the following C program is perfectly valid (after reading about the comma operator in C). But there is a mistake in the following program, can you identify it?  
  2.   
  3. #include <stdio.h>  
  4.   
  5. int main()  
  6. {  
  7.         int a = 1,2;  
  8.         printf("a : %d\n",a);  
  9.         return 0;  
  10. }  
这里逗号的本意是将两个句子和在一块,少写分号.但是int a = 1做单个句子缺少分号;所以出现编译错误,要想避免编译错误有两种方法,第一种:将1,2用括号括起来,即a = (1,2);这时候a被初始化为2,或者int a; a = 1,2;此时a = 1.

第十一道题:

  1. What would be the output of the following C program? (Is it a valid C program?)  
  2.   
  3. #include <stdio.h>  
  4. int main()  
  5. {  
  6.         int i=43;  
  7.         printf("%d\n",printf("%d",printf("%d",i)));  
  8.         return 0;  
  9. }  
printf函数的返回值是被打印的字符数,所以程序输出4321,另外这道题是ppurl.com注册时的一个题,很有点意思.

第十二道题:

  1. void duff(register char *to, register char *from, register int count)  
  2.  {  
  3.      register int n=(count+7)/8;  
  4.      switch(count%8){  
  5.      case 0: do{ *to++ = *from++;  
  6.      case 7:  *to++ = *from++;  
  7.      case 6: *to++ = *from++;  
  8.      case 5: *to++ = *from++;  
  9.      case 4: *to++ = *from++;  
  10.      case 3: *to++ = *from++;  
  11.      case 2: *to++ = *from++;  
  12.      case 1: *to++ = *from++;  
  13.              }while( --n >0);  
  14.      }  
  15.  }  
  16.   
  17. s the above valid C code? If so, what is it trying to acheive and why would anyone do something like the above?   
这段代码是合法的,在很多对性能要求苛刻的程序(如驱动程序中)有可能会用到, 维基 这篇文章阐述了这个东西,我表示自己也没理解透

第十三道题:

  1. Here is yet another implementation of CountBits. Verify whether it is correct (how do you that???). If so, find out the logic used.  
  2.   
  3.   int CountBits(unsigned int x)  
  4.   {  
  5.       int count=0;  
  6.       while(x)  
  7.       {  
  8.           count++;  
  9.           x = x&(x-1);  
  10.       }  
  11.       return count;  
  12.   }  
位运算,x - 1将x二进制中最低位为1的进行借位,之后再&去除一个为1的位,这个方法也可以用来判断一个数是不是2的幂,有点意思

第十四道题:

  1. Are the following two function prototypes same?  
  2.   
  3.   int foobar(void);  
  4.   int foobar();  
  5.   
  6. The following programs should be of some help in finding the answer: (Compile and run both the programs and see what happens)  
  7. Program 1:  
  8.   
  9.   #include <stdio.h>  
  10.   void foobar1(void)  
  11.   {  
  12.    printf("In foobar1\n");  
  13.   }  
  14.   
  15.   void foobar2()  
  16.   {  
  17.    printf("In foobar2\n");  
  18.   }  
  19.   
  20.   int main()  
  21.   {  
  22.      char ch = 'a';  
  23.      foobar1();  
  24.      foobar2(33, ch);  
  25.      return 0;  
  26.   }  
  27.   
  28. Program 2:  
  29.   
  30.   #include <stdio.h>  
  31.   void foobar1(void)  
  32.   {  
  33.    printf("In foobar1\n");  
  34.   }  
  35.   
  36.   void foobar2()  
  37.   {  
  38.    printf("In foobar2\n");  
  39.   }  
  40.   
  41.   int main()  
  42.   {  
  43.      char ch = 'a';  
  44.      foobar1(33, ch);  
  45.      foobar2();  
  46.      return 0;  
  47.   }  
首先这两个函数原型肯定是不一样的,第一个int foobar(void)表示函数不接受任何的参数,第二个int foobar()表示函数接受任意个数的参数,这说起来都是C语言的遗产了,K&R里面做了阐述,在C语言做标准化时引入了foobar(void)这样的void表示函数不接受任何参数,但是为了使得标准化之前的C代码还能够编译便保留了int foobar()这样的声明,且K&R建议在函数不需要参数的时候显式传入void,即第一种用法.上述程序中第一个程序能够编译通过,第二个则会报错.

第十五道题:

  1. What's the output of the following program and why?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.    float a = 12.5;  
  7.    printf("%d\n", a);  
  8.    printf("%d\n", *(int *)&a);  
  9.    return 0;  
  10.   }  
第二句printf将一个浮点数的二进制byte序列强制按一个int值来解读,所以会根据12.5在内存中的位序列将其解释为一个整数,或大或小.

第十六道题:

  1. The following is a small C program split across files. What do you expect the output to be, when both of them compiled together and run?  
  2. File1.c  
  3.   
  4.   int arr[80];  
  5.   
  6. File2.c  
  7.   
  8.   extern int *arr;  
  9.   int main()  
  10.   {  
  11.       arr[1] = 100;  
  12.       return 0;  
  13.   }  
很经典的一道题,<C专家编程>上解释过

第十七道:

  1. Explain the output of the following C program (No, the output is not 20).  
  2.   
  3.   #include<stdio.h>  
  4.   int main()  
  5.   {  
  6.       int a=1;  
  7.       switch(a)  
  8.       {   int b=20;  
  9.           case 1: printf("b is %d\n",b);  
  10.                   break;  
  11.           default:printf("b is %d\n",b);  
  12.                   break;  
  13.       }  
  14.       return 0;  
  15.   }  
作者给出了说明,输出肯定不是20,b输出的是一些随机的未初始化垃圾值,这是因为在switch中程序从default(如果没有case的话)或者case来开始执行,所以int b = 20;这一句没有执行,b是一些垃圾值.事实上在一些高级语言中,上述写法会报错,比如actionscript 3中上述写法就会报错"需要 CaseLabel".

第十八道:

  1. What is the output of the following program? (Again, it is not 40, (if the size of integer is 4)).  
  2.   
  3.   #define SIZE 10  
  4.   void size(int arr[SIZE])  
  5.   {  
  6.           printf("size of array is:%d\n",sizeof(arr));  
  7.   }  
  8.   
  9.   int main()  
  10.   {  
  11.           int arr[SIZE];  
  12.           size(arr);  
  13.           return 0;  
  14.   }  
犯了一个大错误,函数中不能传递数组的,只能通过指针和int arr[]这样的方式来传递,作者本意是给size函数传递一个10个元素的int型数组,但是arr[10]只是一个数,其含义在传递函数是与int* arr和int arr[]含义是不同的,不能这样用,另外需要注意的是sizeof(数组)只会返回整个数组所占字节的大小,而不是数组中元素的个数.

第十九道:

  1. The following is a simple c program, in which there is a function called Error to display errors. Can you see a potential problem with the way Error is defined?  
  2.   
  3.   #include <stdlib.h>  
  4.   #include <stdio.h>  
  5.   void Error(char* s)  
  6.   {  
  7.       printf(s);  
  8.       return;  
  9.   }  
  10.   
  11.   int main()  
  12.   {  
  13.       int *p;  
  14.       p = malloc(sizeof(int));  
  15.       if(p == NULL)  
  16.       {  
  17.           Error("Could not allocate the memory\n");  
  18.           Error("Quitting....\n");  
  19.           exit(1);  
  20.       }  
  21.       else  
  22.       {  
  23.           /*some stuff to use p*/  
  24.       }  
  25.       return 0;  
  26.   }  
挑不出啥大毛病,以后看

第二十道题:

  1. What is the differnce between the following function calls to scanf?(Please notice the space carefully in the second call. Try removing it and observe the behaviour of the program)  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       char c;  
  7.       scanf("%c",&c);  
  8.       printf("%c\n",c);  
  9.   
  10.       scanf(" %c",&c);  
  11.       printf("%c\n",c);  
  12.   
  13.       return 0;  
  14.   }  
不晓得,以后看

第二十一道:

  1. What is the potential problem with the following C program?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       char str[80];  
  7.       printf("Enter the string:");  
  8.       scanf("%s",str);  
  9.       printf("You entered:%s\n",str);  
  10.   
  11.       return 0;  
  12.   }  

字符串结尾问题,如果输入的过长,超过了80个字符,则str字符数组最后一个元素就不是\0,printf函数在打印时则会造成程序的越界访问甚至会崩溃.

第二十二道:

  1. What is the output of the following program?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int i;  
  7.       i = 10;  
  8.       printf("i : %d\n",i);  
  9.       printf("sizeof(i++) is: %d\n",sizeof(i++));  
  10.       printf("i : %d\n",i);  
  11.       return 0;  
  12.   }  
这个简单,sizeof操作符不会对其中传入的表达式或者函数等等求值,所以程序在32位机器输出10,4,10

第二十三道:

  1. Why does the following program give a warning? (Please remember that sending a normal pointer to a function requiring const pointer does not give any warning)  
  2.   
  3.   #include <stdio.h>  
  4.   void foo(const char **p) { }  
  5.   int main(int argc, char **argv)  
  6.   {  
  7.           foo(argv);  
  8.           return 0;  
  9.   }  
以后解决

第二十四道:

  1. What is the output of the following program?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.           int i;  
  7.           i = 1,2,3;  
  8.           printf("i:%d\n",i);  
  9.           return 0;  
  10.   }  
这个和之前有关逗号的题一样,实际上是i = 1;2;3;这三句,所以会输出1.

第二十五道:

  1. The following is a piece of code which implements the reverse Polish Calculator. There is a(are) serious(s) bug in the code. Find it(them) out!!! Assume that the function getop returns the appropriate return values for operands, opcodes, EOF etc..  
  2.   
  3.   #include <stdio.h>  
  4.   #include <stdlib.h>  
  5.   
  6.   #define MAX 80  
  7.   #define NUMBER '0'  
  8.   
  9.   int getop(char[]);  
  10.   void push(double);  
  11.   double pop(void);  
  12.   int main()  
  13.   {  
  14.       int type;  
  15.       char s[MAX];  
  16.   
  17.       while((type = getop(s)) != EOF)  
  18.       {  
  19.           switch(type)  
  20.           {  
  21.               case NUMBER:  
  22.                   push(atof(s));  
  23.                   break;  
  24.               case '+':  
  25.                   push(pop() + pop());  
  26.                   break;  
  27.               case '*':  
  28.                   push(pop() * pop());  
  29.                   break;  
  30.               case '-':  
  31.                   push(pop() - pop());  
  32.                   break;  
  33.               case '/':  
  34.                   push(pop() / pop());  
  35.                   break;  
  36.               /*   ...  
  37.                *   ...     
  38.                *   ...  
  39.                */  
  40.           }  
  41.       }  
  42.   }  
不会,以后弄

第二十六道:

  1. The following is a simple program which implements a minimal version of banner command available on most *nix systems. Find out the logic used in the program.  
  2.   
  3.   #include<stdio.h>  
  4.   #include<ctype.h>  
  5.   
  6.   char t[]={  
  7.       0,0,0,0,0,0,12,18,33,63,  
  8.       33,33,62,32,62,33,33,62,30,33,  
  9.       32,32,33,30,62,33,33,33,33,62,  
  10.       63,32,62,32,32,63,63,32,62,32,  
  11.       32,32,30,33,32,39,33,30,33,33,  
  12.       63,33,33,33,4,4,4,4,4,4,  
  13.       1,1,1,1,33,30,33,34,60,36,  
  14.       34,33,32,32,32,32,32,63,33,51,  
  15.       45,33,33,33,33,49,41,37,35,33,  
  16.       30,33,33,33,33,30,62,33,33,62,  
  17.       32,32,30,33,33,37,34,29,62,33,  
  18.       33,62,34,33,30,32,30,1,33,30,  
  19.       31,4,4,4,4,4,33,33,33,33,  
  20.       33,30,33,33,33,33,18,12,33,33,  
  21.       33,45,51,33,33,18,12,12,18,33,  
  22.       17,10,4,4,4,4,63,2,4,8,  
  23.       16,63  
  24.       };  
  25.   
  26.   int main(int argc,char** argv)  
  27.   {  
  28.   
  29.       int r,pr;  
  30.       for(r=0;r<6;++r)  
  31.           {  
  32.           char *p=argv[1];  
  33.   
  34.           while(pr&&*p)  
  35.               {  
  36.               int o=(toupper(*p++)-'A')*6+6+r;  
  37.               o=(o<0||o>=sizeof(t))?0:o;  
  38.               for(pr=5;pr>=-1;--pr)  
  39.                   {  
  40.                   printf("%c",( ( (pr>=0) && (t[o]&(1<<pr)))?'#':' '));  
  41.   
  42.                   }  
  43.               }  
  44.           printf("\n");  
  45.           }  
  46.       return 0;  
  47.   }  
不会,以后弄

第二十七道:

  1. What is the output of the following program?  
  2.   
  3.   #include <stdio.h>  
  4.   #include <stdlib.h>  
  5.   
  6.   #define SIZEOF(arr) (sizeof(arr)/sizeof(arr[0]))  
  7.   
  8.   #define PrintInt(expr) printf("%s:%d\n",#expr,(expr))  
  9.   int main()  
  10.   {  
  11.       /* The powers of 10 */  
  12.       int pot[] = {  
  13.           0001,  
  14.           0010,  
  15.           0100,  
  16.           1000  
  17.       };  
  18.       int i;  
  19.   
  20.       for(i=0;i<SIZEOF(pot);i++)  
  21.           PrintInt(pot[i]);  
  22.       return 0;  
  23.   }  
C语言中数字以0开头的话表示的是八进制的计数,所以上面数组中的前三项化为十进制为1,8,64,背离了程序作者的真实意思,在八进制时数字钟不能出现8,9这两个数

第二十八道:

  1. The following is the implementation of the Euclid's algorithm for finding the G.C.D(Greatest Common divisor) of two integers. Explain the logic for the below implementation and think of any possible improvements on the current implementation.  
  2. BTW, what does scanf function return?  
  3.   
  4.   #include <stdio.h>  
  5.   int gcd(int u,int v)  
  6.   {  
  7.       int t;  
  8.       while(v > 0)  
  9.       {  
  10.           if(u > v)  
  11.           {  
  12.               t = u;  
  13.               u = v;  
  14.               v = t;  
  15.           }  
  16.           v = v-u;  
  17.       }  
  18.       return u;  
  19.   }  
  20.   
  21.   int main()  
  22.   {  
  23.       int x,y;  
  24.       printf("Enter x y to find their gcd:");  
  25.       while(scanf("%d%d",&x, &y) != EOF)  
  26.       {  
  27.           if(x >0 && y>0)  
  28.               printf("%d %d %d\n",x,y,gcd(x,y));  
  29.                   printf("Enter x y to find their gcd:");  
  30.       }  
  31.       printf("\n");  
  32.       return 0;  
  33.   }  
  34.   
  35. Also implement a C function similar to the above to find the GCD of 4 integers.  
表示不会,以后弄

第二十九道:

  1. What's the output of the following program. (No, it's not 10!!!)  
  2.   
  3.   #include <stdio.h>  
  4.   #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))  
  5.   int main()  
  6.   {  
  7.       int y = 100;  
  8.       int *p;  
  9.       p = malloc(sizeof(int));  
  10.       *p = 10;  
  11.       y = y/*p; /*dividing y by *p */;  
  12.       PrintInt(y);  
  13.       return 0;  
  14.   }  
/*与语句最后面的*/构成了注释符号,所以y = y/*p这句实际上成了y = y;所以程序会输出y:100.要想避免这样的情况很简单,用括号就行了即y = y/(*p);或者唉/*之间打个空格就够了此时程序就变成了y = y/ *p;这样就不会与后面的构成注释了.

第三十道:

  1. The following is a simple C program to read a date and print the date. Run it and explain the behaviour  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int day,month,year;  
  7.       printf("Enter the date (dd-mm-yyyy) format including -'s:");  
  8.       scanf("%d-%d-%d",&day,&month,&year);  
  9.       printf("The date you have entered is %d-%d-%d\n",day,month,year);  
  10.       return 0;  
  11.   }  
以后看

第三十一道:

  1. The following is a simple C program to read and print an integer. But it is not working properly. What is(are) the mistake(s)?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int n;  
  7.       printf("Enter a number:\n");  
  8.       scanf("%d\n",n);  
  9.   
  10.       printf("You entered %d \n",n);  
  11.       return 0;  
  12.   }  

首先scanf中n是不对的,应该传入&n,此外scanf("%d\n",n)中的\n也是问题,scanf中尽量不要使用非输入控制符,像上面的程序就需要输入两个数字程序才能运行完毕.此外,这个程序估计还有别的我不知道的问题.

第三十二道:

  1. The following is a simple C program which tries to multiply an integer by 5 using the bitwise operations. But it doesn't do so. Explain the reason for the wrong behaviour of the program.  
  2.   
  3.   #include <stdio.h>  
  4.   #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))  
  5.   int FiveTimes(int a)  
  6.   {  
  7.       int t;  
  8.       t = a<<2 + a;  
  9.       return t;  
  10.   }  
  11.   
  12.   int main()  
  13.   {  
  14.       int a = 1, b = 2,c = 3;  
  15.       PrintInt(FiveTimes(a));  
  16.       PrintInt(FiveTimes(b));  
  17.       PrintInt(FiveTimes(c));  
  18.       return 0;  
  19.   }  
运算符优先级的问题,t = a << 2 + a,实际上等于t = a << (2 + a),所以出现了与程序作者原意不相符的情况.

第三十三道:

  1. Is the following a valid C program?  
  2.   
  3.   #include <stdio.h>  
  4.   #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))  
  5.   int max(int x, int y)  
  6.   {  
  7.       (x > y) ? return x : return y;  
  8.   }  
  9.   
  10.   int main()  
  11.   {  
  12.       int a = 10, b = 20;  
  13.       PrintInt(a);  
  14.       PrintInt(b);  
  15.       PrintInt(max(a,b));  
  16.   }  
不是合法的C程序,在gcc下报错error: expected expression before 'return'

第三十四道:

  1. The following is a piece of C code, whose intention was to print a minus sign 20 times. But you can notice that, it doesn't work.  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int i;  
  7.       int n = 20;  
  8.       for( i = 0; i < n; i-- )  
  9.           printf("-");  
  10.       return 0;  
  11.   }  
  12.   
  13. Well fixing the above code is straight-forward. To make the problem interesting, you have to fix the above code, by changing exactly one character. There are three known solutions. See if you can get all those three.  
作者要求只改动一个字符使上述程序正常运行,暂时没有方法,以后弄.

第三十五道:

  1. What's the mistake in the following code?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int* ptr1,ptr2;  
  7.       ptr1 = malloc(sizeof(int));  
  8.       ptr2 = ptr1;  
  9.       *ptr2 = 10;  
  10.       return 0;  
  11.   }  
初始化的问题,只有ptr1被生命为一个int指针,ptr2其实被声明为一个int类型,这是问题所在,修改为int *ptr1,*ptr2;即可

第三十六道:

  1. What is the output of the following program?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int cnt = 5, a;  
  7.   
  8.       do {  
  9.           a /= cnt;  
  10.       } while (cnt --);  
  11.   
  12.       printf ("%d\n", a);  
  13.       return 0;  
  14.   }  

当cnt为1时while(cnt--)为真,所以继续进行循环,而此时cnt经过自减操作cnt为0,所以a /= cnt成了a /= 0,会发生除零错误

第三十七道题:

  1. What is the output of the following program?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.       int i = 6;  
  7.       if( ((++i < 7) && ( i++/6)) || (++i <= 9))  
  8.           ;  
  9.       printf("%d\n",i);  
  10.       return 0;  
  11.   }  
输出8,这个是逻辑运算符中的短路原则使用.

第三十八道题:

  1. What is the bug in the following program?  
  2.   
  3.   #include <stdlib.h>  
  4.   #include <stdio.h>  
  5.   #define SIZE 15   
  6.   int main()  
  7.   {  
  8.       int *a, i;  
  9.   
  10.       a = malloc(SIZE*sizeof(int));  
  11.   
  12.       for (i=0; i<SIZE; i++)  
  13.           *(a + i) = i * i;  
  14.       for (i=0; i<SIZE; i++)  
  15.           printf("%d\n", *a++);  
  16.       free(a);  
  17.       return 0;  
  18.   }  
这里第二个for循环中printf("%d\n",*a++),修改了分配内存后a的值,造成了后面free(a)内存释放不成功,造成内存泄露.

第三十九道题:

  1. Is the following a valid C program? If so, what is the output of it?  
  2.   
  3.   #include <stdio.h>  
  4.   int main()  
  5.   {  
  6.     int a=3, b = 5;  
  7.   
  8.     printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);  
  9.     printf(&a["WHAT%c%c%c  %c%c  %c !\n"], 1["this"],  
  10.        2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);  
  11.     return 0;  
  12.   }  
不懂,以后弄

第四十道题:

  1. What is the output of the following, if the input provided is:  
  2. Life is beautiful  
  3.   
  4.   #include <stdio.h>  
  5.   int main()  
  6.   {  
  7.       char dummy[80];  
  8.       printf("Enter a string:\n");  
  9.       scanf("%[^a]",dummy);  
  10.       printf("%s\n",dummy);  
  11.       return 0;  
  12.   }  
不懂,以后弄

第四十一道题:

  1.  Note : This question has more to do with Linker than C language  
  2. We have three files a.c, b.c and main.c respectively as follows:  
  3. a.c  
  4. ---  
  5.   
  6. int a;  
  7.   
  8. b.c  
  9. ---  
  10.   
  11. int a = 10;  
  12.   
  13. main.c  
  14. ------  
  15.   
  16. extern int a;  
  17. int main()  
  18. {  
  19.         printf("a = %d\n",a);  
  20.         return 0;  
  21. }  
  22.   
  23. Let's see what happens, when the files are compiled together:  
  24.   
  25. bash$ gcc a.c b.c main.c  
  26. bash$ ./a.out  
  27. a = 10  
  28.   
  29. Hmm!! no compilation/linker error!!! Why is it so??   
不懂,以后弄

第四十二道题:

  1. The following is the offset macros which is used many a times. Figure out what is it trying to do and what is the advantage of using it.  
  2.   
  3.   #define offsetof(a,b) ((int)(&(((a*)(0))->b)))  

这是stddef.h里定义的一个宏,其返回值为size_t,它适用于结构和union,用于检索结构成员相对于父结构的偏移量,第一个参数为结构名称,第二个参数为结构中的字段名,其主要实现如下:将地址0强制转换为对应结构指针,此时结构的地址为0,然后使用->获得b的内容,再使用&操作符获得b的地址,再将b的地址转换为int类型,使用b的地址减去结构地址0(因为是0强转的),即为结构字段b相对于结构的偏移量,这种在嵌入式里面用的比较多,这里有一篇详解它的文章.它的使用例子如下:

  1. #include <stdio.h>  
  2. #include <stddef.h>  
  3.   
  4. void main(void)  
  5. {     
  6.     struct test  
  7.     {  
  8.         int a;  
  9.         short b;  
  10.         char c;  
  11.         int d;  
  12.     };  
  13.     struct test a;  
  14.     size_t offset = offsetof(struct test,c);  
  15.     printf("the offset of c is %d\n",offset);   /* 输出6,因为32位机器上int占4字节,short为2字节    */  
  16. }  

第四十三道题:

  1. The following is the macro implementation of the famous, Triple xor swap.  
  2.   
  3.   #define SWAP(a,b) ((a) ^= (b) ^= (a) ^= (b))  
  4.   
  5. What are the potential problems with the above macro?   
没有十足把握,不要乱用宏,首先扩展的问题,上面的宏SWAP(1,2)运行正常,SWAP(a++,b++)就会报错,SWAP(1 + 2,2 + 3)同样报错,那SWAP(SWAP(1+2),SWAP(2+3))更加报错,此外有可能还有我没发现的错误,所以还是那句话不是大牛,用宏一定要当心,宏也是会耍大牌的.

第四十四道题:

  1. What is the use of the following macro?  
  2.   
  3.   #define DPRINTF(x) printf("%s:%d\n",#x,x)  
宏中#的用法,很常见

第四十五道题:

  1. Let's say you were asked to code a function IAddOverFlow which takes three parameters, pointer to an integer where the result is to be stored, and the two integers which needs to be added. It returns 0 if there is an overflow and 1 otherwise:  
  2.   
  3.   int IAddOverFlow(int* result,int a,int b)  
  4.   {  
  5.       /* ... */  
  6.   }  
  7.   
  8. So, how do you code the above function? (To put in a nutshell, what is the logic you use for overflow detection?)   
不懂,以后弄

第四十六道题:

  1. What does the following macro do?  
  2.   
  3.   #define ROUNDUP(x,n) ((x+n-1)&(~(n-1)))  
不懂,以后弄

第四十七道题:

  1. Most of the C programming books, give the following example for the definition of macros.  
  2.   
  3.   #define isupper(c) (((c) >= 'A') && ((c) <= 'Z'))  
  4.   
  5. But there would be a serious problem with the above definition of macro, if it is used as follows (what is the problem??)  
  6.   
  7.   char c;  
  8.   /* ... */  
  9.   if(isupper(c++))  
  10.   {  
  11.       /* ... */  
  12.   }  
  13.   
  14. But most of the libraries implement the isupper (declared in ctypes.h) as a macro (without any side effects). Find out how isupper() is implemented on your system.   

如果调用issuper(c++),那么实际上c++在宏中调用了两次,比如c = 'Y',调用issuper(c++)完后Y就变成了字符[,与作者本意不同,因为作者本意是c++运算后,此时运算为字符'Z',一般机器上的都是用位运算来做的,因为大小写字母刚好差32,换算成十六进制就是0x20,即大小写字母只是在第六位(从右到左数)比特位上不相同,其他比特字节相同,所以用位运算又快又准确.

第四十八道题:

  1. I hope you know that ellipsis (...) is used to specify variable number of arguments to a function. (What is the function prototype declaration for printf?) What is wrong with the following delcaration?  
  2.   
  3.   int VarArguments(...)  
  4.   {  
  5.       /*....*/  
  6.       return 0;  
  7.   }  
不懂,以后弄

第四十九道题:

  1. Write a C program to find the smallest of three integers, without using any of the comparision operators.   

我的思路,使用位运算

  1. #include <stdio.h>  
  2.   
  3. /** 
  4.  * 找到两个数中的较小的数,如果相等返回同一个数 
  5.  * 这种方法只适用于使用补码表示有符号数的计算机,且是8比特补码系统 
  6.  */  
  7. int findLess(int a,int b)  
  8. {  
  9.     int c = a - b;  
  10.     int flag = c >> (sizeof(int) * 8 - 1);    /* 获取标志位 */  
  11.     if(flag)    /* 标志位为1表示结果为负数 */  
  12.     {  
  13.         return a;  
  14.     }  
  15.     else if(c)  /* 此时标志位为0,表示c为非负数,如果c为真,表示c大于0,返回b */  
  16.     {  
  17.         return b;  
  18.     }  
  19.     else        /* c为0,表示两个数相等 */  
  20.     {  
  21.         return a;  
  22.     }  
  23.     printf("compare error\n");  
  24.     return -1;  
  25. }  
  26.   
  27. void main(void)  
  28. {  
  29.     int a = 1,b = 2,c = 2;  
  30.       
  31.     printf("the small integer is %d\n",findLess(a,findLess(b,c)));  
  32. }  

第五十道题:

  1. What does the format specifier %n of printf function do?  

msdn描述如下,%n表示当前已经成功写入流或者缓冲的字符数目;该值保存在一个整数中,其地址作为参数传给printf函数,且说明%n内在并不安全,所以默认情况下是禁用的,要使用%n,请查看_set_printf_count_output等.例子如下:

  1. #include <stdio.h>  
  2.   
  3. /** 
  4.  * gcc编译 
  5.  */  
  6. void main(void)  
  7. {  
  8.     char* str = "hello world";  
  9.     int n;  
  10.     printf("%s\n%n",str,&n);    /* 传入n的地址 */  
  11.     printf("%d\n",n);           /* 打印n的值 */  
  12. }  

第五十一道题:

  1. Write a C function which does the addition of two integers without using the '+' operator. You can use only the bitwise operators.(Remember the good old method of implementing the full-adder circuit using the or, and, xor gates....)   
不懂,以后弄

第五十二道题:

  1. How do you print I can print % using the printf function? (Remember % is used as a format specifier!!!)   

  1. #include <stdio.h>  
  2.   
  3. void main(void)  
  4. {  
  5.     printf("I can print %% use the printf function\n");  
  6. }  

第五十三道题:

  1. What's the difference between the following two C statements?  
  2.   
  3.   const char *p;  
  4.   charconst p;  
含义不同,第一个表示的是p指向一个常量char或者非常量char,p在初始化为指向一个常量char之后还可以改变为指向别的char(常量或者非常量都可),也可使用*p作为只读的数据,但是不能使用*p来修改其所指向的char的值,即不允许你*p = 'a';之类的句子出现,示例程序如下:

  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     const char a = 'a';  
  6.     const char b = 'b';  
  7.     char c = 'c';  
  8.       
  9.     const char *p;  
  10.       
  11.     p = &a;  
  12.     printf("%c\n",*p);  /* 输出a */  
  13.     p = &b;  
  14.     printf("%c\n",*p);  /* 输出b */  
  15.     p = &c;  
  16.     printf("%c\n",*p);  /* 输出c */  
  17.       
  18.     /* 
  19.         *p = 'd';   这句需要注释掉,否则会报错error: assignment of read-only location '*p' 
  20.     */  
  21.     return 0;  
  22. }  
char * const p;表示的是该定义的该指针变量是一个常量,所以p在定义时必须赋值(也可以不赋值,这时候其中是编译器给其分配的随机数值,但我们之后不能再对其赋值,所以如果不赋值的话这个变量没有用),因为常量在第一次赋值后不允许再次赋值,p指向的数据可以被修改,p自己本身的值不能被修改,示意程序如下:

  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     const char a = 'a';  
  6.     char b = 'b';  
  7.     char c = 'c';  
  8.       
  9.     /* 
  10.         这句注释掉,否则会报warning: initialization discards 'const' qualifier from pointer target type [enabled by default] 
  11.         这也说明不要将常量的地址赋值给char* const 类型的指针 
  12.         char* const p = &a; 
  13.     */  
  14.       
  15.     charconst p = &b; /* 定义时即赋值 */  
  16.     printf("%c\n",*p);  
  17.       
  18.     *p = c;             /* 可以使用p修改p所指向的数据 */  
  19.     printf("%c\n",b);  
  20.     printf("%c\n",c);  
  21.       
  22.     /* 
  23.         p = &c;     这句需要注释掉,否则报错error: assignment of read-only location '*p' 
  24.     */  
  25. }  

第五十四道题:

  1. What is the difference between memcpy and memmove?   

如果传入的原地址与目标地址有重叠的话,memmove总能正确处理,memcpy则不一定可行.

第五十五道题:

  1. What is the format specifiers for printf to print double and float values?   
以后查

第五十六道题:

  1. Write a small C program to determine whether a machine's type is little-endian or big-endian.  
这个比较简单,两种方法,一种使用指针,一种使用union,示例程序如下:

  1. 方法一:  
  2. #include <stdio.h>  
  3.   
  4. int main(void)  
  5. {  
  6.     int a = 1;  
  7.     char *p = (char*) &a;  
  8.       
  9.     if(*p == 1)  
  10.     {  
  11.         printf("the machine is little endian\n");  
  12.     }  
  13.     else  
  14.     {  
  15.         printf("the machine is big endian\n");  
  16.     }  
  17.       
  18.     return 0;  
  19. }  
  20.   
  21. 方法二:  
  22. #include <stdio.h>  
  23.   
  24. typedef union endian_  
  25. {  
  26.     int a;  
  27.     char b;  
  28. } Endian;  
  29.   
  30. int main(void)  
  31. {  
  32.     Endian a;  
  33.     a.a = 1;  
  34.     if(a.b == 1)  
  35.     {  
  36.         printf("the machine is little endian\n");  
  37.     }  
  38.     else  
  39.     {  
  40.         printf("the machine is big endian\n");  
  41.     }  
  42.     return 0;  
  43. }  
第五十七道题:

  1. Write a C program which prints Hello World! without using a semicolon!!!   

stackOverflow给输了多种答案,下面是其中的一种

  1. #include <stdio.h>  
  2.   
  3. void main(void)  
  4. {  
  5.     if(printf("hello world\n")){}  
  6. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值