C謎題解釋

看到了這個網址http://www.gowrikumar.com/c/,作者收集了一系列網上和自己所遇到的C語言有趣的東西,我感覺挺像<Java解惑>的風格,我下面就嘗試解決一下作者提出的問題.

第一題

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.

#include<stdio.h>

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};

int main()
{
		int d;

		for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
				printf("%d\n",array[d+1]);

		return 0;
}

Find out what's going wrong.
這道題作者給出了提示,因爲sizeof操作符返回的是size_t類型,一般情況下size_t是無符號類型,所以在for循環中當-1與(TOTAL_ELEMENTS-2)比較時,-1首先被轉換成無符號數來進行比較,此時-1被解釋爲一個很大的整數,大於(TOTAL_ELEMENTS-2)的值,所以代碼什麼也不輸出,與程序作者本意相違背.

第二題:

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 :-) ?

#include<stdio.h>

void OS_Solaris_print()
{
	printf("Solaris - Sun Microsystems\n");
}

void OS_Windows_print()
{
	printf("Windows - Microsoft\n");

}
void OS_HP-UX_print()
{
	printf("HP-UX - Hewlett Packard\n");
}

int main()
{
	int num;
	printf("Enter the number (1-3):\n");
	scanf("%d",&num);
	switch(num)
	{
		case 1:
			OS_Solaris_print();
			break;
		case 2:
			OS_Windows_print();
			break;
		case 3:
			OS_HP-UX_print();
			break;
		default:
			printf("Hmm! only 1-3 :-)\n");
			break;
	}

	return 0;
}
這道題比較簡單,就是函數OS_HP-UX_print()中間不能有符號-,作者也給出了提示.

第三道題:

What's the expected output for the following program and why?

enum {false,true};

int main()
{
        int i=1;
        do
        {
                printf("%d\n",i);
                i++;
                if(i < 15)
                        continue;
        }while(false);
        return 0;
}
作者也給出了提示,在K&R的書中提到,在while與do while語句中,continue語句的執行意味着立即執行測試部分.所以上述程序只輸出1,同時要注意程序沒有導入stdio.h頭文件,在一些編譯器上會出錯.

第四道題:

The following program doesn't "seem" to print "hello-out". (Try executing it)

  #include <stdio.h>
  #include <unistd.h>
  int main()
  {
          while(1)
          {
                  fprintf(stdout,"hello-out");
                  fprintf(stderr,"hello-err");
                  sleep(1);
          }
          return 0;
  }

What could be the reason?
這道題我不明白,應該是與多線程之類的有關係(以後再弄)

第五道題:

  #include <stdio.h>
  #define f(a,b) a##b
  #define g(a)   #a
  #define h(a) g(a)

  int main()
  {
          printf("%s\n",h(f(1,2)));
          printf("%s\n",g(f(1,2)));
          return 0;
  }

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:
bash$ ./a.out
12
f(1,2)
bash$

Why is it so?
這道題我也不明白,以後再做

第六道題:

  #include<stdio.h>
  int main()
  {
          int a=10;
          switch(a)
          {
                  case '1':
                      printf("ONE\n");
                      break;
                  case '2':
                      printf("TWO\n");
                      break;
                  defa1ut:
                      printf("NONE\n");
          }
          return 0;
  }

If you expect the output of the above program to be NONE, I would request you to check it out!!
這道題需要細心觀察,default在程序中被寫成了defalut,而這在某些編譯器是可以編譯運行的(我在gcc,vc測過,是可以運行的),所以程序什麼都不會輸出.

第七道題:

The following C program segfaults of IA-64, but works fine on IA-32.

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }

Why does it happen so?
注意這個程序沒有引入malloc函數原型所在的頭文件,在IA-32平臺下,因爲沒有指定頭文件,編譯器默認返回了一個32位的指針類型,在IA-64的情況下,因爲沒有指定頭文件編譯器還是返回的32位的,這樣在轉換的過程中將64位的截斷成了32位,所以就出現段錯誤了.

第八道題:

Here is a small piece of program(again just 14 lines of program) which counts the number of bits set in a number.
Input 	Output
0 	0(0000000)
5 	2(0000101)
7 	3(0000111)

  int CountBits (unsigned int x )
  {
      static unsigned int mask[] = { 0x55555555,
          0x33333333,
          0x0F0F0F0F,
          0x00FF00FF,
          0x0000FFFF
          } ;

          int i ;
          int shift ; /* Number of positions to shift to right*/
          for ( i =0, shift =1; i < 5; i ++, shift *= 2)
                  x = (x & mask[i ])+ ( ( x >> shift) & mask[i]);
          return x;
  }

Find out the logic used in the above program. 
位運算技巧的運用,以後再弄

第九道題:

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)

#include <stdio.h>

int main()
{
        float f=0.0f;
        int i;

        for(i=0;i<10;i++)
                f = f + 0.1f;

        if(f == 1.0f)
                printf("f is 1.0 \n");
        else
                printf("f is NOT 1.0\n");

        return 0;
}
浮點數加減法有很多讓人意想不到的東西,特別是大數與小數相加時,所以出書f is NOT 1.0就是不足爲奇了.

第十道題:

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?

#include <stdio.h>

int main()
{
        int a = 1,2;
        printf("a : %d\n",a);
        return 0;
}
這裏逗號的本意是將兩個句子和在一塊,少寫分號.但是int a = 1做單個句子缺少分號;所以出現編譯錯誤,要想避免編譯錯誤有兩種方法,第一種:將1,2用括號括起來,即a = (1,2);這時候a被初始化爲2,或者int a; a = 1,2;此時a = 1.

第十一道題:

What would be the output of the following C program? (Is it a valid C program?)

#include <stdio.h>
int main()
{
        int i=43;
        printf("%d\n",printf("%d",printf("%d",i)));
        return 0;
}
printf函數的返回值是被打印的字符數,所以程序輸出4321,另外這道題是ppurl.com註冊時的一個題,很有點意思.

第十二道題:

 void duff(register char *to, register char *from, register int count)
  {
      register int n=(count+7)/8;
      switch(count%8){
      case 0: do{ *to++ = *from++;
      case 7:  *to++ = *from++;
      case 6: *to++ = *from++;
      case 5: *to++ = *from++;
      case 4: *to++ = *from++;
      case 3: *to++ = *from++;
      case 2: *to++ = *from++;
      case 1: *to++ = *from++;
              }while( --n >0);
      }
  }

Is the above valid C code? If so, what is it trying to acheive and why would anyone do something like the above? 
這段代碼是合法的,在很多對性能要求苛刻的程序(如驅動程序中)有可能會用到,維基這篇文章闡述了這個東西,我表示自己也沒理解透

第十三道題:

Here is yet another implementation of CountBits. Verify whether it is correct (how do you that???). If so, find out the logic used.

  int CountBits(unsigned int x)
  {
      int count=0;
      while(x)
      {
          count++;
          x = x&(x-1);
      }
      return count;
  }
位運算,x - 1將x二進制中最低位爲1的進行借位,之後再&去除一個爲1的位,這個方法也可以用來判斷一個數是不是2的冪,有點意思

第十四道題:

Are the following two function prototypes same?

  int foobar(void);
  int foobar();

The following programs should be of some help in finding the answer: (Compile and run both the programs and see what happens)
Program 1:

  #include <stdio.h>
  void foobar1(void)
  {
   printf("In foobar1\n");
  }

  void foobar2()
  {
   printf("In foobar2\n");
  }

  int main()
  {
     char ch = 'a';
     foobar1();
     foobar2(33, ch);
     return 0;
  }

Program 2:

  #include <stdio.h>
  void foobar1(void)
  {
   printf("In foobar1\n");
  }

  void foobar2()
  {
   printf("In foobar2\n");
  }

  int main()
  {
     char ch = 'a';
     foobar1(33, ch);
     foobar2();
     return 0;
  }
首先這兩個函數原型肯定是不一樣的,第一個int foobar(void)表示函數不接受任何的參數,第二個int foobar()表示函數接受任意個數的參數,這說起來都是C語言的遺產了,K&R裏面做了闡述,在C語言做標準化時引入了foobar(void)這樣的void表示函數不接受任何參數,但是爲了使得標準化之前的C代碼還能夠編譯便保留了int foobar()這樣的聲明,且K&R建議在函數不需要參數的時候顯式傳入void,即第一種用法.上述程序中第一個程序能夠編譯通過,第二個則會報錯.

第十五道題:

What's the output of the following program and why?

  #include <stdio.h>
  int main()
  {
   float a = 12.5;
   printf("%d\n", a);
   printf("%d\n", *(int *)&a);
   return 0;
  }
第二句printf將一個浮點數的二進制byte序列強制按一個int值來解讀,所以會根據12.5在內存中的位序列將其解釋爲一個整數,或大或小.

第十六道題:

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?
File1.c

  int arr[80];

File2.c

  extern int *arr;
  int main()
  {
      arr[1] = 100;
      return 0;
  }
很經典的一道題,<C專家編程>上解釋過

第十七道:

Explain the output of the following C program (No, the output is not 20).

  #include<stdio.h>
  int main()
  {
      int a=1;
      switch(a)
      {   int b=20;
          case 1: printf("b is %d\n",b);
                  break;
          default:printf("b is %d\n",b);
                  break;
      }
      return 0;
  }
作者給出了說明,輸出肯定不是20,b輸出的是一些隨機的未初始化垃圾值,這是因爲在switch中程序從default(如果沒有case的話)或者case來開始執行,所以int b = 20;這一句沒有執行,b是一些垃圾值.事實上在一些高級語言中,上述寫法會報錯,比如actionscript 3中上述寫法就會報錯"需要 CaseLabel".

第十八道:

What is the output of the following program? (Again, it is not 40, (if the size of integer is 4)).

  #define SIZE 10
  void size(int arr[SIZE])
  {
          printf("size of array is:%d\n",sizeof(arr));
  }

  int main()
  {
          int arr[SIZE];
          size(arr);
          return 0;
  }
犯了一個大錯誤,函數中不能傳遞數組的,只能通過指針和int arr[]這樣的方式來傳遞,作者本意是給size函數傳遞一個10個元素的int型數組,但是arr[10]只是一個數,其含義在傳遞函數是與int* arr和int arr[]含義是不同的,不能這樣用,另外需要注意的是sizeof(數組)只會返回整個數組所佔字節的大小,而不是數組中元素的個數.

第十九道:

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?

  #include <stdlib.h>
  #include <stdio.h>
  void Error(char* s)
  {
      printf(s);
      return;
  }

  int main()
  {
      int *p;
      p = malloc(sizeof(int));
      if(p == NULL)
      {
          Error("Could not allocate the memory\n");
          Error("Quitting....\n");
          exit(1);
      }
      else
      {
          /*some stuff to use p*/
      }
      return 0;
  }
挑不出啥大毛病,以後看

第二十道題:

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)

  #include <stdio.h>
  int main()
  {
      char c;
      scanf("%c",&c);
      printf("%c\n",c);

      scanf(" %c",&c);
      printf("%c\n",c);

      return 0;
  }
不曉得,以後看

第二十一道:

What is the potential problem with the following C program?

  #include <stdio.h>
  int main()
  {
      char str[80];
      printf("Enter the string:");
      scanf("%s",str);
      printf("You entered:%s\n",str);

      return 0;
  }

字符串結尾問題,如果輸入的過長,超過了80個字符,則str字符數組最後一個元素就不是\0,printf函數在打印時則會造成程序的越界訪問甚至會崩潰.

第二十二道:

What is the output of the following program?

  #include <stdio.h>
  int main()
  {
      int i;
      i = 10;
      printf("i : %d\n",i);
      printf("sizeof(i++) is: %d\n",sizeof(i++));
      printf("i : %d\n",i);
      return 0;
  }
這個簡單,sizeof操作符不會對其中傳入的表達式或者函數等等求值,所以程序在32位機器輸出10,4,10

第二十三道:

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)

  #include <stdio.h>
  void foo(const char **p) { }
  int main(int argc, char **argv)
  {
          foo(argv);
          return 0;
  }
以後解決

第二十四道:

What is the output of the following program?

  #include <stdio.h>
  int main()
  {
          int i;
          i = 1,2,3;
          printf("i:%d\n",i);
          return 0;
  }
這個和之前有關逗號的題一樣,實際上是i = 1;2;3;這三句,所以會輸出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..

  #include <stdio.h>
  #include <stdlib.h>

  #define MAX 80
  #define NUMBER '0'

  int getop(char[]);
  void push(double);
  double pop(void);
  int main()
  {
      int type;
      char s[MAX];

      while((type = getop(s)) != EOF)
      {
          switch(type)
          {
              case NUMBER:
                  push(atof(s));
                  break;
              case '+':
                  push(pop() + pop());
                  break;
              case '*':
                  push(pop() * pop());
                  break;
              case '-':
                  push(pop() - pop());
                  break;
              case '/':
                  push(pop() / pop());
                  break;
              /*   ... 
               *   ...    
               *   ... 
               */
          }
      }
  }
不會,以後弄

第二十六道:

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.

  #include<stdio.h>
  #include<ctype.h>

  char t[]={
      0,0,0,0,0,0,12,18,33,63,
      33,33,62,32,62,33,33,62,30,33,
      32,32,33,30,62,33,33,33,33,62,
      63,32,62,32,32,63,63,32,62,32,
      32,32,30,33,32,39,33,30,33,33,
      63,33,33,33,4,4,4,4,4,4,
      1,1,1,1,33,30,33,34,60,36,
      34,33,32,32,32,32,32,63,33,51,
      45,33,33,33,33,49,41,37,35,33,
      30,33,33,33,33,30,62,33,33,62,
      32,32,30,33,33,37,34,29,62,33,
      33,62,34,33,30,32,30,1,33,30,
      31,4,4,4,4,4,33,33,33,33,
      33,30,33,33,33,33,18,12,33,33,
      33,45,51,33,33,18,12,12,18,33,
      17,10,4,4,4,4,63,2,4,8,
      16,63
      };

  int main(int argc,char** argv)
  {

      int r,pr;
      for(r=0;r<6;++r)
          {
          char *p=argv[1];

          while(pr&&*p)
              {
              int o=(toupper(*p++)-'A')*6+6+r;
              o=(o<0||o>=sizeof(t))?0:o;
              for(pr=5;pr>=-1;--pr)
                  {
                  printf("%c",( ( (pr>=0) && (t[o]&(1<<pr)))?'#':' '));

                  }
              }
          printf("\n");
          }
      return 0;
  }

不會,以後弄

第二十七道:

What is the output of the following program?

  #include <stdio.h>
  #include <stdlib.h>

  #define SIZEOF(arr) (sizeof(arr)/sizeof(arr[0]))

  #define PrintInt(expr) printf("%s:%d\n",#expr,(expr))
  int main()
  {
      /* The powers of 10 */
      int pot[] = {
          0001,
          0010,
          0100,
          1000
      };
      int i;

      for(i=0;i<SIZEOF(pot);i++)
          PrintInt(pot[i]);
      return 0;
  }
C語言中數字以0開頭的話表示的是八進制的計數,所以上面數組中的前三項化爲十進制爲1,8,64,背離了程序作者的真實意思,在八進制時數字鐘不能出現8,9這兩個數

第二十八道:

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.
BTW, what does scanf function return?

  #include <stdio.h>
  int gcd(int u,int v)
  {
      int t;
      while(v > 0)
      {
          if(u > v)
          {
              t = u;
              u = v;
              v = t;
          }
          v = v-u;
      }
      return u;
  }

  int main()
  {
      int x,y;
      printf("Enter x y to find their gcd:");
      while(scanf("%d%d",&x, &y) != EOF)
      {
          if(x >0 && y>0)
              printf("%d %d %d\n",x,y,gcd(x,y));
                  printf("Enter x y to find their gcd:");
      }
      printf("\n");
      return 0;
  }

Also implement a C function similar to the above to find the GCD of 4 integers.
表示不會,以後弄

第二十九道:

What's the output of the following program. (No, it's not 10!!!)

  #include <stdio.h>
  #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
  int main()
  {
      int y = 100;
      int *p;
      p = malloc(sizeof(int));
      *p = 10;
      y = y/*p; /*dividing y by *p */;
      PrintInt(y);
      return 0;
  }
/*與語句最後面的*/構成了註釋符號,所以y = y/*p這句實際上成了y = y;所以程序會輸出y:100.要想避免這樣的情況很簡單,用括號就行了即y = y/(*p);或者唉/*之間打個空格就夠了此時程序就變成了y = y/ *p;這樣就不會與後面的構成註釋了.

第三十道:

The following is a simple C program to read a date and print the date. Run it and explain the behaviour

  #include <stdio.h>
  int main()
  {
      int day,month,year;
      printf("Enter the date (dd-mm-yyyy) format including -'s:");
      scanf("%d-%d-%d",&day,&month,&year);
      printf("The date you have entered is %d-%d-%d\n",day,month,year);
      return 0;
  }
以後看

第三十一道:

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)?

  #include <stdio.h>
  int main()
  {
      int n;
      printf("Enter a number:\n");
      scanf("%d\n",n);

      printf("You entered %d \n",n);
      return 0;
  }

首先scanf中n是不對的,應該傳入&n,此外scanf("%d\n",n)中的\n也是問題,scanf中儘量不要使用非輸入控制符,像上面的程序就需要輸入兩個數字程序才能運行完畢.此外,這個程序估計還有別的我不知道的問題.

第三十二道:

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.

  #include <stdio.h>
  #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
  int FiveTimes(int a)
  {
      int t;
      t = a<<2 + a;
      return t;
  }

  int main()
  {
      int a = 1, b = 2,c = 3;
      PrintInt(FiveTimes(a));
      PrintInt(FiveTimes(b));
      PrintInt(FiveTimes(c));
      return 0;
  }
運算符優先級的問題,t = a << 2 + a,實際上等於t = a << (2 + a),所以出現了與程序作者原意不相符的情況.

第三十三道:

Is the following a valid C program?

  #include <stdio.h>
  #define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
  int max(int x, int y)
  {
      (x > y) ? return x : return y;
  }

  int main()
  {
      int a = 10, b = 20;
      PrintInt(a);
      PrintInt(b);
      PrintInt(max(a,b));
  }
不是合法的C程序,在gcc下報錯error: expected expression before 'return'

第三十四道:

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.

  #include <stdio.h>
  int main()
  {
      int i;
      int n = 20;
      for( i = 0; i < n; i-- )
          printf("-");
      return 0;
  }

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.
作者要求只改動一個字符使上述程序正常運行,暫時沒有方法,以後弄.

第三十五道:

What's the mistake in the following code?

  #include <stdio.h>
  int main()
  {
      int* ptr1,ptr2;
      ptr1 = malloc(sizeof(int));
      ptr2 = ptr1;
      *ptr2 = 10;
      return 0;
  }
初始化的問題,只有ptr1被生命爲一個int指針,ptr2其實被聲明爲一個int類型,這是問題所在,修改爲int *ptr1,*ptr2;即可

第三十六道:

What is the output of the following program?

  #include <stdio.h>
  int main()
  {
      int cnt = 5, a;

      do {
          a /= cnt;
      } while (cnt --);

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

當cnt爲1時while(cnt--)爲真,所以繼續進行循環,而此時cnt經過自減操作cnt爲0,所以a /= cnt成了a /= 0,會發生除零錯誤

第三十七道題:

What is the output of the following program?

  #include <stdio.h>
  int main()
  {
      int i = 6;
      if( ((++i < 7) && ( i++/6)) || (++i <= 9))
          ;
      printf("%d\n",i);
      return 0;
  }
輸出8,這個是邏輯運算符中的短路原則使用.

第三十八道題:

What is the bug in the following program?

  #include <stdlib.h>
  #include <stdio.h>
  #define SIZE 15 
  int main()
  {
      int *a, i;

      a = malloc(SIZE*sizeof(int));

      for (i=0; i<SIZE; i++)
          *(a + i) = i * i;
      for (i=0; i<SIZE; i++)
          printf("%d\n", *a++);
      free(a);
      return 0;
  }
這裏第二個for循環中printf("%d\n",*a++),修改了分配內存後a的值,造成了後面free(a)內存釋放不成功,造成內存泄露.

第三十九道題:

Is the following a valid C program? If so, what is the output of it?

  #include <stdio.h>
  int main()
  {
    int a=3, b = 5;

    printf(&a["Ya!Hello! how is this? %s\n"], &b["junk/super"]);
    printf(&a["WHAT%c%c%c  %c%c  %c !\n"], 1["this"],
       2["beauty"],0["tool"],0["is"],3["sensitive"],4["CCCCCC"]);
    return 0;
  }
不懂,以後弄

第四十道題:

What is the output of the following, if the input provided is:
Life is beautiful

  #include <stdio.h>
  int main()
  {
      char dummy[80];
      printf("Enter a string:\n");
      scanf("%[^a]",dummy);
      printf("%s\n",dummy);
      return 0;
  }
不懂,以後弄

第四十一道題:

 Note : This question has more to do with Linker than C language
We have three files a.c, b.c and main.c respectively as follows:
a.c
---

int a;

b.c
---

int a = 10;

main.c
------

extern int a;
int main()
{
        printf("a = %d\n",a);
        return 0;
}

Let's see what happens, when the files are compiled together:

bash$ gcc a.c b.c main.c
bash$ ./a.out
a = 10

Hmm!! no compilation/linker error!!! Why is it so?? 
不懂,以後弄

第四十二道題:

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.

  #define offsetof(a,b) ((int)(&(((a*)(0))->b)))

這是stddef.h裏定義的一個宏,其返回值爲size_t,它適用於結構和union,用於檢索結構成員相對於父結構的偏移量,第一個參數爲結構名稱,第二個參數爲結構中的字段名,其主要實現如下:將地址0強制轉換爲對應結構指針,此時結構的地址爲0,然後使用->獲得b的內容,再使用&操作符獲得b的地址,再將b的地址轉換爲int類型,使用b的地址減去結構地址0(因爲是0強轉的),即爲結構字段b相對於結構的偏移量,這種在嵌入式裏面用的比較多,這裏有一篇詳解它的文章.它的使用例子如下:

#include <stdio.h>
#include <stddef.h>

void main(void)
{	
	struct test
	{
		int a;
		short b;
		char c;
		int d;
	};
	struct test a;
	size_t offset = offsetof(struct test,c);
	printf("the offset of c is %d\n",offset);	/* 輸出6,因爲32位機器上int佔4字節,short爲2字節	*/
}

第四十三道題:

The following is the macro implementation of the famous, Triple xor swap.

  #define SWAP(a,b) ((a) ^= (b) ^= (a) ^= (b))

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))更加報錯,此外有可能還有我沒發現的錯誤,所以還是那句話不是大牛,用宏一定要當心,宏也是會耍大牌的.

第四十四道題:

What is the use of the following macro?

  #define DPRINTF(x) printf("%s:%d\n",#x,x)
宏中#的用法,很常見

第四十五道題:

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:

  int IAddOverFlow(int* result,int a,int b)
  {
      /* ... */
  }

So, how do you code the above function? (To put in a nutshell, what is the logic you use for overflow detection?) 
不懂,以後弄

第四十六道題:

What does the following macro do?

  #define ROUNDUP(x,n) ((x+n-1)&(~(n-1)))
不懂,以後弄

第四十七道題:

Most of the C programming books, give the following example for the definition of macros.

  #define isupper(c) (((c) >= 'A') && ((c) <= 'Z'))

But there would be a serious problem with the above definition of macro, if it is used as follows (what is the problem??)

  char c;
  /* ... */
  if(isupper(c++))
  {
      /* ... */
  }

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,即大小寫字母只是在第六位(從右到左數)比特位上不相同,其他比特字節相同,所以用位運算又快又準確.

第四十八道題:

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?

  int VarArguments(...)
  {
      /*....*/
      return 0;
  }
不懂,以後弄

第四十九道題:

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

我的思路,使用位運算

#include <stdio.h>

/**
 * 找到兩個數中的較小的數,如果相等返回同一個數
 * 這種方法只適用於使用補碼錶示有符號數的計算機,且是8比特補碼系統
 */
int findLess(int a,int b)
{
	int c = a - b;
	int flag = c >> (sizeof(int) * 8 - 1);	/* 獲取標誌位 */
	if(flag)	/* 標誌位爲1表示結果爲負數 */
	{
		return a;
	}
	else if(c)	/* 此時標誌位爲0,表示c爲非負數,如果c爲真,表示c大於0,返回b */
	{
		return b;
	}
	else		/* c爲0,表示兩個數相等 */
	{
		return a;
	}
	printf("compare error\n");
	return -1;
}

void main(void)
{
	int a = 1,b = 2,c = 2;
	
	printf("the small integer is %d\n",findLess(a,findLess(b,c)));
}

第五十道題:

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

msdn描述如下,%n表示當前已經成功寫入流或者緩衝的字符數目;該值保存在一個整數中,其地址作爲參數傳給printf函數,且說明%n內在並不安全,所以默認情況下是禁用的,要使用%n,請查看_set_printf_count_output等.例子如下:

#include <stdio.h>

/**
 * gcc編譯
 */
void main(void)
{
	char* str = "hello world";
	int n;
	printf("%s\n%n",str,&n);	/* 傳入n的地址 */
	printf("%d\n",n);			/* 打印n的值 */
}

第五十一道題:

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....) 
不懂,以後弄

第五十二道題:

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

#include <stdio.h>

void main(void)
{
	printf("I can print %% use the printf function\n");
}

第五十三道題:

What's the difference between the following two C statements?

  const char *p;
  char* const p;
含義不同,第一個表示的是p指向一個常量char或者非常量char,p在初始化爲指向一個常量char之後還可以改變爲指向別的char(常量或者非常量都可),也可使用*p作爲只讀的數據,但是不能使用*p來修改其所指向的char的值,即不允許你*p = 'a';之類的句子出現,示例程序如下:

#include <stdio.h>

int main()
{
	const char a = 'a';
	const char b = 'b';
	char c = 'c';
	
	const char *p;
	
	p = &a;
	printf("%c\n",*p);	/* 輸出a */
	p = &b;
	printf("%c\n",*p);	/* 輸出b */
	p = &c;
	printf("%c\n",*p);	/* 輸出c */
	
	/*
		*p = 'd';	這句需要註釋掉,否則會報錯error: assignment of read-only location '*p'
	*/
	return 0;
}
char * const p;表示的是該定義的該指針變量是一個常量,所以p在定義時必須賦值(也可以不賦值,這時候其中是編譯器給其分配的隨機數值,但我們之後不能再對其賦值,所以如果不賦值的話這個變量沒有用),因爲常量在第一次賦值後不允許再次賦值,p指向的數據可以被修改,p自己本身的值不能被修改,示意程序如下:

#include <stdio.h>

int main()
{
	const char a = 'a';
	char b = 'b';
	char c = 'c';
	
	/*
		這句註釋掉,否則會報warning: initialization discards 'const' qualifier from pointer target type [enabled by default]
		這也說明不要將常量的地址賦值給char* const 類型的指針
		char* const p = &a;
	*/
	
	char* const p = &b;	/* 定義時即賦值 */
	printf("%c\n",*p);
	
	*p = c;				/* 可以使用p修改p所指向的數據 */
	printf("%c\n",b);
	printf("%c\n",c);
	
	/*
		p = &c;		這句需要註釋掉,否則報錯error: assignment of read-only location '*p'
	*/
}

第五十四道題:

What is the difference between memcpy and memmove? 

如果傳入的原地址與目標地址有重疊的話,memmove總能正確處理,memcpy則不一定可行.

第五十五道題:

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

第五十六道題:

Write a small C program to determine whether a machine's type is little-endian or big-endian.
這個比較簡單,兩種方法,一種使用指針,一種使用union,示例程序如下:

方法一:
#include <stdio.h>

int main(void)
{
	int a = 1;
	char *p = (char*) &a;
	
	if(*p == 1)
	{
		printf("the machine is little endian\n");
	}
	else
	{
		printf("the machine is big endian\n");
	}
	
	return 0;
}

方法二:
#include <stdio.h>

typedef union endian_
{
	int a;
	char b;
} Endian;

int main(void)
{
	Endian a;
	a.a = 1;
	if(a.b == 1)
	{
		printf("the machine is little endian\n");
	}
	else
	{
		printf("the machine is big endian\n");
	}
	return 0;
}
第五十七道題:

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

stackOverflow給輸了多種答案,下面是其中的一種

#include <stdio.h>

void main(void)
{
	if(printf("hello world\n")){}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章