指針!


    

指針的經典面試題

C語言爲何如此長壽並實用?C++爲什麼有那麼多精彩?指針可以說是C/C++中的靈魂所在,雖然早期中pascal也有指針,但是和C/C++比起來不是一個級別的.今天爲大家深入淺出的解析一下指針的有關筆試,面試題.所有題目來源網絡,分析是我寫的...

0.預備知識,最基礎的指針

其實最基礎的指針也就應該如下面代碼:
int a;
int* p=&a;
也就是說,聲明瞭一個int變量a,然後聲明一個int 的指針,*p指向a的地址,&也就是取地址符號,而*是指針中取內容的符號,僅僅在聲明的時候標記這個變量是指針.可能有點繞口,但是看代碼來的容易的多...

1.與const在一起的時候

常常聲明的時候會讓人一頭霧水,比如下面的聲明,均是聲明一個char* p的指針:
char * const p;    // 指針不可改,也就說指針只能指向一個地址,不能更改爲其他地址
char const * p;   // 所指內容不可改,也就是說*p是常量字符串
char const * const p; // 內容和指針都不能改
const char * const p; // 同上...內容和指針不能改
額...別暈,別暈....其實方法很簡單...你別真死記硬背...其實可以以*爲分界符,在*左邊有const就說明內容不能改,在*右邊就說明指針不能改,而左邊的char和const順序是不要緊的...呵呵...你也可以理解成const是修飾後面的,正常順序應該這樣:const char * const p; 是不是看起來簡單了?

2.忽悠人的陷阱,str[]和*str的區別

先告訴你哦,下面的題目可是陷阱啊....說說程序結果...
char str1[] = “abc”;
char str2[] = “abc”;

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 ) << endl;
怎麼樣?都輸出true?那顯然你中標了...而且cout輸出bool值的時候,就算全是真也應該都輸出1啊...4個1?那也不對...答案是0011,不信你試試...爲什麼呢?
其實都說了這題是個大陷阱,因爲這題根本不是比較字符串內容!而是比較字符串的地址.哦...恍然大悟...那爲什麼前兩個是假呢?因爲這可是說是一個深拷貝/淺拷貝的問題.當字符串是數組形式聲明並初始化,編譯器認爲是新數組,分配新空間,但不是深拷貝,因爲根本就不算拷貝.而如果是相同的字符串,用指針聲明,那就是比較如果有一樣的字符串,就直接把新指針指過去,這是正宗的淺拷貝.哇哈...你就中計了...

3.str[]用sizeof判斷會出錯麼?

應該說我們常常用指針有很多時候是解決字符串的問題,一般我們用strlen,這當然沒有問題,但是要你編一個呢?看看下面這個MyStrlen有問題麼?
int MyStrlen(char str[])
{
    return
(int)(sizeof(str)-1);
}
呵呵...咱們上當過一次..這個當然也是不對的...不錯...這個函數是錯的...爲什麼呢?
首先,可以告訴你,無論何時,返回的總是3...額...是不是很奇怪,爲什麼不是數組長度呢?str不是char數組指針麼?不錯...確實是數組的指針,但是,當用函數傳遞的數組指針的時候就自動退化爲指針了,而指針的長度是4,你減去1了自然就是3了.但是如果按照下面代碼就可以得到正常的值.
char str[]="hello world";
int len=sizeof(str)-1;   //記得減1哦,最後有'/0'結尾
cout<<len;
這樣輸出的是正常值,也就是你所希望的11;

4.注意數組指針和指針

繼續上面的話題,剛剛提到了數組指針和指針,現在看看下面這端程序代碼:
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
cout<<*(a+1)<<*(ptr-1);
呵呵...BaihowFF總是給陷阱..肯定不是想當然的說就是21...確實...答案是25...額...奇怪吧..爲什麼呢?
首先,a是一個數組,所以編譯器解釋&a就是a的全部長度,就是說(&a+1)也就是說移動了一個數組,指向了並不存在的a[5],所以ptr-1纔會指向a數組的最後一個元素a[4],而a+1和a[1
]是一樣的...所以答案是25,如果你去掉了(&a+1)的括號,那麼答案就是想當然的21了...呵呵...很微妙吧....

5.注意指針要分配給足夠的空間

新手在剛剛接觸指針的時候經常會忘記給指針分配空間,直接用肯定是有問題的,那麼下面的程序呢?
char a;
char *str=&a;
strcpy(str,”hello”);
cout<<str;
BaihowFF是壞蛋..總會下套...呵呵..確實是圈套...這段程序能夠輸出hello,但是輸出後就崩潰了...原因就在你分配str指針的時候僅僅給了1字節的空間,但是你拷貝了6字節過去(不要忘記了最後的'/0'結束).運行輸出後程序因爲訪問了沒有分配的呵呵空間,當然崩潰了.如果你只strcpy(str,"");那程序是可以正常運行的.

6.小心編譯器的指針字符串初始化

經常我們想自己處理字符串,但是像下面的初始化是很危險的!!!
char* s="AAA";
cout<<s<<endl;
s[0]='B';
cout<<s<<endl;
你可以拿這段程序去編譯...沒錯!編譯器報告正常!...這是最要命的...其實程序不能運行的...輸出AAA後就崩潰了..爲什麼?因爲當你在第一句初始化的時候,編譯器就認爲這是個字符串常量了...再做數組操作的時候肯定錯了羅...最好的習慣是聲明一個指針,用new分配空間,然後用庫函數操作,比如strcpy,strcat等等...

7.讓人一眼看上去迷糊的函數指針

看看這句代表什麼意思?
int (*s[10])(int);
咦...這是什麼?其實這是一個函數指針數組,指向了一組int fun(int)的函數,第一眼確實讓人有點迷糊...但是請習慣這樣...

8.注意函數傳遞指針的時候是副本

副本?又下副本?...汗...老兄...不是這個意思...別沉浸在WOW裏了啊...看看下面程序的問題:
void GetMemory(char *p)
{
p=new char[100];
strcpy(p,"hello world");
}

void main(void)
{
char *str=NULL;
GetMemory(str);
cout<<str;
delete []str;
str=NULL;
}
當然了..喜歡下套的BaihowFF又給了錯程序....錯在哪呢?看上去是對的,而且編譯器編譯也正確啊..怎麼就是不能通過呢?而且還崩潰了...好費解吧...
其實原因很簡單...GetMemory這個函數出問題了!函數參數是不能傳遞分配空間的...因爲傳遞過去實際上是一個副本p...不能返回的...而且你在delete那就是件很危險的事情..因爲壓根沒有內容...那我實在想這樣用函數分配怎麼辦呢?像下面這樣改一下就ok了:
void GetMemory(char **p)   // 改成晦澀難懂的指針的指針
{
*p=new char[100];     //給*p的分配地址
strcpy(*p,"hello world");   // 拷貝內容到*p
}

void main(void)
{
char *str=NULL;
GetMemory(&str);    //這地方取地址
cout<<str;
delete []str;
str=NULL;
}
這樣就能正常工作了,但是看起來好彆扭啊...嗯..確實...但是還可以用其他方法哦....你想想...肯定有辦法的...

9.請時刻記住要初始化字符串

嗯...這點大家都知道...那你猜猜下面的程序結果是多少?
char a[10];
cout<<strlen(a)<<endl;
答案應該讓你以外...竟然是15...沒道理吧?!其實strlen函數的結果和是否初始化有關的...雖然你分配了空間..但是沒有初始化..庫函數會出錯的..sizeof不受影響...切忌初始化哦....

10.小括號,大區別

看看這兩端聲明,有什麼不同?我直接在註釋裏告訴你答案吧...這樣好看點...
char (*str)[20];    //str是一個數組指針,即指向數組的指針.
char *str[20];   //str是一個指針數組,其元素爲指針型數據.
千萬別小看括號哦...區別大了吧....

最後給個完整程序,想一下運行結果...分析在最後

 
  1. #include<iostream.h>
  2. #include <string.h>
  3. #include <malloc.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <memory.h>
  7.  
  8. typedef struct  AA
  9. {
  10. int b1:5;
  11. int b2:2;
  12. }AA;
  13.  
  14. void main()
  15. {
  16.     AA aa;
  17.     char cc[100];
  18.     strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
  19.     memcpy(&aa,cc,sizeof(AA));
  20.     cout << aa.b1 <<endl;
  21.     cout << aa.b2 <<endl;
  22. }
#include<iostream.h>#include <string.h>#include <malloc.h>#include <stdio.h>#include <stdlib.h>#include <memory.h>typedef struct  AA{int b1:5;int b2:2;}AA;void main(){	AA aa;	char cc[100];	strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");	memcpy(&aa,cc,sizeof(AA));	cout << aa.b1 <<endl;	cout << aa.b2 <<endl;}

答案:-16和1
首先sizeof(AA)的大小爲4,b1和b2分別佔5bit和2bit.經過strcpy和memcpy後,aa的4個字節所存放的值是: 0,1,2,3的ASC碼,即00110000,00110001,00110010,00110011所以,最後一步:顯示的是這4個字節的前5位,和 之後的2位分別爲:10000,和01,因爲int是有正負之分

發佈了9 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章