使用malloc动态分配内存后字符数组输出少一个字符的原因
问题分析与解决方案
这个问题的核心原因并不是动态分配内存本身,而是输入缓冲区残留的换行符在搞鬼,刚好和动态分配的场景撞在一起让你误以为是内存分配的问题。让我一步步拆解:
为什么会少一个字符?
当你用 scanf("%d", &nchars) 输入数字(比如5)并按下回车后,输入缓冲区里实际是 5\n。%d 格式符只会读取数字部分,把换行符 \n 留在了缓冲区里。
接下来你循环用 scanf("%c", &arr[i]) 读取字符时,第一个 %c 会直接读取缓冲区里的 \n,而不是你手动输入的第一个字符。这就导致:
- 你以为输入了5个字符,但实际上第一个“字符”是换行符,剩下4个才是你真正输入的内容
- 输出时如果过滤掉不可见的换行符,就只会显示4个有效字符
至于你说“不采用动态分配就不会出现问题”,大概率是巧合——静态数组场景下你可能用了不同的输入方式(比如直接用 gets 或者提前处理了缓冲区),本质上静态数组也会遇到同样的缓冲区残留问题。
修复方案
有两种简单的方式解决这个问题:
方法1:读取数字后手动清空缓冲区的换行符
在 malloc 之后,用 getchar() 把残留的换行符读掉:
scanf("%d", &nchars); getchar(); // 吃掉缓冲区里的换行符 arr = (char*)malloc((nchars + 1) * sizeof(char));
方法2:在 %c 前加空格跳过空白字符
scanf 的格式符里,空格会自动跳过所有空白字符(包括换行、空格、制表符),所以把读取字符的代码改成:
for (int i = 0; i < nchars; i++) { scanf(" %c", &arr[i]); // 注意%c前面的空格 }
额外注意事项
- 内存分配的小细节:如果之后要把这个数组当作字符串(比如用
printf("%s", arr)输出),一定要多分配1个字节来存储字符串终止符\0,否则会出现未定义行为。 - 检查 malloc 是否成功:动态分配内存可能失败,一定要加判断:
if (arr == NULL) { printf("Memory allocation failed!\n"); return 1; } - 记得释放内存:动态分配的内存一定要用
free(arr)释放,避免内存泄漏。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> int main() { int nchars = 0; char* arr = NULL; printf("Enter number of characters you want in string: "); scanf("%d", &nchars); // 多分配1字节用于存储字符串终止符 arr = (char*)malloc((nchars + 1) * sizeof(char)); if (arr == NULL) { printf("Failed to allocate memory!\n"); return 1; } // 清空缓冲区的换行符 getchar(); printf("Enter %d characters: ", nchars); for (int i = 0; i < nchars; i++) { scanf("%c", &arr[i]); } // 添加字符串终止符 arr[nchars] = '\0'; // 输出结果 printf("You entered: %s\n", arr); printf("逐个输出字符:"); for (int i = 0; i < nchars; i++) { printf("%c ", arr[i]); } // 释放内存 free(arr); return 0; }
内容的提问来源于stack exchange,提问作者Ami
相关产品推荐
相关产品推荐

