在C语言中的Putchar和Getchar函数

7

我正在阅读K&R的《C程序设计语言》,对于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 >>

我不确定为什么我的输入字符与固定字符串结合并输出。

此外,我也不太确定为什么要使用整数来存储字符。

9个回答

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
}

1
谢谢回复,但代码仍然无法正常工作,“输入单个字符>>”仍会打印两次,而不应该。如果您查看我的主要帖子和最后一个代码块,您可以看到在第二行中我所说的内容,字符a已连接到字符串“输入单个字符>>”,然后“输入单个字符>>”字符串立即再次打印到屏幕上。 - CS Student

4
您没有打印新行。在 putchar(ch); 之后,您应该使用 putchar('\n'); 来打印新行。

1
谢谢回复,但代码仍然无法正常工作,“输入单个字符>>”仍会打印两次,而不应该。如果您查看我的主帖和最后一个代码块,您可以看到在第二行我所指的是,字符a已连接到字符串“输入单个字符>>”,然后“输入单个字符>>”字符串立即再次打印到屏幕上。 - CS Student

3

用户终端可以在规范模式和非规范模式下操作。默认情况下,它在规范模式下运行,这意味着标准输入逐行(而不是逐个符号)提供给程序。当用户键入某些内容时(假设是字母'a',用十六进制表示为0x61)并按下回车键(换行字符'0x0A',用十六进制表示)。Ascii表格在这里。因此,此操作将向程序提供两个符号。如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"指示终端是否使用规范模式)。 另外,关于将字符存储为int类型在getchar()输出中的问题,请参见我在这里提供的类似主题的答案。

1
我们需要关注的术语是“流”
“流”就像一座桥梁,负责按顺序传输数据。(平滑流畅的流式传输在程序内外都由库/头文件管理,例如stdio.h)
回到你的问题:
当您键入输入字符“a”并按下“回车”时,您向输入流提供了2个值。 - a (ASCII值:97) - 回车(ASCII值:13) /* 这个输入中的“回车”很难处理。为了简单起见,我将在下面继续称其为Enter,并且通常不会在屏幕上显示*/
注意/重要/警告:在流完全为空之前,您无法从控制台写入新字符。(此场景仅适用于使用getchar和putchar,如下所示)
以下是您的代码:
for(i = 0; i < 10; i++)
    {
        printf("Enter a single character >> ");
        ch = getchar();
        putchar(ch);
    }
循环第一次: a) 要求用户输入一个字符。// printf语句 b) getchar从流中读取一个字符。 c) putchar从流中呈现/显示一个字符。 d) 在第一次通过时,您将'a'作为输入提供,但也按下'Enter' e) 现在,您的流就像一个***队列***,在第一次通过时,在队列的第1个位置有'a',在第2个位置有'enter'。 Queue f) 一旦您执行putchar,流/队列中的第一个字符,即'a',就会被显示出来。 e) 循环结束。 g) 此次通过的输出: 输入一个单个字符>>a

循环第二遍: a) 要求用户输入一个字符。// printf()语句 b) 不幸的是,您的流不是空的。它有一个来自前一次的“回车”值。 c) 所以,getchar()从流中读取下一个单个字符,即“回车”。(这就是您期望手动输入下一个字符的地方,但系统替您完成了此操作。请阅读上面提到的注意事项/重要事项/警告部分) d) putchar()在屏幕上显示“回车”,但由于“回车”不可显示,因此没有任何东西被显示。 e) 此次循环的输出: 输入一个单个字符>>

循环第三遍: 与循环1类似,只是这次的输入是“b”。

循环第四遍: 与循环2类似

一直进行10次迭代。(因此,您最后能输入的字符是“e”。)

推论/结论:

简而言之,你本来期望输入下一个字符,这样getchar就会捕获你输入的值,但由于在之前的操作中,“回车”键已经被存储在缓冲区中,所以它先被显示出来,给你造成了这样的错觉。

谢谢。 如果你有其他想法,请告诉我。


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;
}

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);
    }

0

我成功地得到了想要的结果。我添加了一个换行符和getchar()函数,它可以捕获额外的字符。

#include <stdio.h>

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

return 0;
}

0

虽然 getchar() 只获取一个字符,但是直到用户按下 Enter 键,控制权才会返回到程序中。实际上,getchar() 函数指示 C 接受输入并将其存储在缓冲区中,该缓冲区是为输入保留的内存区域。缓冲区直到用户按下 Enter 键才被释放,然后缓冲区的内容逐个字符地被释放。这意味着两件事情。一、只要用户没有按下 Enter 键,就可以使用退格键来更正错误的字符输入。二、如果您不清除它,则 Enter 按键会留在输入缓冲区中。为了清除 Enter 按键,请插入一个额外的 getchar() 来捕获 Enter 按键,但不对其进行任何操作。因此,在 ch = getchar(); 后面只需要再加一个 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;
}

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;
       }

这是错误的。你的第一个 getchar() 会吃掉用户输入,而 ch 只会得到一个换行符。 - Cyril

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接