为什么我的教授使用两个getchar();?

为什么我的教授使用两个getchar(); 在我们的C程序教程结束时?

那个“更好的方法”是什么?

最好的方法是不添加任何代码来尝试并保持控制台窗口打开:从控制台窗口直接启动程序。

如果必须从IDE启动程序并希望程序在用户按下Enter之前不终止,则只需一个getchar()

在用户按下某个键后使程序终止的第二个更好的方法是始终确保没有待处理的输入并使用一个getchar()

我猜,你的老师使用2 getchar()的原因是输入缓冲区中已存在来自先前输入的字符。 要使用输入中的所有字符,包括ENTER,这通常是:

 int ch; /* ... */ printf("Press Enter"); fflush(stdout); while ((ch = getchar()) != '\n' && ch != EOF) /* void */; 

他正在等待用户输入,以便您可以看到程序的输出,否则它将刚刚完成并且输出将不可见(取决于操作系统)。 拿出来尝试一下。

他希望控制台保持打开状态并等待用户按下一个键。 我想要记住,取决于你的教授计划在“getchar()”之上发生的事情。 缓冲区中可能仍然存在某些内容,因此他添加了第二个“getchar()”。 不完全是解决问题的最优雅方式。

编辑:这是一个小例子。 “scanf()”缓冲区中仍然存在剩余的“\ n”如果添加第二个“getchar()”,则会得到预期的结果。 你必须在“getchar()”之前刷新缓冲区。

 #include  main() { int input; scanf("%d", &input); printf("The input is %d\n", input); getchar(); return 0; } 

编辑2:这是从这里采取的解决方案。

 int c; printf( "Press ENTER to continue... " ); fflush( stdout ); do c = getchar(); while ((c != '\n') && (c != EOF)); 

许多初学者认为有必要在他们的代码中进行两次 getch调用的原因是一次调用通常不起作用。

原因是getch从输入队列中获取下一个键盘输入。 不幸的是,只要用户按下键盘上的键,这个队列就会被填满,即使应用程序当时没有等待输入(如果它没有读取整个输入 – 请参阅Lulu的答案)。 因此, getch将从输入队列中获取一个字符, 而无需等待下一次按键 – 这正是程序员想要的。

当然,在键盘队列中只有一个字符的情况下,这种“解决方案”在很多情况下仍会失败。 更好的解决方案是刷新该队列, 然后请求下一个字符。 不幸的是,据我所知,在C / C ++中没有与平台无关的方法。 在C ++中执行此操作的常规方法(抱歉,我的C有限)看起来像这样:

 std::cin.ignore(std::cin.rdbuf()->in_avail()); 

这会忽略所有可用输入,有效清除输入队列。 不幸的是,这段代码并不总是有效(出于非常神秘的原因)。

为什么我的教授使用两个getchar(); 在我们的C程序教程结束时?

假设你有类似的东西

 int main ( void ) { int input; scanf ( "%d", &input ); printf ( "The input is %d.\n", input ); getchar(); getchar(); return 0; } 

两个因为scanf在按下enter之后才会返回,但是输入中的’\ n’和输入缓冲区中输入的任何其他字符都会有。

因此,如果您运行上述操作并输入1234 Enter ,程序将在打印后暂停The input is 1234.直到您再次按Enter键 。 第一个getchar读取与第一个Enter相关联的'\n' 。 如果输入其他内容,例如1234 Space Enter ,程序将不会暂停,因为第一个getchar将读取空格。 两个getchar可能还不够,并且您已经将用于打印响应的代码散布到用于处理输入的代码中。

那个“更好的方法”是什么?

在C中有各种标准的读取输入方法。在输入缓冲区中还有一些特定于平台的忽略文本的方法,但是如果使用fgets来读取输入行而不是scanf来读取某些内容,则不需要这样做从输入的最后一行输入。

fgets (读取输入直到’\ n’或文件末尾)后跟sscanf (解析字符串以进行输入)是安全的缓冲区溢出,并将吸收任何额外的输入和行终止’\ n’:

 #include  int main ( void ) { int input; char buf[16] = ""; fgets ( buf, sizeof buf, stdin ); sscanf ( buf, "%d", &input ); printf ( "The input is %d.\n", input ); fflush ( stdout ); getchar(); return 0; } 

在终端IO通常不需要printf之后刷新stdout ,但是如果你将它连接到磁盘上(通常当你记录崩溃的程序时,它会在崩溃之前失去最有趣的一点,如果你不不要冲洗。

因为fgets读取并包括行的末尾,所以缓冲区中没有剩余字符,因此您只需要一个getchar ,而稍微笨拙的输入(如1234 Space Enter)不会导致程序在不暂停的情况下终止。

但是,大多数情况下,您不需要在运行控制台应用程序后等待 – 在Linux或其他Unix系统上,您通常打开控制台并在那里运行程序,之后控制权返回到shell。 在Windows上,诸如Visual Studio之类的IDE通常运行程序并使用以下内容暂停它:

  "C:\WINDOWS\system32\cmd.exe" /c ""...\ConsoleApplication1.exe" & pause" 

或者您可以打开cmd.exe并从那里运行它,或者您可以使用.pif快捷方式运行它并将其设置为不在退出时关闭控制台,或者您可以创建运行它并暂停的批处理文件。

如果你在Windows上并且你正在使用调试器来运行它并且你没有设置任何断点,那么你真的只需要让程序暂停。

暂停(可能)命令行程序。 他正在使用两个,因为只使用一个不起作用,他可能不知道为什么..

找到一个更好的解决方案来做到这一点(而不是std :: cin),你将成为当时的英雄。

从IDE运行程序时,可能会保持输出窗口处于打开状态。

……为什么有两个人在我之外。

这是未使用的缓冲输入问题的天真解决方案。 你的教授认识到了这个问题,但它似乎不知道如何正确地解决它。

如果使用格式化输入,则仅使用与格式说明符匹配的字符。 因此,如果例如最后一个输入使用%d请求十进制整数,您可以在控制台输入:

123

格式化的输入将使用“123”,而缓冲。 未格式化的输入(如getchar())将使用该输入并立即返回。 由于这不是你想要的,你的教授使用了“只需添加另一个getchar()kludge”。 仅当用户输入预期输入时,此方法才有效。 Hamfisted打字员可能输入:

123w

现在第一个getchar()获取’w’,第二个获取 ,并且您的程序在您打算之前终止,并且在GUI环境中,如果终止进程拥有它正在运行的窗口,那么OS关闭它。

一个更强大的解决方案是重复调用getchar(),直到找到

 while( getchar() != '\n' ) { /*do nothing*/} ; getchar() ; /* wait */ 

当然如果以前的输入是一个字符,你需要检查它是不是

 while( ch != '\n' && getchar() != '\n' ) { /*do nothing*/} ; getchar() ; /* wait */ 

而不是在“等待”输入调用之前将刷新循环放在末尾,最好在每个需要它的输入之后执行缓冲区刷新。 这是因为您知道自己需要它,以及它应该如何编码。 我倾向于为我需要的输入类型编写包装函数。

getchar(); 在程序结束时创建一个“按任意键继续”的情况。 我猜他喜欢两次击中任何一把钥匙。

从缓冲区中获取剩余的“\ n”以便应用程序关闭。

因为“输入”按钮的一次点击在Windows上生成两个字符,请参阅维基百科 。 至少它很久以前也用在遥远的银河系中……