二維字符數組和指針的相應問題研究
在嘗試用C語言實現廣度優先算法時,需要用到支持以二維字符數組為值的哈希表,於是我對自己前面實現的int型鍵值對的哈希表進行再加工,發現在定義二維字符數組和指針時遇到較大問題,特此記錄
shadowfish 2019/10/24
將已知的二維字符數組傳入以儲存
嘗試
一開始,我將待傳入的二維字符數組定義為
char a[][30]={"ABCD","EFDG","12122"};
此代碼創建了char類型3行30列 (3個字符串,每個字符串30個字節) 的二維數組。
接着,我嘗試用一個二級指針指向它
char **ap =a;
並讀取它的第一行字符串
printf("%s",*ap);
編譯,運行到printf("%s",*ap);
時報錯Segmentation fault
,即段錯誤
,訪問了不可訪問的內存。
原因
*ap
的值類型為char*
(指向char的指針) ,而它實際存儲的是char
型二維數組a
的第一行數據的值 (本質是int型數據) ,而不是指向a
的第一行數據的首地址。這就導致程序將int
型數據當作地址訪問,自然訪問了不可訪問的內存。
補充
char* p;
字符指針p
相當於一維字符數組名,printf("%s",p)
中p
指向字符數組首地址,配合"%s"
格式化輸出相當於從首地址開始逐個輸出各個字符,到"/0"
結束。
解決
既然出現問題的原因是*ap
指向了int
型數據,那么我們需要讓它指向真正的字符數組首地址。我們將待傳入的二維字符數組定義改為
char *a[30]={"ABCD","EFDG","12122"};
這種定義方式創建了長度為30
的字符型指針數組(char* []
),指針數組里的每個指針指向各個字符數組(字符串)的首地址。
char **ap =a;
用**ap
指向它后,*ap
(即ap[0]
)存儲的是字符型指針變量(char*
)的首地址。
printf("%s",*ap);
此時引用*ap
進行輸出,傳遞進的是指向a
第一行首地址的字符型指針(char*
)(等效於*a
或a[0]
),從而輸出了a
第一行的所有字符。
我制作了便於直觀理解的圖表:
技巧
定義變量時,調整*
的位置,可以更好地理解
char* a[30];
char* *ap;
若將表示字符型指針(char*
)的*
貼近char
,可以很清楚地看出,a[30]
是一個char*
類型的數組,即字符型指針數組;*ap
是一個char*
類型的指針,即指向字符型指針的指針。
延申思考
char *a[30]={"ABCD","EFDG","12122"};
char (*a)[30]={"ABCDEFDG12122"};
char *a={"ABCDEFDG12122"};
上述三種定義方式有很大的區別。
char *a[30]={"ABCD","EFDG","12122"};
創建了長度為30
的char
型指針數組,指針數組中的每個指針指向各個字符數組(字符串)的首地址;
char (*a)[30]={"ABCDEFDG12122"};
創建了指向一個長度為30
的 char
型數組的指針;
char *a={"ABCDEFDG12122"};
創建了指向"ABCDEFDG12122"
這個被隱式創建的字符數組的首地址的指針。
此處三種方式都為a
賦了初值。
char *a[30]={"ABCD","EFDG","12122"};
將指針數組里的前三個指針指向三個字符數組(字符串);
char (*a)[30]={"ABCDEFDG12122"};
初始化了被a
指向的字符數組的前面部分字節,它顯式創建了一個字符數組,a
被定義為一個指向長度為30
的字符數組的指針。VSCODE的調試器可以直接讀取a
指向該字符數組的所有元素值;
char *a={"ABCDEFDG12122"};
隱式創建了一個長度為14
的字符數組,a
被定義為指向這個字符數組首地址的指針,相當於
char b[]={"ABCDEFDG12122"};
char *a=b;
可以看出,顯式和隱式本質上都創建了一個字符數組,並令字符指針指向它的首地址。
不同在,顯式聲明時,VSCODE調試器可以實時獲取a
的下標0-29
的所有元素的值,即使隨后a
指向了長度小於或大於30
的字符數組,VSCODE調試器依然能且只能實時獲取a
下標0-29
的值;
隱式聲明時,VSCODE調試器只能顯示a
指向的字符數組首地址的字符值。
由此可以推斷,顯式和隱式聲明在底層的實現是等效的,區別是告訴調試器以不同的方式處理這個指針變量的值。
另:
第二種方式若像第一種方式一樣賦初值
char (*a)[30]={"ABCD","EFDG","12122"};
由於這只是一個一維字符數組,只會存儲"ABCD"
,后面的字符串不會被存儲。