Malloc分配内存异常:硬编码分配2字符却仅分配1字符致段错误
问题:字符串追加函数的段错误与内存分配异常
我实现了一个appendCharacterToString函数,接收char数组指针string(按引用传递)、char类型字符character(按值传递)、unsigned short int类型变量length(按引用传递)。函数逻辑为:若string已分配内存,则重新分配为(*length + 2)*sizeof(char)大小,将length加1,最后两个字符分别设为character和空终止符;若string未分配,则分配2*sizeof(char)大小的内存,再初始化字符。但设置索引为length的最后一个字符时发生段错误。
原函数代码
void appendCharacterToString(char** string, char character, unsigned short int * length) { if (*string != NULL) { *string = (char* ) realloc(*string, (*length + 2) * sizeof(char)); ++*length; } else { *string = (char* ) malloc(2 * sizeof(char)); *length = 1; } *string[*length - 1] = character; *string[*length] = 0; }
调试信息
通过gdb调试发现,尽管硬编码分配2个char大小的内存,但初始分配的数组仅能访问1个char,设置第二个位置时触发段错误:
Program received signal SIGSEGV, Segmentation fault. appendCharacterToString (string=0x7fffffffe0d8, character=110 'n', length=0x7fffffffe0d0) at hangmanstringutils.c:24 24 *string[*length] = 0; (gdb) (gdb) print string $1 = (char **) 0x7fffffffe0d8 (gdb) print *string $2 = 0x5555555592a0 "n" (gdb) print *length $3 = 1 (gdb) continue Continuing. Program terminated with signal SIGSEGV, Segmentation fault. The program no longer exists. (gdb) break hangmanstringutils.c:12 Breakpoint 1 at 0x555555555612: file hangmanstringutils.c, line 14. (gdb) run Starting program: /home/joseph/code/hangman/hangman [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". Breakpoint 1, appendCharacterToString ( string=0x7fffffffe0d8, character=110 'n', length=0x7fffffffe0d0) at hangmanstringutils.c:14 14 if (*string != NULL) { (gdb) print *string $4 = 0x0 (gdb) print *length $5 = 0 (gdb) break 19 Breakpoint 2 at 0x55555555565a: file hangmanstringutils.c, line 19. (gdb) continue Continuing. Breakpoint 2, appendCharacterToString ( string=0x7fffffffe0d8, character=110 'n', length=0x7fffffffe0d0) at hangmanstringutils.c:19 19 *string = (char* ) malloc(2 * sizeof(char)); (gdb) print *string $6 = 0x0 (gdb) print *length $7 = 0 (gdb) break 21 Breakpoint 3 at 0x555555555677: file hangmanstringutils.c, line 23. (gdb) continue Continuing. Breakpoint 3, appendCharacterToString ( string=0x7fffffffe0d8, character=110 'n', length=0x7fffffffe0d0) at hangmanstringutils.c:23 23 *string[*length - 1] = character; (gdb) print *string $8 = 0x5555555592a0 "" (gdb) print *length $9 = 1 (gdb) print *string[0] $10 = 0 '\000' (gdb) print *string[1] Cannot access memory at address 0x2c0 (gdb)
解决方案
错误根源:运算符优先级问题
C语言中,数组下标运算符[]的优先级高于解引用运算符*,所以*string[*length]会被解析为*(string[*length])——这相当于把二级指针string当成数组,直接访问它的第*length个元素(一个char*指针),再解引用这个指针,完全偏离了操作字符数组的预期逻辑。
正确写法应为(*string)[index]:先解引用二级指针string得到指向字符数组的一级指针,再用下标访问数组元素。
额外优化:内存分配失败检查
malloc和realloc可能分配失败返回NULL,若不检查会触发未定义行为,建议添加检查逻辑避免内存泄漏或非法访问。
修复后的代码
#include <stdlib.h> // 确保malloc/realloc的头文件被包含 void appendCharacterToString(char** string, char character, unsigned short int * length) { if (*string != NULL) { // 用临时变量接收realloc返回值,避免分配失败时丢失原指针 char* temp = realloc(*string, (*length + 2) * sizeof(char)); if (temp == NULL) { return; // 分配失败直接返回 } *string = temp; ++*length; } else { *string = malloc(2 * sizeof(char)); if (*string == NULL) { return; // 分配失败直接返回 } *length = 1; } // 修正运算符优先级,正确访问字符数组 (*string)[*length - 1] = character; (*string)[*length] = '\0'; }
关键修改点说明
- 修正运算符优先级:将
*string[index]改为(*string)[index],确保操作目标是字符数组而非二级指针数组。 - 安全使用realloc:先用临时变量接收返回值,避免分配失败时原指针被覆盖为
NULL导致内存泄漏。 - 添加分配失败检查:若
malloc或realloc返回NULL,直接终止函数,避免后续非法内存访问。 - 明确空终止符:用
'\0'替代0,更清晰表明是字符串终止符(两者功能等价,但可读性更强)。
内容的提问来源于stack exchange,提问作者Joseph Latvala
相关产品推荐
相关产品推荐

