Q:printf和scanf的返回值是什麼?
int main() { int i = 43; int n = printf("%d\n",i); printf("%d\n",n); return 0; }
A:printf函數返回3,因為其輸出了'4', '3', '\n' 三個字符。
printf返回的是成功輸出到STDOUT的字符數。如果發生錯誤,返回一個負數。
scanf返回的是成功賦值的變量個數,如果發生錯誤,返回EOF
Q:既然fgetc是接收輸入的字符,返回值用char或者unsigned char不就行了,為什麼用int呢?
A:這個主要是因為文件結束或者讀寫文件出錯的標志被規定成EOF,也就是-1導致的。unsigned char根本取不到-1這個值,而如果用char做返回值的話,它無法分辨0xFF字符和EOF,因為這兩個數值都被char認為是-1,所以它也不能作為返回值。
Q:此段程序希望輸出數組中的所有元素,但卻沒有得到想要的結果,是什麼產生歧義?
#include#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; }
A:運行上面的程序,結果是什麼都沒有輸出,導致這個結果的原因是sizeof的返回值是一個unsinged int,為此在比較int d 和TOTAL_ELEMENTS兩個值都被轉換成了unsigned int來進行比較,這樣就導致-1被轉換成一個非常大的值,以至於for循環不滿足條件。因此,如果不能理解sizeof操作符返回的是一個unsigned int的話,就會產生類似如上的歧義。
Q:下面這段程序的輸出結果是:
#include#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; }
A:在C語言的宏中,#的功能是將其後面的宏參數進行字符串化操作(Stringfication)。而##被稱為連接符(concatenator),用來將兩個Token連接為一個Token。
看到這段程序你可能會認為,這兩個printf輸出的同一個結果,可是答案卻非如此,本題的輸出是12和f(1,2),為什麼會這樣呢?因為這是宏,宏的解開不象函數執行那樣由裡到外。#將右邊的參數做整體的字符串替換,即便是另一個宏,也不展開,所以,g(f(1,2))->"f(1,2)"。對於h(f(1,2)),由於h(a)是非#或##的普通宏,需要先宏展開其參數a,即展開f(1,2)為12,則h(a) 宏替換為h(12),進而宏替換為g(12), 進而宏替換為"12"。
Q:假如我們的a的地址是:0Xbfe2e100, 而且是32位機,那麼這個程序會輸出什麼?
#includeint main() { int a[5]; printf("%x\n", a); printf("%x\n", a+1); printf("%x\n", &a); printf("%x\n", &a+1); return 0; }
A:
第一條printf語句應該沒有問題,就是 bfe2e100。
第二條printf語句你可能會以為是bfe2e101。那就錯了,a+1,編譯器會編譯成 a+ 1*sizeof(int),int在32位下是4字節,所以是加4,也就是bfe2e104。
第三條printf語句可能是你最頭疼的,我們怎麼知道a的地址?我不知道嗎?可不就是bfe2e100。那豈不成了a==&a啦?這怎麼可能?自己存自己的?也許很多人會覺得指針和數組是一回事,那麼你就錯了。如果是 int *a,那麼沒有問題,因為a是指針,所以 &a 是指針的地址,a 和 &a不一樣。但是這是數組啊a[],所以&a其實是被編譯成了 &a[0]。
第四條printf語句就很自然了,就是bfe2e104。還是不對,因為是&a是數組,被看成int(*)[5],所以sizeof(a)是5,也就是5*sizeof(int),也就是bfe2e114。
Q:如下代碼為什麼結果始終不對?
#includeint main() { int a = 2; if(a & 1 == 0) printf("a & 1 == 0"); else printf("a & 1 != 0"); return 0; }
為什麼輸出“a & 1 != 0”?
A:這是因為==的優先級高於表示位與運算符&.所以a & 1 == 0的實際代碼是a & (1 == 0),也就是a & 0, 當然結果不是預期了。(優先級:==和!= 高於 & 高於 ^ 高於 | 高於 && 高於 || )。優先級從高到低:算術運算符,位移運算符,關系運算符,位操作& ^ |
Q:如下代碼輸出什麼?
int main() { int i = 6; if( ((++i < 7) && ( i++/6)) || (++i <= 9)); printf("%d\n",i); return 0; }
A:8。本題主要考的是&&和||的短路求值的問題。所為短路求值:對於(條件1 && 條件2),如果“條件1”是false,那“條件2”的表達式會被忽略了。對於(條件1 || 條件2),如果“條件1”為true,而“條件2”的表達式則被忽略了。
Q:sizeof後面可以跟表達式,下面的代碼,為什麼i++無效呢?
#includeint main() { int i = 1; sizeof(i++); printf("%d\n", i); return 0; }
運行結果:1
A:正因為sizeof是編譯期求值的,所以如果它跟著表達式,那麼表達式是不被計算的,只是根本表達式的類型得到它占用的空間。
Q:下面的程序試圖使用“位操作”來完成“乘5”的操作,不過這個程序中有個BUG,你知道是什麼嗎?
#include#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; PrintInt(FiveTimes(a)); return 0; }
A:本題的問題在於函數FiveTimes中的表達式“t = a<<2 + a;”,對於a<<2這個位操作,優先級要比加法要低,所以這個表達式就成了“t = a << (2+a)”,於是我們就得不到我們想要的值。該程序修正如下:“t = (a<<2) + a;”
Q:如下代碼關於位運算符的操作為何最終結果和預期不符?
#includeint main() { unsigned char c = 0xfc; unsigned int i = ~c; printf("%x\n",i); return 0; }
運行結果:0xffffff03
按照上面的代碼,~c應該得到的是0x03, 那麼結果應該是0x03, 怎麼會是上面的結果呢?
A:這是因為位運算是被提升到整形運算的。上面的變量c是無符號字符型,在進行~位運算時,是首先提升為整形,即為0x000000fc, 然後取反得到0xffffff03, 所以i得到的數值是這個。同理,如果c是char類型,提升為整形時為0xfffffffc,再取反得到的就是0x03。其實變量被提升有很多地方,比如short計算時也會提升為int再繼續計算。
Q:下面這個程序執行後會有什麼錯誤或者效果:
#define MAX 255 int main() { unsigned char A[MAX]; unsigned chat i; for (i = 0; i <= MAX; i++) A[i] = i; }
A:MAX=255,數組A的下標范圍為:0..MAX-1,下標越界。當i循環到255時,循環內執行: A[255]=255;這句本身沒有問題,但是返回for(i=0;i<=MAX;i++)語句時,由於unsigned char的取值范圍在[0,255],i++以後i又為0了,無限循環下去。
注意:char類型為一個字節,取值范圍是[-128,127],unsigned char取值范圍[0,255]
Q:有a和b兩個整型變量,不用“if”,“? :”,“switch”或者是其他判斷語句,如何得到大者和小者?
A:大者:((a+b)+abs(a-b))/2
小者:((a+b)-abs(a-b))/2
Q:請定義一個宏,比較兩個數a、b的大小,不能使用大於、小於、if語句
A:可以判斷兩個數相減後的符號,32位整數相減後的符號位:
#define MAX(a,b) ((((a)-(b))&(1<<31))?(b):(a))
Q:定義一個宏,求一個結構體struct中某個變量相對於struct的偏移量
A:#define OFFSET(struct, member) ((unsigned int)&((struct *)0)->member)
Q:求不小於x的最小的2的K次方的數:
int pow2_ceil(unsigned int x) { x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x++; return x; }
靈活的位操作可以有效地提高程序運行的效率:
1.設置x的bit5為1,其他位不變:x |= (1<<5);
2.設置x的bit5為0,其他位不變:x &= ~(1<<5);
3.判斷x的bit5是否為1,(x & (1<<5)) != 0 ? 1:0;
4.判斷一個數是不是偶數:(num & 1) == 0 ? 1:0;
關於C中volatile關鍵字的作用:一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裡的備份。
下面是volatile變量的幾個例子:
1). 並行設備的硬件寄存器(如:狀態寄存器)
2). 一個中斷服務子程序中會訪問到的非自動變量(Non-automatic variables,自動變量是auto或register變量)
3). 多線程應用中被幾個任務共享的變量:volatile 關鍵字告訴編譯器不要持有變量的臨時性拷貝。請看以下情形:A線程將變量復制入寄存器,然後進入循環,反復檢測寄存器的值是否滿足一定條件,它期待B線程改變變量的值。在此種情況下,當B線程改變了變量的值時,已改變的值對其在寄存器的值沒有影響。所以A線程進入死循環。