如何正确为存储不同长度字符串的char指针数组分配内存并修复realloc报错
问题核心原因
你代码里的所有问题都来自同一个错误用法:用sizeof获取指针指向的动态分配内存块的大小。
sequences[i]是char*类型的指针,在64位操作系统下,所有指针的占用内存大小都是固定的8字节,和它指向的内存块实际分配了多少空间完全无关。
所以你遇到的两个异常现象直接原因都是这个:
- 你判断
counter == sizeof(sequences[num_of_seq]),只要counter到8就会触发重分配逻辑,这就是字符串长度不到10就进realloc分支的原因。 - 你调用
realloc时传的大小是sizeof(sequences[num_of_seq])*2,第一次重分配直接把原本malloc(MIN_BUFFER)申请的1000字节内存块缩容到了16字节,后续写入内容超过16字节就会发生越界,这就是valgrind报Address 0x4a5b810 is 0 bytes after a block of size 16 alloc'd的根源。
修复方案
你需要单独维护每个字符串的当前分配容量,不能依赖sizeof计算:
- 新增一个数组存储每个序列的分配容量,初始化时赋值为
MIN_BUFFER - 扩容判断、realloc传参都用这个存储的容量值,扩容成功后更新容量值
修复后的代码示例
#define NUM_SEQ 4 #define MIN_BUFFER 1000 #define MAX_BUFFER 10000 char** read_the_file(char* file_name) { // 打开文件逻辑省略 char** sequences = malloc(NUM_SEQ*sizeof(char*)); // 新增容量数组,维护每个序列的已分配大小 size_t seq_cap[NUM_SEQ]; for (int i = 0; i < NUM_SEQ; i++) { sequences[i] = malloc(MIN_BUFFER); seq_cap[i] = MIN_BUFFER; } int num_of_seq = 0; int counter = 0; // 循环逻辑省略 // 扩容判断用存储的容量,注意要留1字节存字符串终止符'\0' if (counter + 1 >= seq_cap[num_of_seq]) { if (seq_cap[num_of_seq] * 2 < MAX_BUFFER) { size_t new_cap = seq_cap[num_of_seq] * 2; char* temp = realloc(sequences[num_of_seq], new_cap); if (temp != NULL) { sequences[num_of_seq] = temp; seq_cap[num_of_seq] = new_cap; } else { printf("内存分配失败\n"); exit(EXIT_FAILURE); } } else { printf("序列过长\n"); exit(EXIT_FAILURE); } } // 其他逻辑省略 return sequences; }
额外注意项
- 打印
size_t类型的变量要使用%zu格式符,不要用%ld,避免不同平台下的格式匹配错误 - 如果你需要把sequences返回给外部调用方使用,最好同时把
seq_cap或者每个字符串的长度也返回给调用方,避免调用方也出现类似的长度计算错误 - 写入字符串时要确保最后留有1字节存储'\0'终止符,否则后续使用字符串函数时也会出现越界问题
内容的提问来源于stack exchange,提问作者Funny
相关产品推荐
相关产品推荐

