本節內容需要掌握記憶體分割槽的概念,可以參見:C程式的記憶體分割槽(節選自黑馬訓練營day1)
下面來看例程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define sTring "I like C!" //定義一個巨集字串
1 void locationOfString() //不同宣告形式下,字串的地址 2 { 3 char arrString[]="I am a freshman!"; //陣列形式宣告字串 4 char *p=arrString; //宣告指標指向上面字串 5 char*q="I am a freshman!"; 6 printf("字串本身的地址是: %p 字串的內容是: %s","I am a freshman!","I am a freshman!\n"); 7 printf("字串陣列的地址是: %p 字串陣列的內容是: %s\n",arrString,arrString); 8 printf("指向字串陣列的指標的地址是:%p 指向字串陣列的指標的內容是:%s\n",p,p); 9 printf("指向字串的指標的指向地址是:%p 指向字串的指標的內容是: %s\n\n",q,q); 10 }
程式執行後,輸出如下:
字串本身的地址是: 00405064 字串的內容是: I am a freshman!
字串陣列的地址是: 0060FEF7 字串陣列的內容是: I am a freshman!
指向字串陣列的指標的地址是:0060FEF7 指向字串陣列的指標的內容是:I am a freshman!
指向字串的指標的指向地址是:00405064 指向字串的指標的內容是: I am a freshman!
從上面程式執行的結果可以推斷出:
1、當程式設計者定義一個字串的時候,編譯器將字串存放在程式資料區(靜態儲存區)。
2、以陣列形式宣告的字串,字串本身在程式資料區(全域性區)。程式執行後,編譯器拷貝字串,並將其放在棧區,形成副本。
字串陣列的地址就是字串棧區副本的地址,該地址的記憶體隨著函式執行結束被釋放。
3、以指標形式宣告的字串,則在棧上沒有副本,指標指向字串本身在程式資料區的地址。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define sTring "I like C!" //定義一個巨集字串 5 6 void outputArrayString() 7 { 8 char arrString[]=sTring; 9 printf("陣列形式輸出字串陣列的第4個字元是: arrString[3]=%c \n",arrString[3]); 10 printf("指標形式輸出字串陣列的第4個字元是:*(arrString+3)=%c \n\n",*(arrString+3)); 11 printf("字串陣列的地址是 : arrString=%p \n",arrString); 12 printf("字串陣列的首地址是:&arrString[0]=%p \n",&arrString[0]); 13 printf("字串本身的首地址是: &sTring=%p \n",&sTring); 14 printf("字串本身的地址是 : sTring=%p \n\n",sTring); 15 } 16 void outputPointString() 17 { 18 char *p=sTring; 19 printf("陣列形式輸出字串陣列的第5個字元是: p[4]=%c \n",p[4]); 20 printf("指標形式輸出字串陣列的第5個字元是:*(p+4)=%c \n\n",*(p+4)); 21 }
通過outputArrayString和outputPointString例程的執行,我們可以看出:
1、只要將字串與陣列或者指標聯絡起來(以賦值的形式),我們就可以輸出字串中的字元。
2、無論是用陣列還是用指標與字串聯絡起來,在定位字串的位置,以輸出字串的某個字元時,
用指標偏移或者陣列偏移的形式都可以。這時,陣列形式和指標形式的定位是通用的,並且可以互換。
1 #define sTring "I like C!" 2 void editArrayString() 3 { 4 char arrString[] = sTring; 5 printf("陣列字串=%s 巨集字串=%s\n", arrString, sTring); 6 arrString[0] = 'W'; 7 printf("陣列字串=%s 巨集字串=%s\n", arrString, sTring); 8 *(arrString) = 'I'; 9 printf("陣列字串=%s 巨集字串=%s\n", arrString, sTring); 10 //++arrString='h'; 當程式執行到這條語句時,提示錯誤。 11 printf("陣列字串=%s 巨集字串=%s\n\n", arrString, sTring); 12 }
通過上面例程可以看出:
1、宣告一個陣列,並將其與巨集字串關聯後,字串陣列可以被修改。
2、被修改的僅僅是字串陣列,也就是巨集字串在棧上的副本,巨集字串本身並沒有改變。
3、字串的地址不能被修改,也就是說,字串陣列變數名不能做左值。
1 void editArrayString2() 2 { 3 char arrString[] = "I believe tomorrow to be a better day!"; 4 printf("程式資料區字串地址=%p\t", &("I believe tomorrow to be a better day!")); 5 printf("程式資料區字串=%s\n", *(&("I believe tomorrow to be a better day!"))); 6 printf("字串陣列地址 =%p \t 字串陣列 =%s\n", arrString, arrString); 7 arrString[0] = 'W'; 8 //*((char*)("I believe tomorrow to be a better day!")) = 'W'; 程式執行至此,系統報錯! 9 printf("程式資料區字串地址=%p\t", &("I believe tomorrow to be a better day!")); 10 printf("程式資料區字串=%s\n", *(&("I believe tomorrow to be a better day!"))); 11 printf("字串陣列地址 =%p \t 字串陣列 =%s \n\n", arrString, arrString); 12 }
通過上面例程可以看出:
1、宣告一個字串陣列後,編譯器在記憶體的程式資料區寫入一個字串常量。
2、宣告字串陣列的函式被呼叫後,編譯器在棧區寫入一個字串常量副本作為字串陣列。
3、字串陣列可以被修改,但被修改的僅僅是字串陣列,也就是字串在棧上的副本,
存放在程式資料區的字串常量並沒有改變。
4、字串本身不可以被修改,被當作常量處理。
1 void editPonintString() 2 { 3 char *p="persevere in!"; 4 printf("指標宣告字串=%s \n",p); 5 //*(p+1)='E'; //程式執行至此,系統報錯! 6 printf("指標宣告字串=%s \n",p); 7 p=p+2; 8 printf("指標宣告字串的第3個字元=%c \n",*(p)); 9 }
通過上面例程可以看出:
1、以指標形式宣告一個字串變數後,該字串不能被修改。
2、指標的地址可以被修改,也就是說,指標變數名能做左值。