7

我正在阅读 K&R 的 The C Programming Language 并且对 putchar 和 getchar 感到困惑。我制作了一个程序,您可以在其中输入 10 个字符,然后程序将它们打印回屏幕。

#include <stdio.h>

int main() 
{
    int i;
    int ch;
    for(i = 0; i < 10; i++)
    {
        printf("Enter a single character >> ");
        ch = getchar();
        putchar(ch);
    }

    return 0;
}

我希望得到这样的输出:

Enter a single character >> a
a
Enter a single character >> b
b

...等等 10 次,但这是我得到的输出:(我在输入 2 个字符后停止)

Enter a single character >> a
aEnter a single character >>
Enter a single character >> b
bEnter a single character >>
Enter a single character >>

不知道为什么我的输入字符与固定字符串组合并输出。

另外,我不太清楚为什么使用整数来存储字符。

4

8 回答 8

5
putchar(ch);

只打印单个字符,以下内容printf在同一行内继续。只需添加:

putchar('\n');

之后putchar(ch);,它将在printf执行之前显式地开始新行。此外,您还应该'\n'从输入字符后保留在那里的输入中获取:

for(i = 0; i < 10; i++)
{
    printf("Enter a single character >> ");
    ch = getchar();
    getchar();        // <-- "eat" new-line character
    putchar(ch);
    putchar('\n');    // <-- start new line
}
于 2013-10-14T19:29:37.810 回答
4

您没有打印新行。之后putchar(ch);你应该使用putchar('\n');打印一个新行。

于 2013-10-14T19:28:22.607 回答
3

用户终端可以在规范和非规范模式下运行。默认情况下,它以规范模式运行,这意味着程序可以逐行使用标准输入(而不是逐个符号)。有问题的用户输入一些东西(让它成为字母'a',十六进制的0x61)并按下回车(十六进制的新行字符'0x0A')。Ascii 表在这里。所以这个动作给了一个程序两个符号。正如 man getchar() 中提到的那样,逐个符号地读取它。所以循环为一个字符迭代两次。要查看发生了什么,请使用以下程序(+循环计数器输出,+字符代码输出):

#include <stdio.h>
#include <unistd.h>

int main() 
{
  int i;
  char ch;
  for(i = 0; i < 10; i++)
  {
    printf("Enter a single character %d >>", i);
    ch = getchar();
    printf("Ch=0x%08X\n", ch);
    /*putchar(ch);*/
  }

  return 0;
}

输出:

┌─(02:01:16)─(michael@lorry)─(~/tmp/getchar)
└─► gcc -o main main.c; ./main 
Enter a single character 0 >>a
Ch=0x00000061
Enter a single character 1 >>Ch=0x0000000A
Enter a single character 2 >>b
Ch=0x00000062
Enter a single character 3 >>Ch=0x0000000A
Enter a single character 4 >>^C

所以程序得到两个符号并打印它们。并且新行符号不可见。因此,在问题中,用户会看到一条奇怪的附加行。有关不同终端模式的详细说明以及如何进行调整,请参见此处

在使用终端选项时, stty实用程序也很有用(“icanon”告诉终端是否使用规范模式)。

关于在 getchar() 输出中将字符存储为 int - 请参阅我对类似主题的回答

于 2013-10-31T22:13:53.387 回答
1

我们应该关注的术语是“流”

“流”就像一座桥梁,负责以顺序方式传输数据。(程序内外流畅流的和谐由库/头文件管理,例如 stdio.h)

回到你的问题:

When you type input as 'a' and hit 'enter', you supply 2 values to input stream. - a (ASCII Value : 97) - enter (ASCII Value : 13) /*This 'enter' as an input is the devil. To keep it simple, i will keep calling it as Enter below, and the enter is usually not displayed on screen*/

继续之前的注意/重要/警告:直到您的流没有完全变空,您才能将新字符从控制台写入流中。(此场景仅暗示使用getchar和putchar,如下图)

这是您的代码:

for(i = 0; i < 10; i++)
    {
        printf("Enter a single character >> ");
        ch = getchar();
        putchar(ch);
    }

循环通行证 1: a) You ask user to enter a character. // printf statement b) getchar reads only a single character from stream. c) putchar renders/displays only a single character from stream. d) At first pass you provide input as 'a' but you also hit 'Enter' e) Now, your stream is like a ***QUEUE***, at first pass, and at 1st place of the queue, you have 'a' and at 2nd place 'enter'. 队列 f) Once you do putchar, the first character , i.e. 'a' from the stream/queue gets displayed. e) Loop ends. g) Output of this pass: Enter a single character >>a

循环通行证 2: a) You ask user to enter a character. // printf() statement b) Unfortunately your stream isn't empty. It has an "enter" value from the previous pass. c) So, getchar(), reads the next single character, i.e. 'enter' from stream. (This is where you were expecting to manually enter the next character, but the system did it for you. Read the NOTE/IMPORTANT/CAUTION section mentioned above) d) putchar() displays 'enter' on screen, but since 'enter' is no displayable thing, nothing gets displayed. e) Output of this pass: Enter a single character >>

Loop Pass 3: 和loop 1类似,这次只输入'b'。

Loop Pass 4: 类似于loop 2

依此类推,直到 10 次通过。(因此,您可以输入的最后一个字符是“e”。)

推论/结论:

So, long story short, you were expecting to enter the next character, so that getchar would pick your entered value, but since from your previous pass,'enter' value was already waiting in the stream, it got displayed first, giving you such an illusion.

谢谢你。如果您的想法不同,请告诉我。

于 2019-01-25T07:19:52.307 回答
0

偶数次循环,getchar()不是从键盘获取输入,而是从上一次输入的命中获取,所以你也会注意到循环只执行了 5 次。所以你必须清除缓冲区,即按下输入,以便在ch.

for (i = 0; i < 5; i++)
    {
        printf("\nEnter a single character >> "); // new line
        ch = getchar();
        while (getchar() != '\n'); //Clearung buffer.
        putchar(ch);
    }
于 2016-06-25T19:32:37.487 回答
0

不确定是否理想,但这有效:

    #include <stdio.h>
    int main() 
    {
       int i;
       int ch;
        for(i = 0; i < 10; i++)
        {
            printf("Enter a single character >> ");
            getchar();
            ch=getchar();
            putchar(ch);
         }

         return 0;
       }
于 2017-04-18T00:36:43.097 回答
0

我是初学者。我尝试了这个版本的代码,它给出了所需的输出。

#include <stdio.h>

int main()
{
    int i;
    int ch;
    for(i = 0; i < 10; i++)
    {
        printf("Enter a single character >> ");
        fflush(stdin);
        ch = getchar();
        putchar(ch);
        printf("\n");
    }

    return 0;
}
于 2018-04-06T05:30:34.653 回答
0

尽管getchar()获取单个字符,但在用户按下 Enter 之前,控制权不会返回给您的程序。getchar()函数实际上指示 C 接受输入到缓冲区中,该缓冲区是为输入保留的内存区域。在用户按下 Enter 之前,缓冲区不会被释放,然后缓冲区的内容会一次释放一个字符。这意味着两件事。一,用户可以按退格键来纠正错误的字符输入,只要他或她没有按回车键。二,如果您不摆脱它,则 Enter 按键将留在输入缓冲区中。摆脱 Enter 按键插入一个额外的getchar()捕获 Enter 但不对其执行任何操作。所以您只需需要一个额外的getchar()在 ch = getchar(); 之后像这样

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

int main()
{    int i;
    int ch;
    for(i = 0; i < 10; i++)
    {
        printf("Enter a single character >> ");
        ch = getchar();
        getchar();
        putchar(ch);
    }
    return 0;
}
于 2020-03-23T11:08:47.897 回答