C++/C程序中,指針和數組在不少地方可以相互替換著用,讓人產生一種錯覺,以為兩者是等價的。
數組要麼在靜態存儲區被創建(如全局數組),要麼在棧上被創建。數組名對應著(而不是指向)一塊內存,其地址與容量在生命期內保持不變,只有數組的內容可以改變。
指針可以隨時指向任意類型的內存塊,它的特征是“可變”,所以我們常用指針來操作動態內存。指針遠比數組靈活,但也更危險。
下面以字符串為例比較指針與數組的特性。
1 修改內容
示例1中,字符數組a的容量是6個字符,其內容為hello\0。a的內容可以改變,如a[0]= ‘X’。指針p指向常量字符串“world”(位於靜態存儲區,內容為world\0),常量字符串的內容是不可以被修改的。從語法上看,編譯器並不覺得語句p[0]= ‘X’有什麼不妥,但是該語句企圖修改常量字符串的內容而導致運行錯誤。
char a[] = “hello”;
a[0] = ‘X’;
cout << a << endl;
char *p = “world”; // 注意p指向常量字符串
p[0] = ‘X’; // 編譯器不能發現該錯誤
cout << p << endl;
示例1 修改數組和指針的內容
2 內容復制與比較
不能對數組名進行直接復制與比較。示例2中,若想把數組a的內容復制給數組b,不能用語句 b = a ,否則將產生編譯錯誤。應該用標准庫函數strcpy進行復制。同理,比較b和a的內容是否相同,不能用if(b==a) 來判斷,應該用標准庫函數strcmp進行比較。
語句p = a 並不能把a的內容復制指針p,而是把a的地址賦給了p。要想復制a的內容,可以先用庫函數malloc為p申請一塊容量為strlen(a)+1個字符的內存,再用strcpy進行字符串復制。同理,語句if(p==a) 比較的不是內容而是地址,應該用庫函數strcmp來比較。
// 數組…
char a[] = "hello";
char b[10];
strcpy(b, a); // 不能用 b = a;
if(strcmp(b, a) == 0) // 不能用 if (b == a)
…
// 指針…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p,a); // 不要用 p = a;
if(strcmp(p, a) == 0) // 不要用 if (p == a)
…
示例2 數組和指針的內容復制與比較
3 計算內存容量
用運算符sizeof可以計算出數組的容量(字節數)。示例3(a)中,sizeof(a)的值是12(注意別忘了’\0’)。指針p指向a,但是sizeof(p)的值卻是4。這是因為sizeof(p)得到的是一個指針變量的字節數,相當於sizeof(char*),而不是p所指的內存容量。C++/C語言沒有辦法知道指針所指的內存容量,除非在申請內存時記住它。
注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。示例3(b)中,不論數組a的容量是多少,sizeof(a)始終等於sizeof(char *)。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12字節
cout<< sizeof(p) << endl; // 4字節
示例3(a) 計算數組和指針的內存容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4字節而不是100字節
}
示例3(b) 數組退化為指針
---------------------------------
1. 字符串宏 #define CONST_STR "const str" 宏在預編譯的時候會替換成實際的值
2.數組 數組名對應一塊內存,在生命周期內其地址和容量不會改變,數組裡面的內容可以變。
3.指針 指針指向一塊內存,如果指向字符串常量(RO),則不能修改內容。 如果申請了一塊內存,復制字符串常量,則可以修改內容