getchar 和 scanf 缓冲区问题。 getchar 没有存储正确的值
getchar and scanf buffer issues. getchar not storing the correct value
我是编程新手,我知道 scanf() 有一些怪癖。也就是说,当它检测到与其转换说明符不匹配的字符时,它会立即 returns 并将有问题的字符放回缓冲区中,以便由另一个 scanf() 调用或其他一些函数读取可以访问缓冲区。
但是,我正在做书本练习,代码行为很奇怪。
float total = 0, operand = 0;
char operator = 0;
printf("Enter an expression: ");
scanf("%f ", &total);
while ((operator = getchar()) != '\n') {
scanf("%f", &operand);
switch (operator) {
case '+':
total += operand;
break;
case '-':
total -= operand;
break;
case '*':
total *= operand;
break;
case '/':
total /= operand;
break;
}
printf("Value of operator: %c\n", operator);
printf("Operand: %f\n", operand);
}
printf("Value of expression: %f\n", total);
两次 printf 调用用于测试。输入:“1 + 5 + 9\n”导致:
Value of operator: +
Operand: 5.000000
Value of operator:
Operand: 5.000000
Value of operator:
Operand: 9.000000
Value of expression: 6.000000
所以,程序似乎是这样的:
scanf() 将 1 读入 'total',将其后的 space 与格式字符串中的 space 配对,遇到 '+',然后将其放回缓冲区并 returns.
然后:
循环 1 - getchar() 读取剩余的“+”并将其放入 'operator'。 scanf() 读取 5,遇到 space,将其放回缓冲区,然后 returns.
循环 2 - getchar() 读取剩余的 ' ',并将其放入 'operator' scanf() 遇到 '+' 并立即 returns 并将其放回缓冲区。
这里的内容与我的理解不符。在循环 3 开始时,getchar() 应该遇到 '+' 并将其存储到 'operator' 中。相反,它被完全跳过了,对我来说毫无意义。
此处跳过空格:while ((operator = nextchar()) != '\n')
而不是 getchar()
其中 nextchar()
可以是
int nextchar(void) {
int ch;
do ch = getchar(); while (ch == ' '); // assume '\n' shows up before EOF
return ch;
}
在第一个循环之后,输入缓冲区包含 " + 9\n"
因此 getchar
将读取 space 并且输入缓冲区然后保存“+ 9\n”
然后scanf("%f", &operand);
会先读取对float有效的+
。因此它继续并读取下一个 space,它在 +
之后对浮点数无效,因此转换失败。 space 留在输入缓冲区中,但已经读取的 +
无法返回,因此它丢失了。
这在标准中有描述(引用 N1570):
An input item is read from the stream, unless the specification includes an n specifier. An
input item is defined as the longest sequence of input characters which does not exceed
any specified field width and which is, or is a prefix of, a matching input sequence. 285)
The first character, if any, after the input item remains unread.
注释 285 说:
- fscanf pushes back at most one input character onto the input stream.
简而言之:
当使用数字转换说明符扫描 +
后跟 space(即“+”)时,将导致匹配失败,并且 +
将被静默地从输入。
针对您的情况,一个简单的解决方案可能是:
while ((operator = getchar()) != '\n') {
if (operator == ' ') continue;
您需要检查 scanf
的返回值,因为它 returns 它能够读取的格式说明符的数量。您仍然需要知道是否输入了 float
。在任何一种情况下,您都需要做不同的事情......如果运算符和数字的顺序不合适,可能会发出语法错误信号。
还考虑将 +3.5
扫描为浮点数或运算符 +
后跟无符号浮点数的可能性。
我是编程新手,我知道 scanf() 有一些怪癖。也就是说,当它检测到与其转换说明符不匹配的字符时,它会立即 returns 并将有问题的字符放回缓冲区中,以便由另一个 scanf() 调用或其他一些函数读取可以访问缓冲区。 但是,我正在做书本练习,代码行为很奇怪。
float total = 0, operand = 0;
char operator = 0;
printf("Enter an expression: ");
scanf("%f ", &total);
while ((operator = getchar()) != '\n') {
scanf("%f", &operand);
switch (operator) {
case '+':
total += operand;
break;
case '-':
total -= operand;
break;
case '*':
total *= operand;
break;
case '/':
total /= operand;
break;
}
printf("Value of operator: %c\n", operator);
printf("Operand: %f\n", operand);
}
printf("Value of expression: %f\n", total);
两次 printf 调用用于测试。输入:“1 + 5 + 9\n”导致:
Value of operator: +
Operand: 5.000000
Value of operator:
Operand: 5.000000
Value of operator:
Operand: 9.000000
Value of expression: 6.000000
所以,程序似乎是这样的: scanf() 将 1 读入 'total',将其后的 space 与格式字符串中的 space 配对,遇到 '+',然后将其放回缓冲区并 returns.
然后:
循环 1 - getchar() 读取剩余的“+”并将其放入 'operator'。 scanf() 读取 5,遇到 space,将其放回缓冲区,然后 returns.
循环 2 - getchar() 读取剩余的 ' ',并将其放入 'operator' scanf() 遇到 '+' 并立即 returns 并将其放回缓冲区。
这里的内容与我的理解不符。在循环 3 开始时,getchar() 应该遇到 '+' 并将其存储到 'operator' 中。相反,它被完全跳过了,对我来说毫无意义。
此处跳过空格:while ((operator = nextchar()) != '\n')
而不是 getchar()
其中 nextchar()
可以是
int nextchar(void) {
int ch;
do ch = getchar(); while (ch == ' '); // assume '\n' shows up before EOF
return ch;
}
在第一个循环之后,输入缓冲区包含 " + 9\n"
因此 getchar
将读取 space 并且输入缓冲区然后保存“+ 9\n”
然后scanf("%f", &operand);
会先读取对float有效的+
。因此它继续并读取下一个 space,它在 +
之后对浮点数无效,因此转换失败。 space 留在输入缓冲区中,但已经读取的 +
无法返回,因此它丢失了。
这在标准中有描述(引用 N1570):
An input item is read from the stream, unless the specification includes an n specifier. An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence. 285) The first character, if any, after the input item remains unread.
注释 285 说:
- fscanf pushes back at most one input character onto the input stream.
简而言之:
当使用数字转换说明符扫描 +
后跟 space(即“+”)时,将导致匹配失败,并且 +
将被静默地从输入。
针对您的情况,一个简单的解决方案可能是:
while ((operator = getchar()) != '\n') {
if (operator == ' ') continue;
您需要检查 scanf
的返回值,因为它 returns 它能够读取的格式说明符的数量。您仍然需要知道是否输入了 float
。在任何一种情况下,您都需要做不同的事情......如果运算符和数字的顺序不合适,可能会发出语法错误信号。
还考虑将 +3.5
扫描为浮点数或运算符 +
后跟无符号浮点数的可能性。