字串的陣列形式和指標形式宣告及其區別 整理版(摘自《C Primer Plus 中文版第六版》第11章及黑馬程式設計師2018C語言提高深入淺出ch1-5 )

大老菜發表於2019-06-21

本節內容需要掌握記憶體分割槽的概念,可以參見: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、指標的地址可以被修改,也就是說,指標變數名能做左值。

相關文章