版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、有關C/C+指針的經典面試題 (2010-06-06 00:26:50)轉載標簽: 雜談分類: C/C+C語言為何如此長壽并實用?C+為什么有那么多精彩?指針可以說是C/C+中的靈魂所在,雖然早期中pascal也有指針,但是和C/C+比起來不是一個級別的.今天為大家深入淺出的解析一下指針的有關筆試,面試題.所有題目來源網絡,分析是我寫的.0.預備知識,最基礎的指針其實最基礎的指針也就應該如下面代碼:int a;int* p=&a;也就是說,聲明了一個int變量a,然后聲明一個int 的指針,*p指向a的地址,&也就是取地址符號,而*是指針中取內容的
2、符號,僅僅在聲明的時候標記這個變量是指針.可能有點繞口,但是看代碼來的容易的多. 1.與const在一起的時候常常聲明的時候會讓人一頭霧水,比如下面的聲明,均是聲明一個char* p的指針:char * const p; / 指針不可改,也就說指針只能指向一個地址,不能更改為其他地址char const * p; / 所指內容不可改,也就是說*p是常量字符串char const * const p; / 內容和指針都不能改const char * const p; / 同上.內容和指針不能改額.別暈,別暈
3、.其實方法很簡單.你別真死記硬背.其實可以以*為分界符,在*左邊有const就說明內容不能改,在*右邊就說明指針不能改,而左邊的char和const順序是不要緊的.呵呵.你也可以理解成const是修飾后面的,正常順序應該這樣:const char * const p; 是不是看起來簡單了? 2.忽悠人的陷阱,str和*str的區(qū)別先告訴你哦,下面的題目可是陷阱啊.說說程序結果.char str1 = “abc”;char str2 = “abc”;const char str3 = “abc”;const char str4 = “abc”;const char *str5 = “a
4、bc”;const char *str6 = “abc”;char *str7 = “abc”;char *str8 = “abc”;cout << ( str1 = str2 ) << endl;cout << ( str3 = str4 ) << endl;cout << ( str5 = str6 ) << endl;cout << ( str7 = str8 ) << endl;怎么樣?都輸出true?那顯然你中標了.而且cout輸出bool值的時候,就算全是真也應該都輸出1啊.4個1?那也
5、不對.答案是0011,不信你試試.為什么呢?其實都說了這題是個大陷阱,因為這題根本不是比較字符串內容!而是比較字符串的地址.哦.恍然大悟.那為什么前兩個是假呢?因為這可是說是一個深拷貝/淺拷貝的問題.當字符串是數(shù)組形式聲明并初始化,編譯器認為是新數(shù)組,分配新空間,但不是深拷貝,因為根本就不算拷貝.而如果是相同的字符串,用指針聲明,那就是比較如果有一樣的字符串,就直接把新指針指過去,這是正宗的淺拷貝.哇哈.你就中計了. 3.str用sizeof判斷會出錯么?應該說我們常常用指針有很多時候是解決字符串的問題,一般我們用strlen,這當然沒有問題,但是要你編一個呢?看看下面這個MyStr
6、len有問題么?int MyStrlen(char str) return (int)(sizeof(str)-1);呵呵.咱們上當過一次.這個當然也是不對的.不錯.這個函數(shù)是錯的.為什么呢?首先,可以告訴你,無論何時,返回的總是3.額.是不是很奇怪,為什么不是數(shù)組長度呢?str不是char數(shù)組指針么?不錯.確實是數(shù)組的指針,但是,當用函數(shù)傳遞的數(shù)組指針的時候就自動退化為指針了,而指針的長度是4,你減去1了自然就是3了.但是如果按照下面代碼就可以得到正常的值.char str="hello world"int len=sizeo
7、f(str)-1; /記得減1哦,最后有'0'結尾cout<<len;這樣輸出的是正常值,也就是你所希望的11; 4.注意數(shù)組指針和指針繼續(xù)上面的話題,剛剛提到了數(shù)組指針和指針,現(xiàn)在看看下面這端程序代碼:int a5=1,2,3,4,5;int *ptr=(int *)(&a+1);cout<<*(a+1)<<*(ptr-1);呵呵.BaihowFF總是給陷阱.肯定不是想當然的說就是21.確實.答案是25.額.奇怪吧.為什么呢?首先,a是一個數(shù)組,所以編譯器解釋&a就是a的全部長度,
8、就是說(&a+1)也就是說移動了一個數(shù)組,指向了并不存在的a5,所以ptr-1才會指向a數(shù)組的最后一個元素a4,而a+1和a1是一樣的.所以答案是25,如果你去掉了(&a+1)的括號,那么答案就是想當然的21了.呵呵.很微妙吧. 5.注意指針要分配給足夠的空間新手在剛剛接觸指針的時候經常會忘記給指針分配空間,直接用肯定是有問題的,那么下面的程序呢?char a;char *str=&a;strcpy(str,”hello”);cout<<str;BaihowFF是壞蛋.總會下套.呵呵.確實是圈套.這段程序能夠輸出hello,但是輸出后就崩潰了.原因
9、就在你分配str指針的時候僅僅給了1字節(jié)的空間,但是你拷貝了6字節(jié)過去(不要忘記了最后的'0'結束).運行輸出后程序因為訪問了沒有分配的呵呵空間,當然崩潰了.如果你只strcpy(str,"");那程序是可以正常運行的. 6.小心編譯器的指針字符串初始化經常我們想自己處理字符串,但是像下面的初始化是很危險的!char* s="AAA"cout<<s<<endl;s0='B'cout<<s<<endl;你可以拿這段程序去編譯.沒錯!編譯器報告正常!.這是最要命的.其實
10、程序不能運行的.輸出AAA后就崩潰了.為什么?因為當你在第一句初始化的時候,編譯器就認為這是個字符串常量了.再做數(shù)組操作的時候肯定錯了羅.最好的習慣是聲明一個指針,用new分配空間,然后用庫函數(shù)操作,比如strcpy,strcat等等. 7.讓人一眼看上去迷糊的函數(shù)指針看看這句代表什么意思?int (*s10)(int);咦.這是什么?其實這是一個函數(shù)指針數(shù)組,指向了一組int fun(int)的函數(shù),第一眼確實讓人有點迷糊.但是請習慣這樣. 8.注意函數(shù)傳遞指針的時候是副本副本?又下副本?.汗.老兄.不是這個意思.別沉浸在WOW里了啊.看看下面程序的問題:void Get
11、Memory(char *p)p=new char100;strcpy(p,"hello world");void main(void)char *str=NULL;GetMemory(str);cout<<str;delete str;str=NULL;當然了.喜歡下套的BaihowFF又給了錯程序.錯在哪呢?看上去是對的,而且編譯器編譯也正確啊.怎么就是不能通過呢?而且還崩潰了.好費解吧.其實原因很簡單.GetMemory這個函數(shù)出問題了!函數(shù)參數(shù)是不能傳遞分配空間的.因為傳遞過去實際上是一個副本p.不能返回的.而且你在delete那就是件很危險的事情.因為
12、壓根沒有內容.那我實在想這樣用函數(shù)分配怎么辦呢?像下面這樣改一下就ok了:void GetMemory(char *p) / 改成晦澀難懂的指針的指針*p=new char100; /給*p的分配地址strcpy(*p,"hello world"); / 拷貝內容到*pvoid main(void)char *str=NULL;GetMemory(&str); /這地方取地址cout<<
13、;str;delete str;str=NULL;這樣就能正常工作了,但是看起來好別扭啊.嗯.確實.但是還可以用其他方法哦.你想想.肯定有辦法的.9.請時刻記住要初始化字符串嗯.這點大家都知道.那你猜猜下面的程序結果是多少?char a10;cout<<strlen(a)<<endl;答案應該讓你以外.竟然是15.沒道理吧?!其實strlen函數(shù)的結果和是否初始化有關的.雖然你分配了空間.但是沒有初始化.庫函數(shù)會出錯的.sizeof不受影響.切忌初始化哦. 10.小括號,大區(qū)別看看這兩端聲明,有什么不同?我直接在注釋里告訴你答案吧.這樣好看點.char (*s
14、tr)20; /str是一個數(shù)組指針,即指向數(shù)組的指針char *str20; /str是一個指針數(shù)組,其元素為指針型數(shù)據千萬別小看括號哦.區(qū)別大了吧.1.char * const p;char const * pconst char *p上述三個有什么區(qū)別?char * const p; /常量指針,p的值不可以修改char const * p;/指向常量的指針,指向的常量值不可以改const char *p; /和char const *p2.char str1 = “abc”;char str2 = “abc
15、”;const char str3 = “abc”;const char str4 = “abc”;const char *str5 = “abc”;const char *str6 = “abc”;char *str7 = “abc”;char *str8 = “abc”;cout << ( str1 = str2 ) << endl;cout << ( str3 = str4 ) << endl;cout << ( str5 = str6 ) << endl;cout << ( str7 = str8 )
16、<< endl;打印結果是什么?解答:結果是:0 0 1 1str1,str2,str3,str4是數(shù)組變量,它們有各自的內存空間;而str5,str6,str7,str8是指針,它們指向相同的常量區(qū)域3. 以下代碼中的兩個sizeof用法有問題嗎?void UpperCase( char str ) / 將 str 中的小寫字母轉換成大寫字母for( size_t i=0; i<sizeof(str)/sizeof(str0); +i )if( a<=stri && stri<=z )stri -= (a-'A );char str =
17、“aBcDe”;cout << “str字符長度為: ” << sizeof(str)/sizeof(str0) << endl;UpperCase( str );cout << str << endl;答:函數(shù)內的sizeof有問題。根據語法,sizeof如用于數(shù)組,只能測出靜態(tài)數(shù)組的大小,無法檢測動態(tài)分配的或外部數(shù)組大小。函數(shù)外的str是一個靜態(tài)定義的數(shù)組,因此其大小為6,函數(shù)內的str實際只是一個指向字符串的指針,沒有任何額外的與數(shù)組相關的信息,因此sizeof作用于上只將其當指針看,一個指針為4個字節(jié),因此返回4。4.main
18、()int a5=1,2,3,4,5;int *ptr=(int *)(&a+1);printf(“%d,%d”,*(a+1),*(ptr-1);輸出結果是什么?答案:輸出:2,5*(a+1)就是a1,*(ptr-1)就是a4,執(zhí)行結果是2,5&a+1不是首地址+1,系統(tǒng)會認為加一個a數(shù)組的偏移,是偏移了一個數(shù)組的大小(本例是5個int)int *ptr=(int *)(&a+1);則ptr實際是&(a5),也就是a+5原因如下:&a是數(shù)組指針,其類型為 int (*)5;而指針加1要根據指針類型加上一定的值,不同類型的指針+1之后增加的大小不同。a是長
19、度為5的int數(shù)組指針,所以要加 5*sizeof(int)所以ptr實際是a5但是prt與(&a+1)類型是不一樣的(這點很重要)所以prt-1只會減去sizeof(int*)a,&a的地址是一樣的,但意思不一樣a是數(shù)組首地址,也就是a0的地址,&a是對象(數(shù)組)首地址,a+1是數(shù)組下一元素的地址,即a1,&a+1是下一個對象的地址,即a5.5.請問以下代碼有什么問題:int main()char a;char *str=&a;strcpy(str,”hello”);printf(str);return 0;答案:沒有為str分配內存空間,
20、將會發(fā)生異常。問題出在將一個字符串復制進一個字符變量指針所指地址。雖然可以正確輸出結果,但因為越界進行內在讀寫而導致程序崩潰。6. char* s=”AAA”;printf(“%s”,s);s0=B'printf(“%s”,s);有什么錯?答案:“AAA”是字符串常量。s是指針,指向這個字符串常量,所以聲明s的時候就有問題。cosnt char* s=”AAA”;然后又因為是常量,所以對是s0的賦值操作是不合法的。7. int (*s10)(int) 表示的是什么?答案:int (*s10)(int) 函數(shù)指針數(shù)組,每個指針指向一個int func(int param)的函數(shù)。8.有以
21、下表達式:int a=248; b=4;int const c=21;const int *d=&a;int *const e=&b;int const *f const =&a;請問下列表達式哪些會被編譯器禁止?為什么?*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;答案:*c 這是個什么東東,禁止*d 說了是const, 禁止e = &a 說了是const 禁止const *f const =&a; 禁止9.#include <stdio.h>#include <stdlib.h>voi
22、d getmemory(char *p) p=(char *) malloc(100);strcpy(p,”hello world”); int main( )char *str=NULL;getmemory(str);printf(“%s/n”,str);free(str);return 0;分析一下這段代碼答案:程序崩潰,getmemory中的malloc 不能返回動態(tài)內存, free()對str操作很危險博主:getmemory中p是形參,是一個指針變量,getmemory(str)調用后,傳入的是指針變量保存的對象地址,p=(char *) malloc(100)實
23、際上是把申請的動態(tài)內存空間的首地址付給p指向的地址(即str指向的地址null),這個是錯誤的。應該修改成指向指針的指針void getmemory(char *p),這樣malloc返回的地址付給*p(即str變量本身)。10.char szstr10;strcpy(szstr,”0123456789);產生什么結果?為什么?答案:長度不一樣,會造成非法的OS11.要對絕對地址0×100000賦值,我們可以用(unsigned int*)0×100000 = 1234;那么要是想讓程序跳轉到絕對地址是0×100000去執(zhí)行,應該怎么做?答案:*(void (*)
24、( )0×100000 ) ( );首先要將0×100000強制轉換成函數(shù)指針,即:(void (*)()0×100000然后再調用它:*(void (*)()0×100000)();用typedef可以看得更直觀些:typedef void(*)() voidFuncPtr;*(voidFuncPtr)0×100000)();12. 分析下面的程序:void GetMemory(char *p,int num) &
25、#160; /p,指向指針的指針,*p,p指向的指針(即str),*p,最終的對象,str指向的單元*p=(char *)malloc(num); /申請空間首地址付給傳入的被p指向的指針,即str int main()char *str=NULL;GetMemory(&str,100); /傳入指針變量本身的地址strcpy(str,”hello”);free(str);if(str!
26、=NULL)strcpy(str,”world”); printf(“n str is %s”,str); 軟件開發(fā)網 getchar(); 問輸出結果是什么?答案:輸出str is world。free 只是釋放的str指向的內存空間,它本身的值還是存在的.所以free之后,有一個好的習慣就是將str=NULL.此時str指向空間的內存已被回收,如果輸出語句之前還存在分配空間的操作的話,這段存儲空間是可能被重新分配給其他變量的,盡管這段程序確實是存在大大的問題(上面各位已經說得很清楚了),但是通常會打印出world來。這是因為,進程中的內存管理一般不是由操作系統(tǒng)完成的,而
27、是由庫函數(shù)自己完成的。當你malloc一塊內存的時候,管理庫向操作系統(tǒng)申請一塊空間(可能會比你申請的大一些),然后在這塊空間中記錄一些管理信息(一般是在你申請的內存 前面一點),并將可用內存的地址返回。但是釋放內存的時候,管理庫通常都不會將內存還給操作系統(tǒng),因此你是可以繼續(xù)訪問這塊地址的。-13.char a10;strlen(a)為什么等于15?#include “stdio.h”#include “string.h”void main()char aa10;printf(“%d”,strlen(aa);答案:sizeof()和初不初始化,沒有關系;strlen()和初始化有關。14.cha
28、r (*str)20;/*str是一個數(shù)組指針,即指向數(shù)組的指針*/char *str20;/*str是一個指針數(shù)組,其元素為指針型數(shù)據*/15.#include<iostream.h>#include <string.h>#include <malloc.h>#include <stdio.h>#include <stdlib.h>#include <memory.h>typedef struct AAint b1:5;int b2:2;AA;void main()AA aa;char cc100;strcp
29、y(cc,”0123456789abcdefghijklmnopqrstuvwxyz”);memcpy(&aa,cc,sizeof(AA);cout << aa.b1 <<endl;cout << aa.b2 <<endl;輸出結果是多少?答案:-16和首先sizeof(AA)的大小為4,b1和b2分別占5bit和2bit.經過strcpy和memcpy后,aa的4個字節(jié)所存放的值是: 0,1,2,3的ASC碼,即00110000,00110001,00110010,00110011所以,最后一步:顯示的是這個字節(jié)的前位,和 之后的位分別
30、為:10000,和01,因為int是有正負之分-16 試題三: 以下代碼有哪些錯誤或不足之處void GetMemory( char *p, int num )*p = (char *) malloc( num ); void Test( void )char *str = NULL;GetMemory( &str, 100 );strcpy( str, "hello" );printf( str );解答:存在2處問題:本題中的Test函數(shù)中未對malloc的內存進行釋放。本題中的GetMemory避免了試題一的問題,傳入GetMe
31、mory的參數(shù)為字符串指針的指針,但是在GetMemory中執(zhí)行申請內存及賦值語句*p = (char *) malloc( num );后未判斷內存是否申請成功,應加上:if ( *p = NULL )./進行申請內存失敗處理17 試題四:找出下面代碼的不足或錯誤之處void Test( void )char *str = (char *) malloc( 100 );strcpy( str, "hello" );free( str );. /省略的其它語句解答:存在2處問題:試題四存在與試題三同樣的問題,在執(zhí)行char *str = (char *) malloc(10
32、0);后未進行內存是否申請成功的判斷;另外,在free(str)后未置str為空,導致可能變成一個“野”指針,應加上:str = NULL;18 判斷輸出是亂碼 還是字符或是字符串 還是表示地址值 ? 如果是地址值就用0xF1247000代表.char類型指針的輸出 標準庫cout輸出時,無法判斷指針的類型,如下面程序所示:char ch = 'a'int num = 1;char *pch = &ch;int *pnum = #std:
33、cout<<pch<<std:endl; /輸出:亂碼std:cout<<(void*)pch<<std:endl; /輸出:0xF1247000std:cout<<pnum<<std:endl;/輸出:0xF1247004std:cout<<(void*)pnum<<std:endl; /輸出:0xF12470004char *pch2="Hello"std:cout<<pch2<&
34、lt;std:endl;/輸出:Hellostd:cout<<(void*)pch2<<std:endl;/輸出:16進制地址 對于字符型指針,要用void*進行類型轉換后,才能輸出其地址,地址以16進制數(shù)的格式顯示32位地址值。若不進行轉換,cout會按照char類型解析指針內容。若是一個字符,沒有'0'結束符,輸出亂碼;若是字符串,則輸出字符串內容。 除了字符指針,其他指針都可以直接用cout語句來輸出地址值。無須進行指針類型轉換。19 指針與引用的區(qū)別?答案
35、:(1)非空區(qū)別。在任何情況下都不能使用指向空值的引用。因此如果你使用一個變量并讓它指向一個對象,但是該變量在某些時候也可能不指向任何對象,這時你應該把變量聲明為指針,因為這樣你可以賦空值給該變量。相反,如果變量肯定指向一個對象,例如你的設計不允許變量為空,這時你就可以把變量聲明為引用。不存在指向空值的引用這個事實意味著使用引用的代碼效率比使用指針要高。(2)合法性區(qū)別。在使用引用之前不需要測試它的合法性。相反,指針則應該總是被測試,防止其為空。(3)可修改區(qū)別。指針與引用的另一個重要的區(qū)別是指針可以被重新賦值以指向另一個不同對象。但是引用則總是指向在初始化時被指定的對象,以后不能改變,但是指
36、定的對象其內容可以改變。思路: 遇到次類型的題目 一定要想想他們的特點是什么 抓住特點進行分析 想想他們的功能是什么 進行比較20:下面5個函數(shù)哪個能成功進行兩個數(shù)的交換?cpp view plain copy 1. #include<iostream> 2. using namespace std; 3. 4. void&
37、#160;swap1(int p,int q) 5. 6. int temp; 7. temp=p; 8. p=q; 9. q=temp; 10. 11. 12. void
38、swap2(int *p,int *q) 13. 14. int *temp; 15. *temp=*p; 16. *p=*q; 17. *q=*temp; 18. 19. 20. v
39、oid swap3(int *p,int *q) 21. 22. int *temp; 23. temp=p; 24. p=q; 25. q=temp; 26. 27. 28
40、. void swap4(int *p,int *q) 29. 30. int temp; 31. temp=*p; 32. *p=*q; 33. *q=temp; 34. 35.
41、160;36. void swap5(int &p,int &q) 37. 38. int temp; 39. temp=p; 40. p=q; 41. q=temp; 42. 43.
42、0; 44. int main () 45. 46. int a=1,b=2; 47. /swap1(a,b); 48. /swap2(&a,&b); 49. /swap3(&a,&b);
43、50. /swap4(&a,&b); 51. /swap5(a,b); 52. cout << "a:"<< a <<endl; 53. cout << "b:"<<
44、 b <<endl; 54. 55. return 0; 56. 解析:這道題考察的是參數(shù)傳遞、值傳遞、指針傳遞(地址傳遞)和引用傳遞。 swap1傳遞的是值的副本,在函數(shù)中只是修改了形參p、q(實際是a、b的一個拷貝),p、q的值確實交換了,但是它們是局部變量,不會影響到主函數(shù)a和 b 。當函數(shù)swap1生命周期結束時,p、q所在的棧也就被刪除了。
45、60; swap2傳遞的是一個地址進去,在函數(shù)體內的形參*p、*q是指向實際的參數(shù)a、b地址的兩個指針。 這里要注意: int *temp; *temp=*p; 是不符合邏輯的,i
46、nt *temp新建了一個指針(但是沒分配內存)。*temp=*p不是指向而是拷貝。把*p所指向的內存的值(也就是a 的值)拷貝到*temp所指向內存里了。但是int *temp不是不分配內存嗎?的確不分配,于是系統(tǒng)在拷貝時臨時給了一個隨機地址,讓它存值。分配的隨機地址是個“意外”,且函數(shù)結束后不回收,造成內存泄漏。 swap3傳遞的是一個地址,在函數(shù)體內的參數(shù)*p、*q是指向實際參數(shù)a、b地址的兩個指針。 這里要注意:
47、0; int *temp; temp=p; int *temp新建了一個指針(但是沒分配內存)。temp=p是指向而不是拷貝。temp指向了*p所指向的地址(也就是a )。而代碼: int *temp; q=temp; 但是函數(shù)swa
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《培訓教程課件》課件
- 2025合資辦學合同
- 2025辦公用品的長期采購合作合同
- 農村社會實踐報告范文
- 超市盤點分析報告范文
- 監(jiān)理工作總結報告范文
- 課題申報書:高水平大學教學為主型崗位準入與動態(tài)轉換機制研究
- 上海農林職業(yè)技術學院《針織服飾設計》2023-2024學年第一學期期末試卷
- 11葡萄溝 公開課一等獎創(chuàng)新教學設計
- 3《自己之歌》公開課一等獎創(chuàng)新教學設計統(tǒng)編版高中語文選擇性必修中冊
- (完整word版)首件檢驗管理制度
- 線路工程灌注樁施工作業(yè)指導書施工方案
- 重力壩的分縫與止水
- 三重管高壓旋噴樁施工工藝規(guī)程與施工方案
- 個體診所藥品清單
- PFMEA的嚴重度SOD的評分和優(yōu)先級別
- 國網基建國家電網公司輸變電工程結算管理辦法
- 100道遞等式計算(能巧算得要巧算)
- 中國地圖含省份信息可編輯矢量圖
- 路政運政交通運輸執(zhí)法人員考試題庫
- 企業(yè)技術標準化管理
評論
0/150
提交評論