【问题标题】:C - Is there a way to read a single character of user input, and not have the rest "pushed down" to the next request for input?C - 有没有办法读取用户输入的单个字符,而不是让其余的“下推”到下一个输入请求?
【发布时间】:2020-02-14 17:00:56
【问题描述】:

所以,我正在用 C 语言开发一个简单的刽子手游戏,并且我有 read_guess 函数,如下所示。

void read_guess(char *guesses, char *p_current_guess)
{
    int valid_guess = 0;

    // Repeatedly takes input until guess is valid
    while (valid_guess == 0)
    {
        printf(">>> ");
        fgets(p_current_guess, 2, stdin);

        if (!isalpha(*p_current_guess)) printf("Guesses must be alphabetic. Please try again.\n\n");
        else
        {
            valid_guess = 1;

            // Iterates over array of guesses and checks if letter has already been guessed
            for (int i = 0; guesses[i] != '\0'; i++)
            {
                if (guesses[i] == *p_current_guess)
                {
                    printf("You have already guessed this letter. Please try again.\n\n");
                    valid_guess = 0;
                    break;
                }
            }
        }
    }
}

我已经尝试了所有标准输入函数(包括 getchar),但是对于所有这些函数,当提供大于一个字符的输入时,而不是只取第一个字符并继续(或再次询问),输入的其余部分被“推回”,并且下一次请求输入时,无论是因为输入包含非字母字符还是下一轮开始,输入的其余部分都会自动处理。这对输入的每个字符重复。

我怎样才能避免这种情况?

【问题讨论】:

  • 不,标准库函数没有这个功能。请记住,用户输入只是从文件中读取
  • 用户将输入作为行输入?只需丢弃所有内容,直到在输入流中找到下一个换行符。如果输入了多个字符,则可选择触发错误。然后进行下一轮。

标签: c input scanf fgets gets


【解决方案1】:

您正在使用fgets,这很好,但不幸的是不是正确的方式......

fgets 读取到行尾或最多 1 减去所询问的字符数。当然剩下的字符留给下一次读取操作......

惯用的方法是确保阅读到行尾,无论长度如何,或者至少达到更大的长度。

  1. 简单但在输入超过 SIZE 个字符时可能会失败:

    #define SIZE 64
    ...
    
    void read_guess(char *guesses, char *p_current_guess)
    {
        char line[SIZE];
        int valid_guess = 0;
    
        // Repeatedly takes input until guess is valid
        while (valid_guess == 0)
        {
            printf(">>> ");
            fgets(line, SiZE, stdin);                // read a line of size at most SIZE-1
            p_current_guess[0] = line[0];            // keep first character
            p_current_guess[1] = '\0';
            ...
    
  2. 强大但稍微复杂一些

    /**
     * Read a line and only keep the first character
     *
     * Syntax: char * fgetfirst(dest, fd);
     *
     * Parameters:
     *  dest: points to a buffer of size at least 2 that will recieve the
     *         first character followed with a null
     *  fd  : FILE* from which to read
     *
     * Return value: dest if one character was successfully read, else NULL
     */
    char *readfirst(dest, fd) {
    #define SIZE 256              // may be adapted
        char buf[SIZE];
        char *cr = NULL;          // return value initialized to NULL if nothing can be read
        for (;;) {
            if(NULL == fgets(buff, sizeof(buff), fd)) return cr; // read error or end of file
            if (0 == strcspn(buff, "\n")) return cr;             // end of file
            if (cr == NULL) {                                    // first read:
                cr = dest;                        //  prepare to return first char
                dest[0] = buff[0];
                dest[1] = 0;
            }
        }
    }
    

    然后您可以在代码中简单地使用它:

    void read_guess(char *guesses, char *p_current_guess)
    {
        int valid_guess = 0;
    
        // Repeatedly takes input until guess is valid
        while (valid_guess == 0)
        {
            printf(">>> ");
            fgetfirst(p_current_guess, stdin);
    

【讨论】:

    【解决方案2】:

    您可以丢弃所有输入直到行尾,每次您想请求输入时。

    void skip_to_eol(FILE* f, int c)
    {
        while (c != EOF && c != '\n')
            c = fgetc(f);
    }
    ...
        char c = getchar(); // instead of fgets
        skip_to_eol(stdin, c);
    

    【讨论】:

      【解决方案3】:

      您可以在 windows 上使用 getch() 函数来获取单个字符。这是 linux 的等价物

      What is the equivalent to getch() & getche() in Linux?

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-01
      • 2017-12-10
      • 2017-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多