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

时间:2009-09-16 13:32:06

标签: c

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

这是什么“更好的方式”?

11 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:16)

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

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

#include <stdio.h>

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

编辑2:这是一个取自here的解决方案。

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

答案 2 :(得分:15)

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

如果您必须从IDE启动程序并希望程序在用户按下Enter键之前不终止,则单个getchar()应该执行此操作。

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

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

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

答案 3 :(得分:5)

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

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

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

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

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

答案 4 :(得分:5)

  

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

假设您有类似

的内容
int main ( void )
{
    int     input;

    scanf ( "%d", &input );

    printf ( "The input is %d.\n", input );

    getchar();
    getchar();

    return 0;
}

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

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

  

这是什么“更好的方式”?

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

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

#include <stdio.h>

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通常不需要stdout之后刷新printf,但如果你将它连接到磁盘上(通常在你记录崩溃的程序时它会丢失)如果你不冲洗,那么在崩溃之前最有趣的一点)。

由于fgets读取并包含该行的结尾,因此缓冲区中没有任何字符,因此您只需要一个getchar,并且稍微笨拙的输入,例如1234 空格 输入不会导致程序在没有暂停的情况下终止。

但是,大多数情况下,您不需要在运行控制台应用程序后等待 - 在Linux或其他Unix系统上,您通常打开控制台并在那里运行程序,然后控制权返回到shell。在Windows上,像Visual Studio这样的IDE通常run the program and pause使用类似的东西:

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

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

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

答案 5 :(得分:3)

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

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

答案 6 :(得分:1)

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

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

答案 7 :(得分:1)

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

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

123<newline>

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

123w<newline>

现在第一个getchar()获取'w',第二个获取<newline>,并且您的程序在您打算之前终止,并且在GUI环境中,如果终止进程拥有该窗口,则它是运行,然后操作系统关闭它。

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

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

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

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

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

答案 8 :(得分:0)

程序结束时

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

答案 9 :(得分:0)

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

答案 10 :(得分:-3)

由于“输入”按钮的一次点击会在Windows上生成两个字符,请参阅wikipedia。至少它很久以前也用在遥远的银河系中......