如何让C语言scanf()函数忽略无效字符并避免程序异常运行?
问题原因
你遇到的重复打印问题本质是输入缓冲区残留+scanf类型匹配失败共同导致的:
- 当你给
%d格式的scanf输入字符时,scanf会匹配失败,返回0,且输入的错误字符不会被从输入缓冲区取走,一直留在缓冲区里 - 下次循环走到
scanf的时候,会直接读取缓冲区里残留的错误字符,再次匹配失败,进入无限循环,反复执行前面的printf语句
修复方案
1. 新增输入缓冲区清空函数
先在代码开头加一个清空输入缓冲区的工具函数,每次scanf调用后都执行清空,避免残留:
void limpiarBuffer() { while (getchar() != '\n'); }
2. 给数字类scanf增加读取成功校验
所有用%d的scanf都不要直接调用,要判断返回值是否为1(表示成功读取1个int值),如果失败就提示重新输入,同时清空缓冲区:
比如你原来读取产品ID的代码修改为:
do{ printf("Escriba la ID del producto: "); if(scanf("%d", &idprompt) != 1){ printf("输入错误,请输入数字!\n"); idprompt = 0; // 赋值为0触发范围校验不通过,继续循环 limpiarBuffer(); // 清空缓冲区残留的错误字符 } }while(0==rangoValido(1,1000,idprompt));
同理,后面读取收款金额的scanf("%d", &monto);也做同样的校验修改。
3. 字符类scanf的残留处理
你现在的%c前面加了空格已经可以跳过换行符,但是如果用户输入多个字符(比如输了yes而不是Y),还是会有残留,所以每次读取完字符之后也调用一次limpiarBuffer()清空多余的输入即可。
补充:你代码里另外3个隐藏bug
- 你定义的二维数组
int productoid[1000][1]和int listacompra[100][1]第二维长度是1,合法下标只能是0,但是你代码里写了productoid[idprompt][1]、listacompra[colector][1],属于数组越界,会导致内存篡改,把第二维长度改成2就行:int productoid[1000][2];、int listacompra[100][2]; - 变量
total定义的时候没有初始化,累加的时候会用垃圾值作为初始值,定义的时候改成int total = 0; - 你的折扣函数有整数除法问题:
descuento / 100两个都是int,比如25/100会得到0,最终折扣后价格是0,改成num * descuento / 100就行,先乘再除避免整数除法误差。
内容的提问来源于stack exchange,提问作者Groxil
相关产品推荐
相关产品推荐

