二维字符数组和指针的相应问题研究
二维字符数组和指针的相应问题研究
在尝试用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"
,后面的字符串不会被存储。