C语言中int与size_t初始化数组的差异及缓冲区异常问题
C90缓冲输入程序的垃圾数据问题
原程序(符合C90标准)
#include <stdio.h> #include <stdlib.h> #define MAXLINE 10 int getLine(char s[]) { int ch; int chCount; for (chCount = 0; (ch = getchar()) != '\n' && ch != EOF; ++chCount) { if (chCount > MAXLINE) { puts("Interrupted read"); break; } s[chCount] = ch; } return chCount; } int main(int argc, char *argv[]) { char buf[MAXLINE]; int count; while (1) { count = getLine(buf); printf("%s: %d\n", buf, count); } return EXIT_SUCCESS; }
测试输入与异常输出
测试输入:one two three
输出结果:
> one two three Interrupted read one two thr�#��6@&'o�: 11 ene two thr�#��6@&'o�: 1
输出中出现�#��6@&'o�这类垃圾数据,后续输出也存在异常。
修改后的程序(仅调整缓冲区大小的类型)
int main(int argc, char *argv[]) { size_t size = MAXLINE; char buf[size]; // 其余代码与原程序一致 ... }
修改后测试输入one two three的输出:
> one two three Interrupted read one two thr: 11 ene two thr: 1
垃圾数据消失,输出恢复正常。
疑问与解答
1. 用固定大小说明符初始化的数组初始是否真的会填充垃圾数据?
是的。C语言中,函数内声明的自动存储期数组(如char buf[MAXLINE])若未显式初始化,其元素值为未定义状态,也就是所谓的“垃圾数据”——这些值是内存空间之前被使用后遗留的随机数据。只有加static修饰的静态存储期数组,才会被默认初始化为0。
2. 为何数组中的垃圾数据超过其用int声明的大小?
问题核心并非数组内的垃圾数据超出大小,而是printf("%s", buf)的行为要求传入以'\0'结尾的字符串,但你的程序从未给buf添加终止符:
buf大小为10,当读取到第11个字符时触发中断,此时buf的10个位置已被填满,没有多余空间存放'\0'。printf会从buf的起始地址持续读取,直到遇到'\0'为止,这会越界读取数组后方的内存区域,这些区域的随机数据被当成字符串的一部分,看起来像是“垃圾数据超过数组大小”。
3. 输出长度为21字符(缓冲区长度的2倍加1)是否具有特殊意义?
没有特殊意义,这只是随机巧合。越界读取的内存长度完全取决于后续内存中第一个'\0'的位置,不同平台、不同运行环境下这个长度都可能不同,21只是当前运行时的偶然结果。
4. 仅将数组大小的类型从int改为size_t为何能完全解决问题?
这是未定义行为的偶然表现,修改数组大小的类型并没有直接修复问题,只是你的编译器在处理size_t类型的变长数组(VLA,注意C90标准本身不支持VLA,这是C99引入的特性,你的编译器可能是在扩展模式下支持)时,恰好调整了栈布局,使得buf后方的内存区域存在'\0',或者越界读取的部分刚好是可打印的正常内容。
真正的修复方案应该是:
- 给数组预留一个字节存放终止符,比如将
MAXLINE对应的数组大小设为MAXLINE+1; - 在
getLine函数中,无论读取多少字符,最后都要给数组添加'\0'终止符,同时确保写入字符时不越界。
示例修改后的getLine函数:
int getLine(char s[], int maxSize) { int ch; int chCount = 0; // 留一个位置给终止符,避免越界 while ((ch = getchar()) != '\n' && ch != EOF && chCount < maxSize - 1) { s[chCount++] = ch; } s[chCount] = '\0'; // 添加字符串终止符 // 可选:丢弃剩余输入,避免影响下一次读取 if (ch != '\n' && ch != EOF) { puts("Interrupted read"); while ((ch = getchar()) != '\n' && ch != EOF); } return chCount; }
内容的提问来源于stack exchange,提问作者A. P. Roblem
相关产品推荐
相关产品推荐

