我现在阅读了 Kernighan 和 Ritchie C 编程书,对“getchar”和“putchar”有一些疑问。
问题位于代码示例下方:
#include <stdio.h> int main(void) { int c; c = getchar(); while(c != EOF) { putchar(c); c = getchar(); } return 0; }
当我在终端中运行此代码并输入一个符号(例如'i')然后按 Enter 键时,它会打印输入的符号:
i // 输入的符号
i // 打印的符号
之后,它会要求我输入另一个符号。如果我输入另一个符号,则该过程将重复。如果我按 Ctrl-D (EOF) 而不是输入另一个符号,程序将终止。第一个问题是,为什么当我运行此代码并在输入符号(“i”)后,我没有按 Enter 而是按 Ctrl-D,它会打印输入的符号并以这种方式打印:
ii // 输入第一个符号,按 Ctrl-D 后打印第二个符号
因此要终止程序我需要再次按 Ctrl-D。
为什么在上面的代码中我可以输入一个单词并且它会打印一个单词,而在下面的代码中即使我输入了一个单词它也只打印一个符号? 代码:
#include <stdio.h> int main(void) { int c; printf("Enter a character:\n"); c = getchar(); printf("Entered character is:\n"); putchar(c); printf("\n"); return 0; }
如能提供任何帮助我将非常感激。
答案1
作为 C 语言输入的一般规则,它通常以行的形式工作 - 即,它是缓冲的。这意味着您输入的任何内容在Enter按下 之前都不会真正发送到程序。因此,对于第一个程序,它只是在请求时等待(也称为“阻塞”)getchar()
直到一行数据输入。因此,在发送整行之前,它实际上看不到输入的任何内容。
该行以“This is a line[EOF]”的形式发送(其中 [EOF] 是 C 运行时定义的文字 EOF 字符)。第一个程序中的循环工作方式有点像 do/while 结构,只需从缓冲区中一次抓取一个字符并打印它们直到结束。如您所知,Ctrl+D是 EOF 的 shell 同义词。在第一个程序中,当您按下Enter它时,光标会移动到下一行的开头(请注意该程序中没有“\n”,“\n”是由用户在Enter输入行后按下的)。这就是为什么当您使用Ctrl+时D不会发生换行符,因为不是程序本身产生换行符,而是用户按下Enter产生此换行符的键。
第二个程序大致相同,但是调用时没有循环getchar()
。这意味着getchar()
只调用一次。它从输入缓冲区获取第一个字符,打印该字符,然后打印一个新行,然后退出。由于没有循环告诉它执行多次getchar()
,这就是为什么您只看到一个字符而不是整行。
为了清楚起见,请记住输入是经过缓冲的。因此,在第二个程序中,您从输入缓冲区的开头抓取一个字符。但是,其余字符将保留在那里,直到您使用另一个调用来检索它们。开始 C/C++ 编程时的一个常见错误是忘记在完成操作后清空缓冲区。否则,该数据将保留在那里。
我记得当我第一次开始编写 C++(我的第一语言)程序时,我很困惑,我会使用类似下面的代码:
#include <iostream>
int main()
{
std::cout << "Enter a sentence: ";
std::string the_sentence;
std::cin >> the_sentence;
std::cout << "\nYou entered: " << the_sentence << std::endl;
std::cout << "Enter another sentence: ";
std::cin >> the_sentence;
std::cout << "\nYou entered: " << the_sentence << std::endl;
return 0;
}
我将得到一个运行的示例程序,如下所示:
Enter a sentence: Hi my name is Bob!
You entered: Hi
Enter a sentence: (the program would seemingly skip this input block)
You entered: my
这是因为 std::cin 调用只会读取第一个空格,其余输入则留在缓冲区中。下一次 std::cin 调用时,它会提取缓冲区中剩余的第一个内容,从而完全跳过实际输入阶段,因为缓冲区中已经有内容需要读取。
为了在 C 中刷新缓冲区,你可以使用类似
while((c = getchar()) != '\n' && c != EOF);
这只是一行 while 循环,本质上与第一个程序中的循环执行相同的操作,但它只是丢弃了输入
如果我充分回答了您的问题,请务必选择我的答案作为最佳答案。如果没有,请给我留言,我会尝试进一步扩展我的答案。