本文摘錄網(wǎng)上能夠找到的c語(yǔ)言筆試題目,回答中包含個(gè)人的理解,如有錯(cuò)誤,希望能夠得到指正,多謝。
1. main函數(shù)執(zhí)行完畢后,是否可能會(huì)再執(zhí)行一段代碼?
答:是。main函數(shù)執(zhí)行完畢后還可以執(zhí)行代碼,它可以通過(guò)atexit()函數(shù)來(lái)注冊(cè)回調(diào)函數(shù),回調(diào)函數(shù)的形式是void (*function)(void)。atexit()聲明在stdlib.h中。具體可以參考:c語(yǔ)言基礎(chǔ)函數(shù)——exit()和atexit()
2. 給一個(gè)字符串、例如 “ababc”要求返回“ab”,因?yàn)椤癮b”連續(xù)重復(fù)出現(xiàn)且最長(zhǎng)。用C/C++語(yǔ)言寫(xiě)一函數(shù)完成該算法,給出復(fù)雜度。
答:下面是具體的參考代碼:
- #include <stdio.h>
- #include <string.h>
-
- /*
- 函數(shù)表示:返回給定字符串中的最大子字符串長(zhǎng)度
- 參數(shù): src:原始字符串
- sub:最大子字符串
- 返回值:最大子字符串長(zhǎng)度(不包含結(jié)尾的\0),因?yàn)閟trlen本來(lái)也不包含\0。
- 說(shuō)明:
- 1. 如果存在多個(gè)子字符串的長(zhǎng)度相同,返回第一個(gè)子字符串
- */
- int GetSubStr(char * src, char * sub) {
- int length; //原始字符串的長(zhǎng)度
- int max; //最大子字符串的長(zhǎng)度
- int tmp_max; //最大子字符串的長(zhǎng)度,臨時(shí),比較時(shí)使用
- int index;
- char *p, *q; //用來(lái)遍歷字符串的兩個(gè)指針
- char *k; //指向最終的子字符串的起始位置
-
- length = strlen(src);
- printf("length of src is %d\n", strlen(src));
- max = 0;
- p = src;
- k = src;
- //從第一個(gè)字符開(kāi)始遍歷
- while (*p != '\0') {
- //與前一個(gè)字符比較
- for (q = p + 1; *q != '\0'; q++) {
- tmp_max = 0;
- //如果相等了,表示有可能出現(xiàn)最大連續(xù)字符串了,之后就要以p和q為起始,比較兩者之后的字符串是否相等
- if (*p == *q) {
- //起始字符相等后,就開(kāi)始比較兩個(gè)字符串
- for (index = 0; index < q - p; index++) {
- if (*(p + index) == *(q + index)) {
- tmp_max++;
- } else {
- if (tmp_max > max) {
- max = tmp_max;
- k = p;
- }
- break;
- }
- }
- }
- }
- p++;
- }
- strncpy(sub, k, max);
- //最后需要手動(dòng)加上一個(gè)\0
- sub[max] = '\0';
-
- return max;
- }
-
- void main() {
- char * src = "I am a abc and he is not abc";
- char result[100];
- int max = GetSubStr(src, result);
-
- printf("result[%d]: %s\n", max, result);
-
- return 0;
- }
上述代碼返回的結(jié)果是" abc“,最前面有一個(gè)空格。
說(shuō)明:上述代碼的基本思路是使用兩個(gè)指針,第一個(gè)從頭開(kāi)始遍歷,即while (*p != '\0');第二個(gè)是從第一個(gè)指針之后的指針,從該位置開(kāi)始找與第一個(gè)指針指向的內(nèi)容具有相等字符串的指針位置,即for (q = p + 1; *q != '\0'; q++)循環(huán)。該算法的復(fù)雜度是O(n^2)。
3. 完成字符串拷貝可以使用 sprintf、strcpy 及 memcpy 函數(shù),請(qǐng)問(wèn)這些函數(shù)有什么區(qū)別,你喜歡使用哪個(gè),為什么?
答:這些函數(shù)的區(qū)別在于實(shí)現(xiàn)功能以及操作對(duì)象不同。
1. strcpy函數(shù)操作的對(duì)象是字符串,完成從源字符串到目的字符串的拷貝功能。
2. sprintf函數(shù)操作的對(duì)象不限于字符串:雖然目的對(duì)象是字符串,但是源對(duì)象可以是字符串、也可以是任意基本類(lèi)型的數(shù)據(jù)。這個(gè)函數(shù)主要用來(lái)實(shí)現(xiàn)(字符串或基本數(shù)據(jù)類(lèi)型)向字符串的轉(zhuǎn)換功能。如果源對(duì)象是字符串,并且指定 %s 格式符,也可實(shí)現(xiàn)字符串拷貝功能。
3. memcpy函數(shù)顧名思義就是內(nèi)存拷貝,實(shí)現(xiàn)將一個(gè)內(nèi)存塊的內(nèi)容復(fù)制到另一個(gè)內(nèi)存塊這一功能。內(nèi)存塊由其首地址以及長(zhǎng)度確定。程序中出現(xiàn)的實(shí)體對(duì)象,不論是什么類(lèi)型,其最終表現(xiàn)就是在內(nèi)存中占據(jù)一席之地(一個(gè)內(nèi)存區(qū)間或塊)。因此,memcpy 的操作對(duì)象不局限于某一類(lèi)數(shù)據(jù)類(lèi)型,或者說(shuō)可適用于任意數(shù)據(jù)類(lèi)型,只要能給出對(duì)象的起始地址和內(nèi)存長(zhǎng)度信息、并且對(duì)象具有可操作性即可。鑒于memcpy函數(shù)等長(zhǎng)拷貝的特點(diǎn)以及數(shù)據(jù)類(lèi)型代表的物理意義,memcpy 函數(shù)通常限于同種類(lèi)型數(shù)據(jù)或?qū)ο笾g的拷貝,其中當(dāng)然也包括字符串拷貝以及基本數(shù)據(jù)類(lèi)型的拷貝。
對(duì)于字符串拷貝來(lái)說(shuō),用上述三個(gè)函數(shù)都可以實(shí)現(xiàn),但是其實(shí)現(xiàn)的效率和使用的方便程度不同:
· strcpy無(wú)疑是最合適的選擇:效率高且調(diào)用方便。
· sprintf要額外指定格式符并且進(jìn)行格式轉(zhuǎn)化,麻煩且效率不高。
· memcpy 雖然高效,但是需要額外提供拷貝的內(nèi)存長(zhǎng)度這一參數(shù),易錯(cuò)且使用不便;并且如果長(zhǎng)度指定過(guò)大的話(huà)(最優(yōu)長(zhǎng)度是源字符串長(zhǎng)度 + 1),還會(huì)帶來(lái)性能的下降。其實(shí)strcpy函數(shù)一般是在內(nèi)部調(diào)用memcpy函數(shù)或者用匯編直接實(shí)現(xiàn)的,以達(dá)到高效的目的。因此,使用 memcpy 和 strcpy 拷貝字符串在性能上應(yīng)該沒(méi)有什么大的差別。
對(duì)于非字符串類(lèi)型的數(shù)據(jù)的復(fù)制來(lái)說(shuō),strcpy和snprintf一般就無(wú)能為力了,可是對(duì)memcpy卻沒(méi)有什么影響。但是,對(duì)于基本數(shù)據(jù)類(lèi)型來(lái)說(shuō),盡管可以用memcpy進(jìn)行拷貝,由于有賦值運(yùn)算符可以方便且高效地進(jìn)行同種或兼容類(lèi)型的數(shù)據(jù)之間的拷貝,所以這種情況下memcpy幾乎不被使用。memcpy 的長(zhǎng)處是用來(lái)實(shí)現(xiàn)(通常是內(nèi)部實(shí)現(xiàn)居多)對(duì)結(jié)構(gòu)或者數(shù)組的拷貝,其目的是或者高效,或者使用方便,甚或兩者兼有。
4. 變量的定義和聲明有什么區(qū)別?
答:定義包含為變量分配存儲(chǔ)空間和指定初始值;而聲明僅用于向編譯器告知變量的名稱(chēng)和類(lèi)型。
5. 請(qǐng)寫(xiě)出下面代碼在32位平臺(tái)上的運(yùn)行結(jié)果,并說(shuō)明 sizeof 的性質(zhì)。
答:直接看代碼,注釋部分為結(jié)果:
- #include <stdio.h>
- #include <stdlib.h>
- int main(void)
- {
- char a[30];
- char *b = (char *)malloc(20 * sizeof(char));
- printf("%d\n", sizeof(a)); // 30,a是一個(gè)數(shù)組,這里應(yīng)該計(jì)算所有的值
- printf("%d\n", sizeof(b)); // 4,b就是一個(gè)char指針
- printf("%d\n", sizeof(a[3])); // 1,一個(gè)char
- printf("%d\n", sizeof(b + 3)); // 4,一個(gè)char指針
- printf("%d\n", sizeof(*(b + 4))); // 1,一個(gè)char
- return 0;
- }
結(jié)果已經(jīng)有了,sizeof的性質(zhì)也就很明了了,不寫(xiě)了。
6. 請(qǐng)編寫(xiě)一個(gè)C函數(shù),該函數(shù)給出一個(gè)字節(jié)中被置1的位的個(gè)數(shù),并請(qǐng)給出該題的至少一個(gè)不同解法。
答:下面是具體的代碼。兩種不同的解法中,第一種依賴(lài)的是移位,第二種依賴(lài)的是2的除法和取余:
- #include <stdio.h>
- #include <stdlib.h>
-
- /*
- 函數(shù)說(shuō)明:返回參數(shù)中比特位值是1的總個(gè)數(shù)
- 函數(shù)參數(shù):value:待測(cè)試的值
- 返回值 :待測(cè)試值中的比特位值是1的總個(gè)數(shù)
- */
- int BitOneTest1(char value) {
- int index;
- int result; //返回結(jié)果
- char tmp; //存放value及其移位值的臨時(shí)變量
-
- result = 0;
- for (index = 0; index < 8; index++) {
- tmp = value >> index;
- result += tmp & 1;
- }
-
- return result;
- }
-
- int BitOneTest2(char value) {
- int result; //返回結(jié)果
- unsigned char tmp; //這里需要將value轉(zhuǎn)換成unsigned char,否則當(dāng)value最高位是1時(shí)后面除法和取余操作會(huì)使結(jié)果發(fā)生錯(cuò)誤
-
- result = 0;
- tmp = (unsigned char)value;
-
- while (tmp) {
- if ((tmp % 2) == 1) {
- result++;
- }
- tmp = tmp / 2;
- }
-
- return result;
- }
-
- int main(void)
- {
- char num = 0b11111111;
- printf("[方法1]bit置為1的個(gè)數(shù): %d\n", BitOneTest1(num));
- printf("[方法2]bit置為1的個(gè)數(shù): %d\n", BitOneTest2(num));
-
- return 0;
- }
又看到一種方法:
- #include<stdio.h>
- #define TRUE 1
- #define FALSE 0
-
- int BitOneTest3(char value) {
- int count = 0;
- while (value)
- {
- count++;
- value = value & (value - 1);
- }
- return count;
- }
-
- int main(void)
- {
- char num = 0b11110111;
- printf("[方法3]bit置為1的個(gè)數(shù): %d\n", BitOneTest3(num));
- return 0;
- }
7. 實(shí)現(xiàn)自己的itoa和atoi函數(shù)。
答:參見(jiàn)http://blog.csdn.net/jiangwei0512/article/details/50668937。
8. 定義 int **a[3][4], 則變量占有的內(nèi)存空間為多少。
答:這題不確定要考什么東西......要是是確定變量a的大小,那么就是4,因?yàn)樗褪且粋€(gè)指針。如果是數(shù)組的大小,那么是4*3*4=48,它實(shí)際上是一個(gè)指針的指針的二維數(shù)組。
9. 編寫(xiě)一個(gè)函數(shù),要求輸入年月日時(shí)分秒,輸出該年月日時(shí)分秒的下一秒。如輸入2004年12月31日23時(shí)59分59秒,則輸出2005年1月1日0時(shí)0分0秒。
答:參見(jiàn)具體代碼:
- void NextTime (
- int *year,
- int *month,
- int *date,
- int *hour,
- int *minute,
- int*second
- )
- {
- int dayOfMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
- if (*year < 0 || *month < 1 || *month > 12 ||
- *date < 1 || *date > 31 || *hour < 0 || *hour > 23 ||
- *minute < 0 || *minute > 59 || *second <0 || *second >60)
- return;
-
- //處理閏年
- if ((*year % 400 == 0) || ((*year % 100 != 0) && (*year % 4 == 0)))
- dayOfMonth[1] = 29;
-
- *second = *second + 1;
- if (*second >= 60)
- {
- *second = 0;
- *minute += 1;
- if (*minute >= 60)
- {
- *minute = 0;
- *hour += 1;
- if (*hour >= 24)
- {
- *hour = 0;
- *date += 1;
- if (*date > dayOfMonth[*month - 1])
- {
- *date = 1;
- *month += 1;
- if (*month > 12)
- {
- *month = 1;
- *year += 1;
- }
- }
- }
- }
- }
- return;
- }
10. 寫(xiě)一個(gè)函數(shù),判斷一個(gè)int型的整數(shù)是否是2的冪,即是否可以表示成2^X的形式(不可以用循環(huán))。
答:這里指定了不能用循環(huán),那么可以考慮使用遞歸,下面是具體的代碼:
- #define TRUE 1
- #define FALSE 0
- int IsBinrayPower(int num) {
- int tmp = num;
- //0的時(shí)候返回FALSE
- if (tmp == 0) {
- return FALSE;
- } else if (tmp == 1) {
- // 1 = 2 ^ 0,所以返回TRUE;
- return TRUE;
- }
- else {
- if (tmp % 2 == 0) {
- return IsBinrayPower(num / 2);
- } else {
- return FALSE;
- }
-
- }
- }
還有一種方法,一句代碼就搞定了:
- #define TRUE 1
- #define FALSE 0
- int IsBinrayPower(int num) {
- return (num & (num - 1)) ? FALSE : TRUE;
- }
11. int (* (*f)(int, int))(int)表示什么含義?
答:f是一個(gè)函數(shù)指針,它的參數(shù)是(int ,int),返回值是一個(gè)函數(shù)指針(形式是int *(g)(int))。雖然看上去很復(fù)雜,但是在實(shí)際的應(yīng)用中確實(shí)也有類(lèi)似的,比如在signal.h中就有這樣的定義:
- void (*signal(int, void (*)(int)))(int);
(以上來(lái)自O(shè)S X系統(tǒng),其它系統(tǒng)可能略有不同)
12. x=x+1,x+=1,x++,為這三個(gè)語(yǔ)句的效率排序。并說(shuō)明為什么。
答:從網(wǎng)上找到的結(jié)果是,x=x+1 < x+1 < x++,因?yàn)椋?/p>
x=x+1的執(zhí)行過(guò)程如下:1. 讀取右x的地址; 2. x+1; 3. 讀取左x的地址; 4. 將右值傳給左邊的x(編譯器并不認(rèn)為左右x的地址相同)。
x+=1的執(zhí)行過(guò)程如下:1. 讀取右x的地址; 2. x+1; 3. 將得到的值傳給x(因?yàn)閤的地址已經(jīng)讀出)。
x++的執(zhí)行如下:1. 讀取右x的地址; 2. x自增1。
但實(shí)際的情況是:VS2015下反匯編的結(jié)果如下:
- x = x + 1;
- 00D81685 mov eax,dword ptr [x]
- 00D81688 add eax,1
- 00D8168B mov dword ptr [x],eax
- x += 1;
- 00D8168E mov eax,dword ptr [x]
- 00D81691 add eax,1
- 00D81694 mov dword ptr [x],eax
- x++;
- 00D81697 mov eax,dword ptr [x]
- 00D8169A add eax,1
- 00D8169D mov dword ptr [x],eax
實(shí)際上根本沒(méi)有什么區(qū)別,編譯器會(huì)去優(yōu)化的。
13. 寫(xiě)一算法檢測(cè)單向鏈表中是否存在環(huán)(whether there is a loop in a link list),要求算法復(fù)雜度(Algorithm's complexity是O(n)) 并只使用常數(shù)空間(space is O(c))。
答:使用追趕的方法,設(shè)定兩個(gè)指針slow、fast,從頭指針開(kāi)始,每次分別前進(jìn)1步、2步。如存在環(huán),則兩者相遇;如不存在環(huán),fast遇到NULL退出。具體的代碼如下:
- #define TRUE 1
- #define FALSE 0
- typedef struct _Node{
- int data;
- struct _Node * next;
- } Node;
- int IsLoop(Node *head)
- {
- Node *pSlow = head;
- Node *pFast = head;
- while (pSlow != NULL && pFast != NULL)
- {
- pSlow = pSlow->next;
- pFast = pFast->next->next;
- if (pSlow == pFast)
- return TRUE;
- }
- return FALSE;
- }
14. static全局變量與普通全局變量有什么區(qū)別?static局部變量和普通局部變量有什么區(qū)別?static函數(shù)與普通函數(shù)有什么區(qū)別?
答:
1. static全局變量和普通的全局變量,在內(nèi)存中的位置是一樣的,區(qū)別在于static全局變量只在當(dāng)前的文件有效,而普通全局變量在所有的文件中都有效。
2. static局部變量和普通局部變量在內(nèi)存中的存儲(chǔ)就不一樣了,使得普通全局變量每次都會(huì)重新初始化,而static局部變量只會(huì)初始化一次,之后就沿用上一次的值。
3. static函數(shù)和普通函數(shù)的差別是,static函數(shù)只在當(dāng)前文件有效,而普通函數(shù)默認(rèn)是extern的,因此在其它文件也有效。
15. 下面程序的打印結(jié)果是什么?
- #include<stdio.h>
- main()
- {
- char *a = "hello";
- char *b = "hello";
- if (a == b)
- printf("YES");
- else
- printf("NO");
- }
答:粗的來(lái)看應(yīng)該是打印NO,但是因?yàn)閔ello是存放在靜態(tài)存儲(chǔ)區(qū)的,編譯器有可能進(jìn)行優(yōu)化,將a和b指向同一個(gè)hello,此時(shí)a==b。在vs2015上的測(cè)試結(jié)果也是YES。
16. 求a b c的結(jié)果。
答:參見(jiàn)具體的代碼,這題主要考察的是一個(gè)就近原則,即a+++b實(shí)際上是(a++)+b;還有就是后++發(fā)生在+=等操作之后:
- #include<stdio.h>
- void main()
- {
- int a = 5, b = 7, c;
- c = a+++b;
- printf("a = %d, b = %d, c= %d\n", a, b, c); //a = 6, b = 7, c= 12
- }
17. What does the following function return?- #include<stdio.h>
- char foo(void)
- {
- unsigned int a = 6;
- int b = -20;
- printf("%d\n", ((a + b) > 6));
- char c;
- (a + b > 6) ? (c = 1) : (c = 0);
- return c;
- }
-
- void main()
- {
- printf("%d\n", foo()); //1
- }
答:這里的考察的是一個(gè)類(lèi)型的轉(zhuǎn)換,在《c++ primer》中文版第五版中,P34頁(yè)有這么一句:“當(dāng)一個(gè)算術(shù)表達(dá)式中既有無(wú)符號(hào)數(shù)又有int值時(shí),那個(gè)int值就會(huì)轉(zhuǎn)換成無(wú)符號(hào)數(shù)?!币虼司涂梢钥吹竭@里的a+b中,-20會(huì)被轉(zhuǎn)換成無(wú)符號(hào)數(shù),所以a+b > 6成立,因此c=1。
18. 有1,2,....一直到n的無(wú)序數(shù)組,求排序算法,并且要求時(shí)間復(fù)雜度為O(n),空間復(fù)雜度O(1),使用交換,而且一次只能交換兩個(gè)數(shù)。
答:參見(jiàn)具體代碼:
- #include<stdio.h>
- void main()
- {
- int a[] = { 9, 3, 4, 5, 6, 8, 2, 7, 1 };
- //排序后的數(shù)組應(yīng)該是{1,2,3,4,5,6,7,8,9},也就是說(shuō)元素值和下標(biāo)是一一對(duì)應(yīng)的,這個(gè)就是算法的基礎(chǔ)
-
- int tmp;//臨時(shí)存放數(shù)據(jù)
- int index;
- int length = sizeof(a) / sizeof(int);//數(shù)組長(zhǎng)度
-
- for (index = 0; index < length; ) {
- tmp = a[a[index] - 1];//a[index]是原值,原值應(yīng)該放的位置是a[index]-1,這個(gè)位置對(duì)應(yīng)的值是a[a[index] - 1]
- a[a[index] - 1] = a[index];
- a[index] = tmp;
- //index++的條件是該位置的值已經(jīng)正確了
- if (a[index] == index + 1) {
- index++;
- }
- }
-
- for (index = 0; index < length; index++) {
- printf("%d ", a[index]);
- }
- printf("\n");
- }
19. 寫(xiě)一個(gè)函數(shù)判斷計(jì)算機(jī)的字節(jié)存儲(chǔ)順序是升序(little-endian)還是降序(big-endian)。
答:需要記住的是,小端模式下低字節(jié)內(nèi)存放低位數(shù)據(jù),即,對(duì)于int類(lèi)型的數(shù)據(jù)0x12345678,最低地址放的是0x78。這個(gè)可以作為編程的依據(jù):
- #include <stdio.h>
-
- int main(void)
- {
- unsigned int a = 0x12345678;
- if (*((unsigned char *)&a) == 0x78) {
- printf("little end\n");
- }
- else {
- printf("big end");
- }
- return 0;
- }
20. 有個(gè)數(shù)組a[100]存放了100個(gè)數(shù),這100個(gè)數(shù)取自1-99,且只有兩個(gè)相同的數(shù),剩下的98個(gè)數(shù)不同,寫(xiě)一個(gè)搜索算法找出相同的那個(gè)數(shù)的值。(注意空間效率時(shí)間效率盡可能要低)。
答:參見(jiàn)第18題,兩者非常的相似。如果這里按照18題的代碼那樣進(jìn)行排序,并將原來(lái)的int a[] = { 9, 3, 4, 5, 6, 8, 2, 7, 1 };更換成int a[] = { 7, 3, 4, 5, 6, 8, 2, 7, 1 };代碼將會(huì)掛死。原因就是因?yàn)閮蓚€(gè)數(shù)相同之后,導(dǎo)致這兩個(gè)相同的一直再做交換。只要修改一下代碼,就可以用到這一題上來(lái)。
- #include<stdio.h>
- void main()
- {
- int a[] = { 7, 3, 4, 5, 6, 6, 1, 2, 8 };
-
- int tmp;//臨時(shí)存放數(shù)據(jù)
- int index;
- int length = sizeof(a) / sizeof(int);//數(shù)組長(zhǎng)度
-
- for (index = 0; index < length; ) {
- tmp = a[a[index] - 1];//a[index]是原值,原值應(yīng)該放的位置是a[index]-1,這個(gè)位置對(duì)應(yīng)的值是a[a[index] - 1]
- a[a[index] - 1] = a[index];
- a[index] = tmp;
- //index++的條件是該位置的值已經(jīng)正確了
- if (a[index] == index + 1) {
- index++;
- }
- //新增代碼
- else if (a[index] == a[a[index] - 1]) {
- printf("found: %d\n", a[index]);//found 6
- break;
- };
- }
- }
21. 寫(xiě)出判斷ABCD四個(gè)表達(dá)式的是否正確, 若正確, 寫(xiě)出經(jīng)過(guò)表達(dá)式中a的值。int a = 4;
(A)a += (a++); (B) a += (++a) ; (C) (a++) += a; (D) (++a) += (a++);
答:AB,CD錯(cuò)誤。具體的值參見(jiàn)代碼:
- #include<stdio.h>
- void main()
- {
- int a = 4;
- a += (a++);
- printf("a = %d\n", a);//9
-
- a = 4;
- a += (++a);
- printf("a = %d\n", a);//10
-
- a = 4;
- // (a++) += a;//錯(cuò)誤
- printf("a = %d\n", a);
-
- a = 4;
- // (++a) += (a++);//錯(cuò)誤
- printf("a = %d\n", a);
- }
a++和++a不能作為左值。a+=(a++),這里的a實(shí)際上只有一次自增會(huì)被計(jì)算進(jìn)去,第二次沒(méi)有,所以結(jié)果是4+5=9。
22. switch中允許的數(shù)據(jù)類(lèi)型是?
答:整型常量表達(dá)式。重點(diǎn)是整型和常量。
23. 嵌入式系統(tǒng)中經(jīng)常要用到無(wú)限循環(huán),你怎么樣用C編寫(xiě)死循環(huán)呢?
答:參見(jiàn)具體的代碼:
24. Typedef 在C語(yǔ)言中頻繁用以聲明一個(gè)已經(jīng)存在的數(shù)據(jù)類(lèi)型的同義字。也可以用預(yù)處理器做類(lèi)似的事。例如,思考一下下面的例子: - #define dPS struct s *
- typedef struct s * tPS;
以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個(gè)指向結(jié)構(gòu)s指針。哪種方法更好呢?(如果有的話(huà))為什么?
答:typedef好。具體見(jiàn)下面的代碼:
- #include<stdio.h>
- struct s {
- int a;
- int b;
- };
- #define dPS struct s *
- typedef struct s * tPS;
- void main()
- {
- dPS p1, p2;
- tPS p3, p4;
- printf("p1: %d, p2: %d, p3: %d, p4: %d\n", sizeof(p1), sizeof(p2), sizeof(p3), sizeof(p4)); //p1: 4, p2: 8, p3: 4, p4: 4
- }
注意結(jié)果中sizeof(p2)=8,原因是對(duì)于#define,編譯器只是在編譯時(shí)展開(kāi)宏,所以得到的結(jié)果是struct s *p1, p2。p2實(shí)際上就是一個(gè)結(jié)構(gòu)體,這個(gè)可能不是代碼真實(shí)需要的。
25. 如何判斷一段程序是由C編譯程序還是由C++編譯程序編譯的?
答:使用__cplusplus宏:
- #include <iostream>
- using std::cout;
- using std::endl;
-
- void main()
- {
- #if __cplusplus
- cout << "c++" << endl;
- #else
- cout << "c" << endl;
- #endif
- }
26. 用宏定義寫(xiě)出swap(x, y)。
答:具體參見(jiàn)代碼:
- #define SWAP(x, y) (x = (x)+(y), y =(x)-(y), x = (x)-(y))
27. int(*s[10])(int);表示的是什么。答:表示的是一個(gè)函數(shù)指針數(shù)組,每一個(gè)元素是一個(gè)形如int (*f)(int)的函數(shù)指針。
28. 關(guān)于struct位域的題目。
答:下面是幾個(gè)例子:
- struct s1 {
- int i : 1; //0偏移,占1位
- int j : 2; //1位偏移,占2位
- int a : 9; //3位偏器,占9位
- //int b : 33;
- };//補(bǔ)齊int大小,總共4個(gè)字節(jié)
- int main(void)
- {
- struct s1 s1 = { 1, 1, 1 };
- printf("%d\n", *(unsigned char *)(&s1)); //取結(jié)構(gòu)體的第一個(gè)字節(jié),得到的值是11,即1011b,證明了元素是緊緊排列的。沒(méi)有位對(duì)齊這么一說(shuō)。
-
- return 0;
- }
網(wǎng)上有幾個(gè)說(shuō)法:
1. 位域不能跨字節(jié)存儲(chǔ)。但是實(shí)際上是可以的,如上例中的s1.a,但是確實(shí)不能大于原始數(shù)據(jù)類(lèi)型的大小,這里就不能大于32。
2. 位域也需要對(duì)齊,比如這里的s1.j需要按2位對(duì)齊,所以偏移從2位開(kāi)始。實(shí)際上也是錯(cuò)的,同類(lèi)型位域就是緊挨著的。
另外一個(gè)例子:
- #include<stdio.h>
-
- struct s1 {
- int i : 8; //0偏移,占8位
- int j : 4; //8位偏移,占4位
- int a : 3; //12位偏器,占3位
- };//補(bǔ)齊int大小,總共4個(gè)字節(jié)
-
- struct s2 {
- int i : 8; //0偏移,占8位
- int j : 4; //8位偏移,占4位
- int a : 3; //12位偏器,占3位
- double b; //不同類(lèi)型還是需要對(duì)齊的,4字節(jié)偏移,占8字節(jié)
- };<span style="font-family: Arial, Helvetica, sans-serif;">//照理說(shuō)總共就12個(gè)字節(jié)可以了,但是還需要按照最大元素類(lèi)型的大小來(lái)補(bǔ)齊,所以需要時(shí)8字節(jié)的倍數(shù),所以總大小是16</span>
-
-
- struct s3 {
- int i : 8; //0偏移,占8位
- int j : 4; //8位偏移,占4位
- double b; //不同類(lèi)型還是需要對(duì)齊的,4字節(jié)偏移,占8字節(jié)
- int a : 3; //不同類(lèi)型還是需要對(duì)齊的,12字節(jié)偏移,占3位,再補(bǔ)齊到4個(gè)字節(jié)
- };//照理說(shuō)總共就16個(gè)字節(jié)可以了,但是還需要按照最大元素類(lèi)型的大小來(lái)補(bǔ)齊,所以需要時(shí)8字節(jié)的倍數(shù),所以總大小是24
-
- struct s4 {
- int i;
- double j;
- };//按最大元素大小整數(shù)倍,所以總大小是16
-
- int main(void)
- {
- printf("sizeof(int) = %d\n", sizeof(int)); //4
- printf("sizeof(double) = %d\n", sizeof(double)); //8
- printf("sizeof(s1) = %d\n", sizeof(struct s1)); //4
- printf("sizeof(s2) = %d\n", sizeof(struct s2)); //16
- printf("sizeof(s3) = %d\n", sizeof(struct s3)); //24
- printf("sizeof(s4) = %d\n", sizeof(struct s4)); //16
- return 0;
- }
29. 下面的代碼有什么錯(cuò)誤:- swap(int* p1, int* p2)
- {
- int *p;
- *p = *p1;
- *p1 = *p2;
- *p2 = *p;
- }
答:p是一個(gè)野指針,不能*p = *p1,有可能踩到不該踩的區(qū)域。
30. 求1000!的未尾有幾個(gè)0。
答:1-1000中,能夠整除5的有200個(gè),能夠整除25的有40個(gè),能夠整除125的有8個(gè),能夠整除625的有1個(gè),總共是249個(gè),所以有249個(gè)0。