当用户在 scanf() 中输入错误的数据类型时如何修复无限循环?
How to fix infinite loops when user enters wrong data type in scanf()?
这里是C初学者。对于下面的程序,每当用户输入一个字符或字符串时,它就会进入一个无限循环。在仍然使用 scanf 的情况下,您将如何解决这个问题?与使用 scanf 相比,编写此程序的更好方法是什么?感谢那些会回答的人。
#include <stdio.h>
#include <ctype.h>
int main() {
int rounds = 5;
do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);
} while(isdigit(rounds) == 0);
return 0;
}
改变
scanf("%d", &rounds);
到
int ret;
if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
if (ret == EOF) break;
scanf("%*[^\n\r]"); // Consume the rest of the line
}
使用'scanf' 需要格式化输入。 Scanf 处理错误输入的能力非常有限。常见的解决方案是使用 fgets/sscanf,遵循以下结构:
char buff[256] ;
int rounds = 0 ;
while ( fgets(buff, sizeof(buff), stdin) ) {
if ( sscanf(buff, "%d", &rounds) == 1 ) {
// additional verification here
break ;
} ;
} ;
// Use rounds here ...
fgets/sscanf 将允许从解析错误中恢复 - 错误的输入行将被忽略。根据要求,这可能是可接受的解决方案。
如果你很喜欢scanf,可以使用getch来丢弃非数字输入:
int rounds = MIN_INT;
while (scanf("%d", &rounds)) != 1)
if (getc() == EOF) /* discard a rubbish character */
break; // or other error-handling return
// rounds is only valid if we did not break, when its value should be MIN_INT.
// but you might need another indicator
我会说只有两个 "fixes"。
保留 scanf
个调用、缺点和所有。当 scanf
需要数字时,请小心避免输入非数字。
放弃scanf
并使用其他东西。我们刚刚在 this new question.
上讨论了这个策略
一旦您使用 scanf
,尝试 "fix" 总是很诱人,因此这里可能潜伏着第三个答案,解释如何做得更好、更人性化、更容错输入,同时仍然使用 scanf
。然而,在我看来,这是徒劳的,是浪费时间。 scanf
的许多缺陷的简单、明显的修复本身并不完美,并且还有更多缺陷。您可能会花费更多时间尝试修复 scanf
-using 程序,而不是将其重写为不使用 scanf
——而且您会获得总体上更好的结果(更不用说更干净的程序了) 与非scanf
-using 无论如何重写。
C初学者也在这里。和你一样,我用的是scanf
,有时会出问题。
我遇到了你同样的问题,在找到更好的解决方案之前,我尝试用 scanf
和基本的东西来解决它。
我从这里尝试了不同的解决方案,但我一次又一次地遇到同样的问题,就像我输入:
- 一个数字后跟一个字符(例如123a),结果是一个有效数字(我不想要);结果是“123”。
- 一串数字和以数字开头的字符(例如 1a2b3),结果仍然是一个有效数字,即“1”。
- 开头的一个字符(例如a123)可以产生无限循环。
...等等...我试过do...while
,只有while
,for
...什么都没有。
我发现提示用户直到 he/she 只写数字的唯一解决方案如下,但是...
注意:如果用户键入 space,程序只考虑它之前的部分,例如'12 3',只考虑 12,3 不存在......除非你想像我那样使用无限循环,在这种情况下,你可以输入多个数字,检查它们并 运行 你的程序在他们身上一次。例如:'12 23 34 45' ...
注意 2:这是一个非常基本的初学者解决方案,我正在学习,这正是我所知道的。现在无法做得更好,正如我所说,我没有找到我喜欢输出的任何其他解决方案。
注意 3:我使用计数器对所有不是数字的输入求和,如果找到一个就存储值。如果我不使用此解决方案,我将最终遇到第一个字符是数字但其余字符不是数字的情况,它仍然有效(例如:'12w3' 是 12,我不想要)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
while (1) // try also multiple inputs separated by space
{
char str[10]; // should be enough for short strings/numbers (?!)
int strlength, num, counter;
do
{
printf("Enter a number: ");
scanf("%s", str);
strlength = strlen(str);
counter = 0;
for (int i = 0; i < strlength; i++)
{
if (!isdigit(str[i]))
counter++;
}
if (counter != 0)
printf("%s is not a number.\n", str);
} while (counter != 0);
num = atoi(str);
printf("%d is a number. Well done!\n\n", num);
}
}
你也可以把它放在一个函数中,远离 main()
。
这里是C初学者。对于下面的程序,每当用户输入一个字符或字符串时,它就会进入一个无限循环。在仍然使用 scanf 的情况下,您将如何解决这个问题?与使用 scanf 相比,编写此程序的更好方法是什么?感谢那些会回答的人。
#include <stdio.h>
#include <ctype.h>
int main() {
int rounds = 5;
do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);
} while(isdigit(rounds) == 0);
return 0;
}
改变
scanf("%d", &rounds);
到
int ret;
if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
if (ret == EOF) break;
scanf("%*[^\n\r]"); // Consume the rest of the line
}
使用'scanf' 需要格式化输入。 Scanf 处理错误输入的能力非常有限。常见的解决方案是使用 fgets/sscanf,遵循以下结构:
char buff[256] ;
int rounds = 0 ;
while ( fgets(buff, sizeof(buff), stdin) ) {
if ( sscanf(buff, "%d", &rounds) == 1 ) {
// additional verification here
break ;
} ;
} ;
// Use rounds here ...
fgets/sscanf 将允许从解析错误中恢复 - 错误的输入行将被忽略。根据要求,这可能是可接受的解决方案。
如果你很喜欢scanf,可以使用getch来丢弃非数字输入:
int rounds = MIN_INT;
while (scanf("%d", &rounds)) != 1)
if (getc() == EOF) /* discard a rubbish character */
break; // or other error-handling return
// rounds is only valid if we did not break, when its value should be MIN_INT.
// but you might need another indicator
我会说只有两个 "fixes"。
保留
scanf
个调用、缺点和所有。当scanf
需要数字时,请小心避免输入非数字。放弃
scanf
并使用其他东西。我们刚刚在 this new question. 上讨论了这个策略
一旦您使用 scanf
,尝试 "fix" 总是很诱人,因此这里可能潜伏着第三个答案,解释如何做得更好、更人性化、更容错输入,同时仍然使用 scanf
。然而,在我看来,这是徒劳的,是浪费时间。 scanf
的许多缺陷的简单、明显的修复本身并不完美,并且还有更多缺陷。您可能会花费更多时间尝试修复 scanf
-using 程序,而不是将其重写为不使用 scanf
——而且您会获得总体上更好的结果(更不用说更干净的程序了) 与非scanf
-using 无论如何重写。
C初学者也在这里。和你一样,我用的是scanf
,有时会出问题。
我遇到了你同样的问题,在找到更好的解决方案之前,我尝试用 scanf
和基本的东西来解决它。
我从这里尝试了不同的解决方案,但我一次又一次地遇到同样的问题,就像我输入:
- 一个数字后跟一个字符(例如123a),结果是一个有效数字(我不想要);结果是“123”。
- 一串数字和以数字开头的字符(例如 1a2b3),结果仍然是一个有效数字,即“1”。
- 开头的一个字符(例如a123)可以产生无限循环。
...等等...我试过do...while
,只有while
,for
...什么都没有。
我发现提示用户直到 he/she 只写数字的唯一解决方案如下,但是...
注意:如果用户键入 space,程序只考虑它之前的部分,例如'12 3',只考虑 12,3 不存在......除非你想像我那样使用无限循环,在这种情况下,你可以输入多个数字,检查它们并 运行 你的程序在他们身上一次。例如:'12 23 34 45' ...
注意 2:这是一个非常基本的初学者解决方案,我正在学习,这正是我所知道的。现在无法做得更好,正如我所说,我没有找到我喜欢输出的任何其他解决方案。
注意 3:我使用计数器对所有不是数字的输入求和,如果找到一个就存储值。如果我不使用此解决方案,我将最终遇到第一个字符是数字但其余字符不是数字的情况,它仍然有效(例如:'12w3' 是 12,我不想要)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
while (1) // try also multiple inputs separated by space
{
char str[10]; // should be enough for short strings/numbers (?!)
int strlength, num, counter;
do
{
printf("Enter a number: ");
scanf("%s", str);
strlength = strlen(str);
counter = 0;
for (int i = 0; i < strlength; i++)
{
if (!isdigit(str[i]))
counter++;
}
if (counter != 0)
printf("%s is not a number.\n", str);
} while (counter != 0);
num = atoi(str);
printf("%d is a number. Well done!\n\n", num);
}
}
你也可以把它放在一个函数中,远离 main()
。