C语言中的Scanf字符 [英] Scanf character in C

查看:84
本文介绍了C语言中的Scanf字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于某些原因, scanf 会读取字符,但即使字符有效,程序也不会继续经过用于验证字符的while循环。有时它可以工作,而其他时候则不行。奇怪的是我没有做任何不同的事情。有任何想法吗?

For some reason scanf reads the character but the program doesn't continue past the while loop used to validate the character even though the character is valid. Sometimes it works and other times it doesn't. The weird thing is I don't do anything different. Any ideas?

do
{
    printf("Enter \"p\" if you want to sort and shuffle a list of players or enter \"s\" if you want to sort a list of slots: "); // prompt
    scanf("%c", &tmp);
} while (tmp != 'p' && tmp != 's');

新代码:

printf("Enter 'p' if you want to sort and shuffle a list of players or enter 's' if you want to sort a list of slots:"); // prompt
tmp = getchar();

printf("%c ",tmp);
if (tmp == 'p')
{
    size = readPlayerFile(players); // calling readPlayerFile function
    shufflePlayers(players, size); // call shufflePlayers function
    sortPlayers(players, size); // call sortPlayers function
}
else if (tmp == 's')
{
    printf("hello");
    size = readSlotFile(slots); // calling readSlotFile function
    sortSlot(slots, size); // call sortSlots function

}


推荐答案

最简单的选择是在 scanf()中的格式字符串中添加前导空格。例如,如果您想在提供错误输入时提示用户再次输入字符,则可以执行以下操作:

The simplest option is to add a leading space to the format string in scanf(). For example, if you want to prompt the user to enter a character again when bad input is provided, you could do this:

#include <stdio.h>

int main(void)
{

    char tmp;
    printf("Enter \"p\" if you want to sort and shuffle a list of players "
           "or enter \"s\" if you want to sort a list of slots: "); // prompt
    while (scanf(" %c", &tmp) != 1 || (tmp != 'p' && tmp != 's')) {
        printf("Please enter \"p\" or \"s\": ");
    }
    printf("You chose %c\n", tmp);

    printf("Choose \"a\"scending or \"d\"escending sort: ");
    while (scanf(" %c", &tmp) != 1 || (tmp != 'a' && tmp != 'd')) {
        printf("Please enter \"a\" or \"d\": ");
    }
    printf("You chose %c\n", tmp);

    return 0;
}

这种简单的方法存在问题。如果用户输入 aaap ,则结果将为:

There is a problem with this simple approach though. If the user enters "aaap" then the resulting output would be:

Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: aaap
Please enter "p" or "s": Please enter "p" or "s": Please enter "p" or "s": You chose p
Choose "a"scending or "d"escending sort:

或者,更糟糕的是,如果用户输入正确的第一个字符,然后输入其他字符,例如 sfffa

Or, worse, if the user enters a correct first character followed by other characters, such as "sfffa":

Enter "p" if you want to sort and shuffle a list of players or enter "s" if you want to sort a list of slots: sfffa
You chose s
Choose "a"scending or "d"escending sort: Please enter "a" or "d": Please enter "a" or "d": Please enter "a" or "d": You chose a

因为 scanf() 在输入流中留下不匹配的字符,必须先处理这些字符,然后才能再次读取输入流。在使用%c 的简单解决方案中,初始空间导致 scanf()跳过前导空白字符,但其他任何字符都会被拾取。在现实世界中,您不能指望用户通过提供行为良好的输入来进行合作。

Because scanf() leaves unmatched characters in the input stream, those characters must be dealt with before reading the input stream again. In the simple solution using " %c", the initial space causes scanf() to skip over leading white-space characters, but any other characters will be picked up. And in the real world you can't count on the user cooperating by providing well-behaved input.

一种典型的便携式解决方案是使用 getchar()循环执行输入操作后清除输入流。您可能需要稍微更改输入循环逻辑才能做到这一点:

One typical, portable, solution is to use getchar() in a loop to clear the input stream after an input operation. You may need to change the input loop logic a bit to do this:

#include <stdio.h>

...

char tmp;
int c;
int scanf_ret;

do {
    printf("Enter \"p\" if you want to sort and shuffle a list of players "
           "or enter \"s\" if you want to sort a list of slots: "); // prompt
    scanf_ret = scanf("%c", &tmp);
    while ((c = getchar()) != '\n' && c != EOF) {
        continue;                   // discard extra characters
    }
} while (scanf_ret != 1 || (tmp != 'p' && tmp != 's'));

在调用 scanf()之后,输入一个循环,该循环读取并丢弃输入流中剩余的所有字符。请注意, c int ,而 EOF 是在循环中显式测试。 getchar()函数在发生错误或用户发出<$ c $信号时可能返回 EOF c> EOF 或从文件重定向输入。在这种情况下未能测试 EOF 会导致死循环。

After the call to scanf(), a loop is entered that reads and discards any characters remaining in the input stream. Note that c is an int, and that EOF is tested for explicitly in the loop. The getchar() function may return EOF in the event of an error, or if the user signals EOF from the keyboard, or if input has been redirected from a file. Failure to test for EOF in such circumstances would result in an infinite loop condition.

即使用户输入不可预测的输入,因为输入流始终在获取输入后清除。并且请注意,格式字符串中不需要前导空格。另一种解决方案是使用 fgets()将一行输入读取到缓冲区中,然后使用 sscanf()到缓冲区中。

This solution works, even if the user enters unpredictable input, since the input stream is always cleared after getting input. And note that there is no need for the leading space in the format string. Another solution would be to use fgets() to read a line of input into a buffer, and sscanf() to parse the buffer.

#include <stdio.h>
#include <stdlib.h>

...

char buffer[1000];
char tmp;
int sscanf_ret;

do {
    printf("Enter \"p\" if you want to sort and shuffle a list of players "
           "or enter \"s\" if you want to sort a list of slots: "); // prompt
    if (fgets(buffer, sizeof buffer, stdin) == NULL) {
        fprintf(stderr, "Error in fgets()\n");
        exit(EXIT_FAILURE);
    }
    sscanf_ret = sscanf(buffer, "%c", &tmp);
} while (sscanf_ret != 1 || (tmp != 'p' && tmp != 's'));

fgets()函数获取整个输入行(通过换行符),或者从输入流中获取(sizeof buffer)-1 个字符(如果缓冲区的大小不足以容纳输入中的所有字符)流和 \0 终止符。通过提供足够大的缓冲区,这应该可以正常工作。用户仍然可以输入大量字符,尽管这不会使缓冲区溢出,但字符将留在输入流中,以供下一次读取操作查找。为避免此类问题,如果后面还有多余的字符,则应在使用<$调用 fgets()后清除输入流。 c $ c> getchar()从上面循环。

The fgets() function gets an entire line of input, through the newline, or gets (sizeof buffer) - 1 characters from the input stream if the buffer is not large enough to hold all of the characters in the input stream and a \0 terminator. By providing a generously sized buffer, this should work fine. A user could still enter a very large number of characters, and while this will not overflow the buffer, characters would be left behind in the input stream for the next read operation to find. To avoid such issues, if there are extra characters left behind, the input stream should be cleared after the call to fgets() using the getchar() loop from above.

所有这些技术都有自己的位置。显然,后两个要比第一个更健壮,并且由于用户不太可能在输入提示下输入999个字符(包括换行符),因此它们几乎处于平等的地位。但是,为避免所有意外,最好在获得用户输入后明确清除输入流。

All of these techniques have their place. Clearly the last two are much more robust than the first, and as it is unlikely that a user will enter 999 characters at the input prompt (including the newline), they are almost on equal footing. But, to avoid all surprise, explicitly clearing the input stream after getting user input is best.

这篇关于C语言中的Scanf字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆