如果用户输入"abc";作为输入,Do While循环大约循环3次,每个字母循环一次。但是,我希望它只循环一次。
int main(void) {
do {
printf("Enter how much money you can contribute: ");
numArgsRead = scanf(" %lf", &availableFundsToContribute);
scanf("%c", &finalValOnLine);
} while (!((availableFundsToContribute > 0) && (numArgsRead == 1) && (finalValOnLine == 'n')));
return 0;
}
以下是我的输出:
Enter how much money you can contribute: abc
Enter how much money you can contribute: Enter how much money you can contribute: Enter how much money you can contribute:
以下是我想要的样子:
Enter how much money you can contribute: abc
Enter how much money you can contribute:
有两个主要选项——继续使用scanf()
和切换到fgets()
和sscanf()
。
继续scanf()
如注释中所述,您需要跟踪scanf()
在不遇到EOF的情况下转换输入失败的时间,并处理无关的输入。处理它的正常方法是读到并包括行尾。
static inline int gobble_to_eol(void)
{
int c;
while ((c = getchar()) != EOF && c != 'n')
;
return c;
}
int main(void)
{
int numArgsRead;
double availableFundsToContribute = 0.0;
char finalValueOnLine = ' ';
do
{
printf("Enter how much money you can contribute: ");
if ((numArgsRead = scanf("%lf", &availableFundsToContribute)) == EOF)
break;
if (numArgsRead == 0)
{
if (gobble_to_eol() == EOF)
break;
}
else
{
if (scanf("%c", &finalValOnLine) == EOF)
break;
if (c != 'n')
{
/* Input might be 3.14abc */
if (gobble_to_eol() == EOF)
break;
}
} while (!(numArgsRead == 1 && availableFundsToContribute > 0.0 && finalValOnLine == 'n'));
return 0;
}
详细说明:除三种格式(%c
、%[…]
(扫描集(和%n
(外,所有格式都会自动跳过前导空格,包括换行符。没有必要在"%lf"
中包含空白(但在开始时这样做也没有害处,但在结束时添加空白是UI灾难(。
切换到fgets()
和sscanf()
另一种方法是读取整条线,然后用sscanf()
扫描它们。用户3386109在评论中提到了这一点,但这是标准建议,通常是处理输入的最佳方式。
代码可能看起来像这样:
int main(void)
{
char buffer[4096]; // Make it bigger if you prefer!
double availableFundsToContribute = 0.0;
char finalValOnLine;
do
{
printf("Enter how much money you can contribute: ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
break;
if ((numArgsRead = sscanf(buffer, "%lf%c", &availableFundsToContribute, &finalValOnLine)) != 2)
{
buffer[strcspn(buffer, "n")] = ' '; // Zap newline
fprintf(stderr, "Unrecognized input [%s] - try again.n", buffer);
}
} while (!(numArgsRead == 2 && availableFundsToContribute > 0 && finalValOnLine == 'n'));
return 0;
}
在这两种情况下,我可能都会使用一个顶部控制的循环(for
或while
(,但我会接近原始代码。在第一个代码中,可能应该有与调用gobble_to_eol()
相关的错误报告,以便用户知道程序认为什么是错误的。请注意,直接使用scanf()
会使报告问题的原因变得困难;读取一行,然后对其进行解析意味着您可以准确地报告错误的输入。同样需要注意的是,使用fgets()
意味着空行将被报告为错误,而不是默默地忽略等待新的输入。
警告:没有就代码的准确性咨询任何编译器。谨慎对待