调用free后重新分配内存,char*为何输出垃圾值?
问题分析:分词程序释放内存后出现垃圾值的原因
问题重现
代码实现
#include <stdio.h> #include <stdlib.h> void tokenize(char *buffer, char** tokens, int n) { int tokens_index = 0; int curr_index = 0; for(int i = 0; i < n; i++) { if(buffer[i] != ' ' && buffer[i] != '\0') { tokens[tokens_index][curr_index] = buffer[i]; curr_index++; } else if(i != 0 && buffer[i] == ' ' && buffer[i-1] == ' ') { continue; } else if(buffer[i] == ' ') { curr_index = 0; tokens_index++; } else if(buffer[i] == '\0') { tokens_index++; tokens[tokens_index][0] == '\0'; break; } } } int main(int argc, char **argv) { char buffer[50]; while(fgets(buffer, 50, stdin)) { char **tokens = (char **) malloc(sizeof(char *) * 20); for(int i = 0; i < 20; i++) { tokens[i] = (char *) malloc(sizeof(char) * 50); } tokenize(buffer, tokens, 50); for(int i = 0; i < 20; i++) { if(*tokens[i] == '\0') { break; } printf("%s\n", tokens[i]); } for(int i = 0; i < 20; i++) { free(tokens[i]); } free(tokens); } return 0; }
测试输入
ab cd ef gh ij kl
异常输出
ab cd ef gh ij kl �� �� `�
问题核心:首次循环运行正常,后续循环释放内存后重新分配,输出出现垃圾值;移除free语句则运行正常。
问题根源
字符串未正确终止:
tokenize函数仅向tokens中写入字符,但未给每个分词添加C字符串必需的终止符'\0'。首次运行时,malloc分配的堆内存可能恰好初始化为全0,未被赋值的tokens元素开头是'\0',打印循环会正常终止。但释放内存后再次malloc,堆内存会残留之前的垃圾数据,未终止的分词会带上这些垃圾,未被赋值的tokens元素也不是以'\0'开头,导致printf输出乱码。赋值逻辑错误:在处理
'\0'的分支中,代码写成了tokens[tokens_index][0] == '\0';,这是比较操作而非赋值,完全起不到标记结束的作用。
修复方案
修正后的tokenize函数
void tokenize(char *buffer, char** tokens, int n) { int tokens_index = 0; int curr_index = 0; // 初始化第一个token的终止符,处理空输入边界 tokens[tokens_index][0] = '\0'; for(int i = 0; i < n; i++) { if(buffer[i] != ' ' && buffer[i] != '\0') { tokens[tokens_index][curr_index] = buffer[i]; curr_index++; // 实时添加终止符,确保字符串合法 tokens[tokens_index][curr_index] = '\0'; // 防止单个分词超出内存限制 if(curr_index >= 49) break; } else if(i != 0 && buffer[i] == ' ' && buffer[i-1] == ' ') { continue; } else if(buffer[i] == ' ') { // 给当前分词添加终止符 tokens[tokens_index][curr_index] = '\0'; curr_index = 0; tokens_index++; // 初始化下一个分词的终止符 tokens[tokens_index][0] = '\0'; } else if(buffer[i] == '\0') { // 给最后一个分词添加终止符 tokens[tokens_index][curr_index] = '\0'; tokens_index++; // 标记结束位置 tokens[tokens_index][0] = '\0'; break; } } }
关键修复点
- 每个分词在写入字符后立即添加
'\0',确保是合法的C字符串; - 切换分词时,先给当前分词加终止符,再初始化下一个分词的终止符;
- 修正了
==为=的赋值错误; - 增加了单个分词的长度限制,防止数组越界。
额外优化建议
- 无需预先分配20个分词,可以根据实际分词数量动态分配内存,减少浪费;
- 使用标准库函数
strtok或strsep可以简化分词逻辑,避免手动实现的潜在bug。
内容的提问来源于stack exchange,提问作者boring_pencil
相关产品推荐
相关产品推荐

