K&R C 5.2节getint示例非数字输入异常及逻辑缺陷问询
问题根因拆解
1. 非数字输入时输出乱码的直接原因
getint在遇到「非数字、非EOF、非正负号」的字符时,会直接执行ungetch(c)并返回0,整个流程完全没有修改指针pn指向的内存- 你定义的
array[SIZE]是栈上的局部数组,没有做初始化,内存里存的是栈帧残留的随机垃圾值 - 主循环的终止条件只判断了
getint(...) != EOF,只要返回值不是EOF就会执行后续的printf,直接把未初始化的垃圾值打印出来,就是你看到的那些毫无意义的大整数 - 哪怕你只输入了4个非数字字符,因为每次无效字符都会被压回输入缓冲,循环会跑满
SIZE=5次才会退出,刚好对应你测试时输出5个乱码值的现象
2. 循环逻辑不匹配函数返回语义的设计陷阱
K&R教材明确标注了getint的三类返回值语义:
- 返回正整数:成功读到合法数字,
*pn已经写入有效数值 - 返回0:遇到无法识别为数字的无效字符,
*pn没有被修改 - 返回EOF:输入流结束
但原示例的主循环完全没处理返回值为0的分支: - 因为返回0既不是EOF,循环不会终止,会一直跑满5次数组容量才退出
- 每次遇到无效字符,
getint会把这个字符压回输入缓冲,下一次循环又会读到同一个字符,再压回缓冲,短时间内就会把100大小的buf写满,甚至踩坏相邻内存 - 整个流程中无效字符从来没有被真正消费掉,只是在缓冲和函数调用之间来回传递
3. 合法数字场景能正常工作的原因
输入合法数字序列时,getint 会完整走到数字累加的流程:
- 对每个数字执行
*pn = 10 * *pn + (c - '0'),把转换后的整数写入*pn - 数字读完后,把紧跟的非数字分隔符(空格、换行)压回缓冲,返回这个分隔符的ASCII码(都是正整数)
- 全程不会走到返回0的分支,
array里的数值都是有效赋值,所以输出符合预期
可行的改进思路
- 主循环严格按照返回值做分支处理:
- 收到EOF直接终止读取流程
- 收到返回0时,不要读取当前下标的数组值,直接把压回缓冲的无效字符读出来丢弃(避免反复卡在同一个字符),同时把数组下标退一格,不占用数组的有效存储位置
- 收到正值返回时,确认已经成功写入整数,再推进下标、打印结果
- 给
array做初始化赋值(比如全部置0),即使遇到未写入的场景,也不会打印出无意义的乱码 - 给
ungetch增加边界检查,当sp达到BUFSIZE上限时直接报错,避免缓冲溢出踩坏内存
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

