C语言scanf读取输入时i、n字符被异常存为换行符问题咨询
问题描述
- 预期功能:实现用户输入
end时程序自动终止的逻辑 - 代码设计逻辑:读取输入时,数值存入
firstArray.content[index],非数字字符存入end[whileCounter] - 异常表现:绝大多数场景逻辑运行正常,仅当
end接收字符i或n时触发异常:对应位置会被存入换行符'\n',而非用户实际输入的i或n字符 - 复现特征:输入
4lol时程序运行完全符合预期,但输入4null时,字符数组中仅存入ull,开头的n字符丢失 - 已排除项:该问题不是scanf常见的尾随换行符残留问题,因为异常仅在输入特定字符时触发
可复现异常的完整代码如下:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> struct HeapArrRealNums { size_t size; size_t nextIndex; size_t currentIndex; double* content; }; int main() { struct HeapArrRealNums firstArray = { 0 }; firstArray.size = 4; firstArray.nextIndex = 1; firstArray.currentIndex = 0; firstArray.content = malloc(firstArray.size * sizeof(double)); #define NOT_A_NUMBER 0 int scanCheck; size_t index = firstArray.currentIndex; char end[6] = { 'c' }; size_t whileCounter = 0; while ((scanCheck = scanf("%lf", &firstArray.content[index])) != 1) { if (scanCheck == EOF) { printf("\n----EOF. Program terminated----"); firstArray.currentIndex = index; //return true; } if (scanCheck == NOT_A_NUMBER) { (void)scanf("%c", &end[whileCounter]); whileCounter++; printf("-%s-", end); //continue; } } }
异常根因
问题出在对scanf("%lf")匹配规则的认知偏差:%lf读取双精度浮点数时,并非遇到非数字字符就立刻停止、完全不消费缓冲区内容。
除了普通数字、小数点、正负号、科学计数法的e/E之外,%lf还会尝试匹配C标准定义的特殊浮点值字面量:
- 以
n开头的nan/nan(...)(表示非数值) - 以
i开头的inf/infinity(表示无穷大)
当输入流中出现n或i开头的内容时,scanf会先将开头的n/i从输入缓冲区读走,继续向后读取字符尝试拼接成完整的特殊浮点值;如果后续字符不符合nan/inf的格式要求,scanf会判定匹配失败、返回0,但按照C语言标准,scanf匹配失败时最多只会向输入流回推1个字符——也就是最后读到的那个不匹配的字符,之前已经读走的首字符n/i会被直接丢弃,不会放回缓冲区。
这完全对应观察到的所有异常现象:
- 输入
i后按回车:scanf读走i,读到后续的换行符时发现无法凑成合法的inf格式,匹配失败,仅把换行符推回缓冲区,后续scanf("%c")读到的就是这个换行符,表现为i的位置被存入了'\n' - 输入
4null时,开头的数字4会被正常解析为浮点数存入数组,缓冲区剩余null,scanf读走首字符n,读到后续的u时发现无法凑成合法的nan格式,匹配失败,仅把u推回缓冲区,后续逐字符读取时只能读到u、l、l,开头的n直接丢失 - 输入
4lol时,开头的数字4被正常解析后,缓冲区剩余lol,scanf读到第一个字符l就发现完全不可能匹配浮点数格式,会直接把l推回缓冲区,不会消费任何字符,因此逐字符读取逻辑完全正常,这也是其他场景看起来运行符合预期的原因。
内容的提问来源于stack exchange,提问作者SarcasticLeo
相关产品推荐
相关产品推荐

