二级指针是否比指针数组更灵活?指针数组栈溢出问题咨询
问题解答
错误原因分析
你的代码两处内存申请逻辑都存在越界问题,只是触发报错的时机不同:
- 二级指针
ppi部分:你仅为ppi申请了1个char*大小的堆空间,仅能合法访问下标0,后续访问ppi[1]、ppi[2]属于堆内存越界,属于C语言的未定义行为,没直接报错只是运行时巧合,不代表代码逻辑正确。 - 指针数组
pp部分:char *pp[1]是定义在栈上的固定长度数组,编译时就确定了只能容纳1个char*指针,仅能合法访问下标0。你对pp[1]、pp[2]的赋值操作直接越界覆盖了栈上的其他内存区域,触发了编译器内置的栈溢出保护机制,也就是你看到的stack smashing detected错误。
疑问解答
关于指针数组的扩容问题
指针数组本质就是固定长度的数组,其容纳元素的数量在定义时就已经确定,不存在“动态扩容”的能力。你之前用二级指针可以实现扩容,本质是你在堆上申请了连续的指针存储区域,可通过realloc调整这块堆区域的大小,和指针数组本身的特性完全不同。如果强行对固定长度的指针数组做“扩容”(也就是访问超出定义长度的下标),不管数组定义在栈、全局区还是堆上,都属于内存越界,必然会引发不可预期的问题。
关于全局变量能否解决问题
将指针数组定义为全局变量只能规避stack smashing detected的报错提示,不能解决根本问题。全局数组的长度同样是定义时固定的,越界访问只会把越界写入的区域从栈变成全局数据区,依然属于未定义行为,随时可能出现数据篡改、程序崩溃等问题。
正确实现方案
如果不想改变指针数组的使用习惯,可以选择两种方案:
- 提前确定最大需要存储的指针数量,直接定义对应长度的指针数组即可。比如你需要存3个字符串指针,直接定义
char *pp[3]即可,不管定义在栈上还是全局区都不会有越界问题。 - 使用堆上动态分配的二级指针,这种方案完全支持
ppi[0]、ppi[1]这类和指针数组完全一致的下标访问写法,需要扩容时调用realloc调整ppi指向的内存空间大小即可,既满足动态扩容需求,也符合你操作指针数组的习惯。
额外注意:你当前为每个字符串申请空间的逻辑
malloc(sizeof(char)+1)仅能存储长度为1的字符串(含结束符),如果后续要存储更长的字符串,需要对应调整申请的内存大小;所有通过malloc申请的空间,使用完毕后记得调用free释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user786
相关产品推荐
相关产品推荐

