为什么scanf输入一个字符就进入循环?
Why does scanf enter a loop when I input a character?
我必须完成一个大学项目,我的部分代码运行异常。
该部分的目标是让用户输入一个整数并将其存储在一个变量中,以便我以后可以使用它,但是如果用户输入一个字符,我必须再次询问该数字。
我使用 scanf
函数获取用户输入并将其放入 while
循环中以在输入无效时不断请求输入。
问题在于,当用户输入字符时,代码会崩溃并开始 运行 while
循环,而不会在 scanf
中停止以获取用户输入。
循环条件始终为真是有道理的,但奇怪的是它不会停止读取新输入。
我解构了我的代码以重现问题以使其更易于调试。
我知道有一些无用的变量,但在我的原始代码中它们很有用,我只是将它们保留在那里以使其看起来与原始代码相似。
我只能使用 scanf
来获取用户输入,尽管知道他们,但在这个项目中我只被允许使用 scanf。我不能用scanf
的格式来获取字符,这个项目只允许数字类型。
C11 是我们在 类 中使用的标准版本。
如果这个问题的解决方案很愚蠢,我很抱歉,我不擅长 C 并且这个学期我遇到了一些困难...
提前致谢。
while (!verification) {
printf(">>>"); //write values in here
check = scanf("\n%d", &var); //input a number and store the number of valid inputs
if (check) verification = 1; //if the input is a number then the while condition should turn to false with this statement
printf("var = %d, check = %d, verification = %d\n", var, check, verification); //printing all variables
}
如果用户未输入整数,则在调用 scanf 后输入流中仍有字符。因此,在下一次尝试读取整数之前,您需要阅读到行尾。否则 scanf 将尝试一次又一次地读取相同的非整数字符。这是一个例子:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch, i, n;
n = scanf("%d", &i);
while (n == 0) {
fprintf(stderr, "wrong input, integer expected\n");
do {
ch = getchar();
} while ((ch != EOF) && (ch != '\n'));
n = scanf("%d", &i);
}
if (n == 1) {
printf("%d\n", i);
} else { /*n == EOF*/
fprintf(stderr, "reading input failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
不要使用 scanf()
来读取用户的输入。
它实际上仅用于读取已知为特定格式的数据,以及来自用户的输入...通常不是。
虽然您确实正确检查了 scanf("%d")
的 return 值,并且可以解决输入不是数字的情况,但如果输入是空行,或数字后跟其他内容 (123 foobar
).
在空行的情况下scanf()
将继续等待非空白字符。这可能令人困惑,因为用户会期望按回车键来执行 某事。
如果数字后面有尾随内容,这些内容将保留在输入缓冲区中,并且下次您阅读内容时,它会被读取。这可能再次令人困惑,因为用户很少期望他们对一个问题的输入也能作为对另一个问题的输入。
相反,阅读带有 fgets()
或 getline()
的完整行,然后是 运行 sscanf()
或 strtol()
。这更加直观,并且避免了 scanf()
仅部分消耗输入行(或消耗多于一行)导致的断开连接。另见例如scanf() leaves the new line char in the buffer
此处,使用getline()
(POSIX,即使不是在标准C中。如果getline()
不可用,则使用fgets()
:
#include <stdio.h>
int main(void)
{
char *line = NULL;
size_t len = 0;
int result;
printf("Please enter a number: ");
while (1) {
if (getline(&line, &len, stdin) == -1) {
/* eof or error, do whatever is sensible in your case */
return 1;
}
if (sscanf(line, "%d", &result) != 1) {
printf("That didn't seem like number, please try again: ");
continue;
}
break;
}
printf("You entered the number %d\n", result);
}
问题是您必须在转换失败时丢弃有问题的输入。
这是一个仅使用 scanf()
的简单解决方案:
#include <stdio.h>
int main() {
int n;
for (;;) {
printf("Enter an number: ");
switch (scanf("%d", &n)) {
case 1:
/* successful conversion */
printf("The number is %d\n", n);
return 0;
case 0:
/* conversion failure: discard the rest of the line */
scanf("*[^\n]"); // discard characters before the newline if any
scanf("*1[\n]"); // optional: discard the newline if present
printf("Invalid input. Try again\n");
continue;
case EOF:
/* input failure */
printf("Premature end of file\n");
return 1;
}
}
}
我必须完成一个大学项目,我的部分代码运行异常。
该部分的目标是让用户输入一个整数并将其存储在一个变量中,以便我以后可以使用它,但是如果用户输入一个字符,我必须再次询问该数字。
我使用 scanf
函数获取用户输入并将其放入 while
循环中以在输入无效时不断请求输入。
问题在于,当用户输入字符时,代码会崩溃并开始 运行 while
循环,而不会在 scanf
中停止以获取用户输入。
循环条件始终为真是有道理的,但奇怪的是它不会停止读取新输入。
我解构了我的代码以重现问题以使其更易于调试。
我知道有一些无用的变量,但在我的原始代码中它们很有用,我只是将它们保留在那里以使其看起来与原始代码相似。
我只能使用 scanf
来获取用户输入,尽管知道他们,但在这个项目中我只被允许使用 scanf。我不能用scanf
的格式来获取字符,这个项目只允许数字类型。
C11 是我们在 类 中使用的标准版本。
如果这个问题的解决方案很愚蠢,我很抱歉,我不擅长 C 并且这个学期我遇到了一些困难...
提前致谢。
while (!verification) {
printf(">>>"); //write values in here
check = scanf("\n%d", &var); //input a number and store the number of valid inputs
if (check) verification = 1; //if the input is a number then the while condition should turn to false with this statement
printf("var = %d, check = %d, verification = %d\n", var, check, verification); //printing all variables
}
如果用户未输入整数,则在调用 scanf 后输入流中仍有字符。因此,在下一次尝试读取整数之前,您需要阅读到行尾。否则 scanf 将尝试一次又一次地读取相同的非整数字符。这是一个例子:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch, i, n;
n = scanf("%d", &i);
while (n == 0) {
fprintf(stderr, "wrong input, integer expected\n");
do {
ch = getchar();
} while ((ch != EOF) && (ch != '\n'));
n = scanf("%d", &i);
}
if (n == 1) {
printf("%d\n", i);
} else { /*n == EOF*/
fprintf(stderr, "reading input failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
不要使用 scanf()
来读取用户的输入。
它实际上仅用于读取已知为特定格式的数据,以及来自用户的输入...通常不是。
虽然您确实正确检查了 scanf("%d")
的 return 值,并且可以解决输入不是数字的情况,但如果输入是空行,或数字后跟其他内容 (123 foobar
).
在空行的情况下scanf()
将继续等待非空白字符。这可能令人困惑,因为用户会期望按回车键来执行 某事。
如果数字后面有尾随内容,这些内容将保留在输入缓冲区中,并且下次您阅读内容时,它会被读取。这可能再次令人困惑,因为用户很少期望他们对一个问题的输入也能作为对另一个问题的输入。
相反,阅读带有 fgets()
或 getline()
的完整行,然后是 运行 sscanf()
或 strtol()
。这更加直观,并且避免了 scanf()
仅部分消耗输入行(或消耗多于一行)导致的断开连接。另见例如scanf() leaves the new line char in the buffer
此处,使用getline()
(POSIX,即使不是在标准C中。如果getline()
不可用,则使用fgets()
:
#include <stdio.h>
int main(void)
{
char *line = NULL;
size_t len = 0;
int result;
printf("Please enter a number: ");
while (1) {
if (getline(&line, &len, stdin) == -1) {
/* eof or error, do whatever is sensible in your case */
return 1;
}
if (sscanf(line, "%d", &result) != 1) {
printf("That didn't seem like number, please try again: ");
continue;
}
break;
}
printf("You entered the number %d\n", result);
}
问题是您必须在转换失败时丢弃有问题的输入。
这是一个仅使用 scanf()
的简单解决方案:
#include <stdio.h>
int main() {
int n;
for (;;) {
printf("Enter an number: ");
switch (scanf("%d", &n)) {
case 1:
/* successful conversion */
printf("The number is %d\n", n);
return 0;
case 0:
/* conversion failure: discard the rest of the line */
scanf("*[^\n]"); // discard characters before the newline if any
scanf("*1[\n]"); // optional: discard the newline if present
printf("Invalid input. Try again\n");
continue;
case EOF:
/* input failure */
printf("Premature end of file\n");
return 1;
}
}
}