【问题标题】:Using getchar() inside an infinite loop in C在 C 的无限循环中使用 getchar()
【发布时间】:2018-02-06 11:13:54
【问题描述】:

我想输入一个字符并得到相应的 ASCII 整数作为输出。我正在使用 getchar() 获取输入,使用 while 创建一个无限循环,当输入 'q' 时循环将中断。我的代码是 -

#include <stdio.h>

int main() {
    int c;

    printf("Enter a character(press q to exit):\n");

    while(1) {
        c = getchar();
        printf("%d\n",c);

        if(c == 'q')
            break;
    }

    printf("End of the program");
    return 0;
}

当输入 q 时程序运行良好,退出程序。但如果我输入任何其他字符,数值最后会加上 10。例如,如果我输入 i,则输出为

Enter a character(press q to exit): 
i 
105
10
I
73
10

任何字符都在末尾添加了这 10 个字符。我做错了什么?

【问题讨论】:

  • 10 是 \n(换行符)的 ASCII 码。
  • 我不认为这是一个骗子,@MCG。它处理如何立即获取字符(基本上是原始模式)。这更多的是询问10 的来源。
  • 是的,我对 10 的来源感到困惑

标签: c while-loop infinite-loop getchar


【解决方案1】:

在使用getchar() 时,您作为 C 程序员的主要工作是考虑输入缓冲区中的所有字符。当您输入a 并按Return 时,getchar(); 读取'a',但将按Return 生成的'\n' 留在输入缓冲区stdin。在循环的下一次旅行中,代码似乎绕过任何提示而无需等待输入 -- 为什么?,因为 getchar() 已经有一个字符了等待阅读——'\n'

因此,任何这些面向字符的输入问题,您都必须戴上会计的帽子,并考虑stdin中留下的每个字符。有几种方法可以做到这一点。 Paxdiablo 展示了一个非常好的方法。另一种类似的方法利用辅助函数读取并丢弃stdin 中保留的所有字符。例如,如果您打算输入'a',但一只猫踩到了键盘,将"asdfdeeees" 留在了输入缓冲区中,则在读取'a' 之后,以下字符仍然是"sdfdeeees\n"。您需要一种简单的方法来丢弃所有剩余的字符。

下面提供了一个名为empty_stdin 的简单辅助函数,通过不断读取直到遇到'\n'EOF(它可以返回最后一个字符(或EOF)以允许检查供用户在 Linux 上使用 Ctrl + D 或在windoze 上使用 Ctrl + Z 手动取消输入。

#include <stdio.h>

/* helper function - empty all chars that remain in stdin */
int empty_stdin()
{
    int c = getchar();              /* get 1st char remaining in stdin */

    while (c != '\n' && c != EOF)   /* while not '\n' or EOF, get next */
        c = getchar();

    return c;
}

int main (void) {

    while (1) {     /* infinite loop for input */
        int c;

        printf ("Enter a character (press q to exit): ");
        c = getchar();                  /* read character   */

        if (c == '\n')                  /* is it a newline? */
            continue;                   /* if so, continue  */
        if (c == EOF) { /* end-of-file, from ctrl+d, or ctrl+z (windoze) */
            putchar ('\n');             /* tidy up with \n  */
            break;                      /* bail             */
        }
        if (c == 'q')                   /* did user quit?   */
            break;                      /* bail             */

        printf ("'%c' is integer: %d\n", c, c);

        if (empty_stdin() == EOF) {
            putchar ('\n');             /* tidy up with \n  */
            break;
        }
    }

    return 0;
}

使用/输出示例

以下是一个会话的输出,其中单个字符、多个字符(根本没有字符,只需按 Return 即可,并且可以毫无问题地处理每种可能的情况:

$ ./bin/getchar_min
Enter a character (press q to exit): A
'A' is integer: 65
Enter a character (press q to exit): BC and other stuff
'B' is integer: 66
Enter a character (press q to exit):
Enter a character (press q to exit): Z
'Z' is integer: 90
Enter a character (press q to exit): a
'a' is integer: 97
Enter a character (press q to exit): z
'z' is integer: 122
Enter a character (press q to exit): Q
'Q' is integer: 81
Enter a character (press q to exit): q

查看所有问题,查看所有答案,然后戴上会计师的帽子。看看每一个是如何成功的,在再次提示输入更多输入之前考虑缓冲区中的所有字符。同样重要的是检查EOF,这是用户在不使用'q'或生成SIGINT中断信号的情况下发出输入取消信号的唯一方法,例如Ctrl + C 在 Linux 上。如果您有任何其他问题,请告诉我。


编辑

注意:我在捕获每个 EOF 后添加了一个“整理 \n”,以便在执行结束时提供适当的换行符(因此,您的下一个终端提示不会在您的最后一次输入提示之后开始程序 -- 1/2 跨终端 :)

【讨论】:

  • 非常感谢你解释得这么好!
【解决方案2】:

10 是 ASCII 换行符,由于您在每行的末尾按 ENTER,它被放置在缓冲区中。

如果您想忽略这些字符,请不要对它们采取行动:

#include <stdio.h>
int main (void) {
    int c;
    printf ("Enter a series of characters (q will exit): ");
    for (;;) {
        c = getchar();
        if ((c == 'q') || (c == EOF)) // stop if EOF or 'q'.
            break;
        if (c != '\n')                // only print non-newlines.
            printf ("%d\n", c);
    }
    printf ("End of the program");
    return 0;
}

请注意,我也在循环中检查文件的结尾,否则返回值会导致相当烦人的无限循环。

【讨论】:

    【解决方案3】:

    你可以换行

    printf("%d\n",c);
    

     if (c != '\n') printf("%d\n",c);
    

    正如其他人指出的那样,您正在打印换行符。使用上面的“if”,确保只打印不是换行符的字符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 1970-01-01
      • 1970-01-01
      • 2021-07-18
      • 2022-01-22
      相关资源
      最近更新 更多