C语言scanf读取整数后无法读取字符运算符问题求解
问题描述
编写简易计算器程序时,核心运算逻辑已验证正确,但存在输入读取异常:按照「先读取两个整数、再读取字符类型运算符」的逻辑编写代码时,运算符无法正常读取;若调整输入读取顺序,改为「先读取字符类型运算符、再读取两个整数」,代码即可正常运行。
异常代码如下:
#include <stdio.h> #include <stdint.h> void add (unsigned int temp1, unsigned int temp0); void subtract (unsigned int temp1, unsigned int temp0); void multiply (unsigned int *temp); void divide (unsigned int *temp); int main() { unsigned int num[2]; char op; printf("Enter two numbers\n"); scanf("%u", &num[0]); scanf("%u", &num[1]); printf("Enter operation\n"); scanf("%c", &op); switch(op) { case '+': add(num[0],num[1]); break; case '-': subtract(num[0],num[1]); break; case '*': multiply(num); break; case '/': divide(num); break; default: printf("Invalid Operation"); break; } return 0; } void add (unsigned int temp1, unsigned int temp0) { printf("Sum of the numbers is: %u", temp1+temp0); } void multiply (unsigned int *temp) { printf("Product of the numbers is: %u", temp[0]*temp[1]); } void subtract (unsigned int temp1, unsigned int temp0) { if (temp1 > temp0) { printf("Difference of the numbers is: %u", temp1-temp0); } else { printf("Difference of the numbers is: %u", temp0-temp1); } } void divide (unsigned int *temp) { unsigned int quo; unsigned int rem; quo = temp[0]/temp[1]; rem = temp[0]%temp[1]; printf("Quotient of %u divided by %u is: %u\n", temp[0], temp[1], quo); printf("Remainder of %u divided by %u is: %u\n", temp[0], temp[1], rem); }
根本原因
异常来自C语言标准输入的行缓冲机制与scanf不同格式符的读取规则差异:
- 终端输入默认采用行缓冲模式,所有输入内容(包括输入的数字、输入完成后按下的回车对应的换行符
\n)会先暂存在输入缓冲区中,等待scanf按格式规则读取。 - 使用
%u格式符读取无符号整数时,scanf会自动跳过缓冲区开头的所有空白字符(空格、换行符、制表符均属于空白字符),从第一个非空白字符开始读取数字,直到碰到非数字字符才停止,将读取到的内容转换为整数存入对应变量;停止位置的非数字字符会残留在缓冲区中,不会被自动清除。 - 当代码读完第二个整数时,输入缓冲区中刚好残留着输入完第二个数字后按下的换行符
\n。接下来使用%c格式符读取字符时,%c的读取规则是不跳过任何字符,直接读取缓冲区当前位置的第一个字符,因此会直接把残留的换行符读入op变量,根本不会等待用户输入运算符,程序直接进入default分支输出非法操作提示。 - 调整为先读运算符再读整数时不会触发异常,是因为程序启动时输入缓冲区为空,
%c会正常等待用户输入;输入运算符后按下回车产生的残留换行符,会被后续两个%u格式符自动跳过,不会影响整数读取。
修复方法
两种常用修复方案任选其一即可:
- 在读取运算符的
scanf格式串中,%c前加一个空格,显式要求读取前跳过所有空白字符:// 原代码:scanf("%c", &op); scanf(" %c", &op);注意
%c前的空格不是多余写法,它会指示scanf在读取目标字符前,先跳过缓冲区中所有连续的空白字符,直到碰到第一个非空白字符再完成读取,刚好可以解决残留换行符被误读的问题。 - 读完两个整数后,手动清空输入缓冲区中到换行符为止的残留内容,再读取运算符:
scanf("%u", &num[0]); scanf("%u", &num[1]); // 新增:读走缓冲区中所有残留字符直到换行 while(getchar() != '\n'); printf("Enter operation\n"); scanf("%c", &op);
内容的提问来源于stack exchange,提问作者Karthick Duraisamy
相关产品推荐
相关产品推荐

