指標和陣列存在著一些本質的區別。當然,在某種情況下,比如陣列作為函式的引數進行傳遞時,由於該陣列自動退化為同型別的指標,所以在函式內部,作 為函式引數傳遞進來的指標與陣列確實具有一定的一致性,但這只是一種比較特殊的情況而已,在本質上,兩者是有區別的。請看以下的例子:
char a = "1234567";
char *p = "1234567";
上述兩個變數的記憶體布局分別如下:
陣列a需要在記憶體中占用8個位元組的空間,這段記憶體區通過名字a來標誌。指標p則需要4個位元組的空間來存放位址,這4個位元組用名字p來標誌。其中存放的位址幾乎可以指向任何地方,也可以**都不指,即空指標。目前這個p指向某地連續的8個位元組,即字串"1234567"。
另外,例 如:對於a[2]和p[2],二者都返回字元『i』,但是編譯器產生的執行**卻不一樣。對於a[2],執行**是從a的位置開始,向後移動2兩個位元組, 然後取出其中的字元。對於p[2],執行**是從p的位置取出乙個位址,在其上加2,然後取出對應記憶體中的字元。
p指標變數本身在棧上,指向的內容在靜態儲存區;
a只是個陣列名,本身不佔執行時程式的空間,只是在源程式中用來標記乙個字元陣列(即其首位址),而陣列也是儲存在棧上的。
char s1 = "a";
char *s2 = "b";
a是在執行時刻賦值的;
而b是在編譯時就確定的;
但是,在以後的訪問中,在棧上的陣列比指標所指向的字串(例如堆)快。
比如:int main()
char a = 1;
char c = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return 0;
對應的彙編**
10: a = c[1];
00401067 8a 4d f1 mov cl,byte ptr [ebp-0fh]
0040106a 88 4d fc mov byte ptr [ebp-4],cl
11: a = p[1];
0040106d 8b 55 ec mov edx,dword ptr [ebp-14h]
00401070 8a 42 01 mov al,byte ptr [edx+1]
00401073 88 45 fc mov byte ptr [ebp-4],al
第一種在讀取時直接就把字串中的元素讀到暫存器cl中,而第二種則要先把指標值讀到edx中,在根據edx讀取字元,顯然慢了。
#include
#include
char *function1()
char *function2()
char a="cdefgh";
/*這個是常量字串的拷貝,
相當於strcpy(a,"cdefgh"),
這樣寫都會有字串拷貝,
造成時間和空間上的開銷,
如果字串很長盡量不要這樣寫,
由於字元陣列a在棧上,
所以在函式結束後它便無效了..
---------------
char *a="cdefgh";
a直接指向常量字串,
這個字串儲存在靜態儲存區中...
所以在函式結束後,它返回的位址仍然有效..
*/int main()
/*(1)function1()的a和function2()的a都是自動變數,都在棧上分配空間
(2)function1()的a分配的空間=sizeof(char *)=sizeof(void *),
任何指標的大小都是相同的,指向靜態資料區存的"cdefgh"
(3)function2()的a分配的空間=strlen("cdefgh")+1,並且用來儲存"cdefgh"
(4)返回的指標,function1指向靜態資料區,function1指向棧(已自動釋放)
故function1的值是對的
*/(1)指標陣列: 是陣列,但陣列中的每個元素都是指標
int *p[5];//如p[2]是指標,可*p[ 2]=3;
(2)指向陣列的指標: 是個指標,但它指向的是乙個陣列
int a[5];
int (*p)[5];//與前一行比較,*p相當於a,即p=&a;就像:int m;int *pm;//*pm就相當於m.pm=&m;
p= &a;//可與前一行合併為int (*p)[5]=&a;
----------------------
a代表這個陣列,它是乙個指標,指向第乙個元素
這裡一定要記住,a是陣列名,&a代表的不是取a這個變數的位址,而是取陣列元素的位址
---------------------------------------
a 的型別是 int[5] 陣列
&a 的型別是 int(*)[5] 指標——指向int[5]陣列的指標
&a[0] 的型別是 int * 指標——指向int型別的指標。
sizeof(a)=20;
sizeof(*a)=4 =sizeof(a[0]);
sizeof(*&a)=20;//因為p=&a,所以=sizeof(*p),而*p=a,所以=sizeof(a)=20;
---------------------------------------
int a[5]=;
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));//輸出:2,5
*pc與int
*pi,sizeof(pc)=sizeof(pi)=4,但為什麼輸出時,cout<<*pc只從記憶體處取乙個字元,而cout<&
lt;*pi則從記憶體處取4個字元,這是由指標型別(char,int)決定的.對a* p;p+1=(a*)(p的位址值+sizeof(a)),如pc+1=pc+sizeof(char)=(char*)(pc的位址值+1個位元組),而pi+1=pc+sizeof(int)=(int*)(pi的位址值+4個位元組).
對**中的&a+1,&a是陣列指標,其型別為int
(*)[5],因為p=&a,也即是p的型別.所以&a+1=&a+sizeof(a),其中a為int[5]:(把
a=int[5]代入a*
a[5]),&a+1仍是int (*)[5]型別,經(int
*)(&a+1)強制轉化為int*,賦值給ptr.後面的ptr-1=ptr-sizeof(int)=ptr的位址值-4個位元組,即變為陣列
a的最後乙個元素的位址&a[4],*(ptr-1)即為a[4],故輸出為5.
而a+1=a+sizeof(int):(此處a退化為int*,故對於a* p,a為int)=a的位址值+4個位元組,即是&a[1],則*(a+1)即a[1],故輸出2.
又如:double t= ;
double *pt= &t[3];//指向值為111
int *ptint= reinterpret_cast< int * > (pt);
char *ptch= reinterpret_cast< char * > (pt);
cout<< *( pt- 1)<< "\t"<< *(reinterpret_cast(ptint-2))<<"\t"<<
*(reinterpret_cast(ptch-8));//最後輸出結果全為578
---------------------
void fun( int *p)與void fun( int p)是一樣的,即函式列表中的陣列此時退化成了指標
char a 和char a 的區別
char a hello 中的a是指向第乙個字元 a 的乙個指標 char a 20 hello 中陣列名a也是執行陣列第乙個字元 h 的指標 但二者並不相同 看例項 把兩個字串相加 結果 對比 結果 把字串加到指標所指的字串上去,出現段錯誤,本質原因 d 0123456789 存放在常量區,是無法...
char a 和char a 的不同
char a dghtql 中的a是乙個常量指標,指向 dghtql 這個字串,並且不能通過操作指標a來改變 dghtql 存放於常量區,只能通過指標來訪問,不能通過指標來修改和賦值。如scanf 等方法不能用於a上。而char a dghtql 中的a既是陣列名又是指向第乙個字母d的指標,陣列是存...
char a 與char a 的區別
char a hello 中的a是指向第乙個字元 a 的乙個指標 char a 20 hello 中陣列名a也是執行陣列第乙個字元 h 的指標 但二者並不相同 看例項 把兩個字串相加 結果 對比 結果 把字串加到指標所指的字串上去,出現段錯誤,本質原因 d 0123456789 存放在常量區,是無法...