动态扩展char数组超31字符出现副作用及代码崩溃原因咨询
我来帮你拆解这两个问题,结合你的代码和Valgrind检测结果逐一分析:
问题1:注释掉的*string[*used]=0的作用与段错误原因
代码原本的意图
这行代码是想给拼接后的字符串添加C语言字符串必需的'\0'终止符,这样后续用fprintf输出时,才能正确识别字符串的结束位置,避免读取越界的内存内容。
触发段错误的核心原因
问题出在C语言的运算符优先级上:数组下标[]的优先级高于解引用*,所以*string[*used]会被编译器解析为*(string[*used])。
string是char**类型(指向char*的指针),string[*used]相当于访问第*used个char*元素,但你的程序里string只指向了一个buffer指针(也就是只有string[0]是有效的)。- 当
*used大于0时,string[*used]就是在访问超出合法范围的内存地址,属于非法内存访问,直接触发段错误。
正确的写法
如果要实现添加终止符的功能,需要给*string加上括号,确保先解引用得到buffer的指针,再访问对应下标:
(*string)[*used] = 0;
问题2:字符总数超过31出现副作用的原因
先看你代码里的内存分配逻辑:
char *buffer=(char*) malloc(sizeof(char));
你只给buffer分配了1字节的内存,但后续每次调用add_to_string时,直接用memcpy往buffer + *used的位置写数据——这完全是在越界写入未分配的内存区域,属于C语言中的未定义行为。
- 当写入的字符较少时,可能刚好越界的内存还没被其他数据占用,程序看起来能“正常”运行;
- 当字符总数超过一定长度(比如31),越界写入会覆盖堆上的其他数据(比如
used变量的内容、malloc的元数据),甚至可能覆盖到栈上的缓存信息(比如fprintf的格式化字符串)。这就会导致程序出现各种奇怪的副作用,比如你看到的重复输出There are 14 argument(s) to process,本质就是内存被破坏后,fprintf读取到了错误的内容。
Valgrind的检测结果也直接点明了问题:
27291 Invalid write of size 1
27291 at 0x4C33B5B: memmove (vg_replace_strmem.c:1258)
27291 by 0x1088B2: add_to_string (tmp.c:9)
27291 Address 0x51f4091 is 0 bytes after a block of size 1 alloc'd
这段日志明确说明你在写入超出malloc分配的1字节内存之外的区域,属于非法操作。
简单修复思路
要解决这个问题,你需要在每次添加数据前检查当前buffer的容量是否足够,不够的话用realloc重新分配更大的内存(比如每次扩容为原来的2倍,或者预先计算所有参数的总长度一次性分配)。比如可以给add_to_string增加一个capacity参数跟踪当前buffer的容量,当*used + data_len >= capacity时,触发内存扩容。
内容的提问来源于stack exchange,提问作者Aethalides

