如何在C语言中为字符串无冗余动态分配内存?代码输出null的问题排查
代码存在的核心问题
- 值传递导致指针修改完全失效:C语言函数参数默认是值拷贝传递,把
user_input传入strmalloc时,函数内部拿到的string只是和user_input初始值(NULL)相同的临时副本——对这个副本的所有赋值操作,都不会影响main函数里的user_input本身。更关键的是strmalloc虽然设计了返回值,但main函数调用时压根没有接收这个返回值,导致user_input从头到尾都是初始的NULL,打印时自然输出(null)。哪怕user_input是全局变量,形参和原变量也是内存里完全独立的存储单元,这种修改根本传不回去。 - 缺少字符串终止符:就算解决了指针传值的问题,循环把用户输入的可读字符全部存入缓冲区后,没有补上C字符串强制要求的
\0结束标记,直接用printf("%s")打印会触发内存越界读取,轻则输出乱码,重则直接程序崩溃。 - 逐字节扩容的效率损耗:每读一个字符就调用一次
realloc把内存扩大1字节,会频繁触发内存块拷贝、地址迁移,开销极高。这种方式虽然最终能让内存大小和输入长度刚好匹配,但中间过程的性能损耗完全没有必要。
正确的实现方案
要实现动态分配无冗余空间的输入字符串,需要对齐三个核心要求:
- 保证动态分配后的内存地址能被外部正确拿到,要么通过函数返回值传递,要么传入二级指针修改原指针的值。
- 输入读取完成后必须在字符串末尾补
\0终止符,符合C语言字符串的格式要求。 - 调整扩容策略为固定步长或倍数增长减少系统调用次数,最后通过一次
realloc裁剪掉多余的预分配空间,实现零冗余的最终效果。
参考修正代码:
#include <stdio.h> #include <stdlib.h> char *read_dynamic_string(void); int main(void) { printf("Enter a sentence to find out the number of words: "); char *user_input = read_dynamic_string(); if (user_input == NULL) { printf("Memory allocation failed, exit.\n"); return 1; } printf("You entered: %s\n", user_input); free(user_input); // 动态内存使用完毕必须释放,避免内存泄漏 return 0; } char *read_dynamic_string(void) { char *string = NULL; size_t capacity = 0, length = 0; const size_t expand_step = 4; // 每次预分配4字节,降低realloc调用频率 int ch; while ((ch = getchar()) != '\n' && ch != EOF) { // 已用长度等于当前容量时触发扩容 if (length == capacity) { capacity += expand_step; char *tmp = realloc(string, capacity); if (!tmp) { free(string); return NULL; } string = tmp; } string[length++] = ch; } // 非空输入才处理 if (string != NULL) { // 补字符串终止符 string[length] = '\0'; // 裁剪多余预分配空间,实现无冗余分配 char *trimmed = realloc(string, length + 1); if (trimmed != NULL) { string = trimmed; } } return string; }
这种实现既避免了逐字节扩容的低效率,最终通过裁剪保证了分配的内存大小刚好等于输入字符串的实际长度(含终止符),没有冗余空间,也完全符合C语言的字符串格式要求。
内容的提问来源于stack exchange,提问作者Matthew Schell
相关产品推荐
相关产品推荐

