二维字符数组和指针的相应问题研究

二维字符数组和指针的相应问题研究

在尝试用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*)(等效于*aa[0]),从而输出了a第一行的所有字符。

我制作了便于直观理解的图表:
二维字符数组和指针的相应问题研究.jpg

技巧

定义变量时,调整*的位置,可以更好地理解
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"};创建了长度为30char型指针数组,指针数组中的每个指针指向各个字符数组(字符串)的首地址;
char (*a)[30]={"ABCDEFDG12122"};创建了指向一个长度为30char型数组的指针;
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",后面的字符串不会被存储。


posted @ 2019-10-28 09:25  shadowfish0  阅读(2450)  评论(0编辑  收藏  举报