按任意键继续 . . .
这通常是Windows上的一个问题,原因是有些非常糟糕的IDE不知道如何确保程序完成后控制台保持打开。然而,这确实触及了您思考编程方式的一个主要哲学问题。毕竟,控制台程序应该从
控制台运行——否则一旦它终止,控制台
就应该消失。我们稍后会解决这个问题。目前,我们先专注于眼前的问题。
- - - - - - - - - - - - - - - - 简单答案 - - - - - - - - - - - - - - - -
虽然简单,但这确实是一件
坏事。请参阅
为什么system()很糟糕了解更多。
1 2 3 4 5 6 7
|
#ifdef __cplusplus__
#include <cstdlib>
#else
#include <stdlib.h>
#endif
system("PAUSE");
|
它也仅限于Windows。要在Linux上执行相同操作,您需要使用
read shell命令
1 2
|
system("read -p \"Press a key to continue...\" -n 1 -s");
|
- - - - - - - - - - - - - - - - 标准方法 - - - - - - - - - - - - - - - -
最正确的方法是这样的
1 2 3 4 5 6 7 8
|
#include <iostream>
#include <limits>
void PressEnterToContinue()
{
std::cout << "Press ENTER to continue... " << flush;
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );
}
|
1 2 3 4 5 6 7 8 9
|
#include <stdio.h>
void PressEnterToContinue()
{
int c;
printf( "Press ENTER to continue... " );
fflush( stdout );
do c = getchar(); while ((c != '\n') && (c != EOF));
}
|
之后,只需在程序末尾调用它即可
1 2 3 4 5 6 7 8
|
#include <stdio.h>
int main()
{
puts( "Hello world!" );
PressEnterToContinue();
return 0;
}
|
这种方法的主要问题在于
它仅在输入正确同步时才有效。如果不同步,您将需要
刷新标准输入。有关正确同步的更多信息,请参阅
读取用户输入时出现的问题。
此外,它要求用户按下
回车键继续。这可能不像您想的那么糟糕。神秘的
任意键让很多人感到困惑。(一个更好的说法应该是“按任意键继续……”——最坏的情况下,人们会按下
A键。)请记住,
非程序员几乎总是您的目标受众。即使不是,您想到的内容通常也不像您想象的那么明显。请确保向用户提供关于您的程序接下来需要何种输入的清晰指示。
A键。)请记住,
非程序员几乎总是您的目标受众。即使不是,您想到的内容通常也不像您想象的那么明显。请确保向用户提供关于您的程序接下来需要何种输入的清晰指示。
- - - - - - - - - - - - - - - - 使用NCurses - - - - - - - - - - - - - - - -
Curses库是为处理控制台而设计的。优点:它是跨平台的。缺点:它与标准流的交互不太好。换句话说,您不应该混合使用
printf()等或
cout等与curses。二者选一,不要混用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
#include <curses.h>
int main()
{
initscr();
addstr( "Hello world!\n\n" );
addstr( "\nPress a key to continue..." );
cbreak(); /* turn off line-buffering */
noecho(); /* turn off character echo */
getch(); /* read and discard a single character (caveats!) */
echo(); /* turn echo back on */
nocbreak(); /* turn line-buffering back on */
endwin();
return 0;
}
|
在使用[
w]
getch()时,还有一些其他事项需要注意。请务必阅读
开始使用Curses。
因此,如果您的所有需求只是暂停程序一两次,那么使用Curses就有点大材小用了。
- - - - - - - - - - - - - - - - 使用<conio.h> - - - - - - - - - - - - - - - -
首先,是一些代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#include <conio.h>
#include <stdio.h>
void PressAKeyToContinue()
{
int c;
printf( "\nPress a key to continue..." );
c = getch();
if (c == 0 || c == 224) getch();
}
int main()
{
puts( "Hello world!" );
PressAKeyToContinue();
return 0;
}
|
该库已严重弃用,但它非常流行,以至于在大多数80x86硬件编译器上都存在某种形式的它——几乎总是在Windows编译器上,并且也存在Linux版本。然而,如果可以的话,请使用
NCurses……
需要注意的是,它是
非标准的,这意味着它提供的实际函数变化很大,而且它们的行为并不总是恰到好处。(微软很多年前就发明了它。没错,
不是Borland——尽管Borland因此[臭名昭著])。
因此,对于Windows程序以外的任何程序,它也是一个次优的解决方案。请参阅
使用<conio.h>了解更多。
- - - - - - - - - - - - - - - - 特定于操作系统的实现方式 - - - - - - - - - -
要做得更好,您需要做一些特定于操作系统的操作。C,特别是C++的设计理念之一是,操作系统不存在(或者如果存在,它是一个神奇的黑盒子)。因此,要做一些与控制台相关的特殊操作(记住,C和C++不知道什么是控制台)意味着您将不得不编写与您的操作系统相关的特殊代码。
这是一个真正允许您按任意键并返回被按下键的函数。Windows提供了一些不错的、简单的函数来处理控制台。在Linux上需要更多的“魔法”,但几乎和它一样简单。
Windows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
/* ---------------------------------------------------------------------------
* PressAnyKey()
* ---------------------------------------------------------------------------
* Copyright 2008 Michael Thomas Greer
* <a href="https://boost.ac.cn/LICENSE_1_0.txt">https://boost.ac.cn/LICENSE_1_0.txt</a>
*
* function
* Optionally print a message and and wait for the user to press (and
* release) a single key.
*
* arguments
* The message to print. If NULL, uses a default message. Specify the empty
* string "" to not print anything.
*
* returns
* The virtual keycode for the key that was pressed.
*
* Windows #defines virtual keycode values like
* VK_UP
* VK_DOWN
* VK_RIGHT
* VK_LEFT
* which you can use to identify special keys.
*
* Letter keys are simply the upper-case ASCII value for that letter.
*/
#include <windows.h>
int PressAnyKey( const char *prompt )
{
DWORD mode;
HANDLE hstdin;
INPUT_RECORD inrec;
DWORD count;
char default_prompt[] = "Press a key to continue...";
/* Set the console mode to no-echo, raw input, */
/* and no window or mouse events. */
hstdin = GetStdHandle( STD_INPUT_HANDLE );
if (hstdin == INVALID_HANDLE_VALUE
|| !GetConsoleMode( hstdin, &mode )
|| !SetConsoleMode( hstdin, 0 ))
return 0;
if (!prompt) prompt = default_prompt;
/* Instruct the user */
WriteConsole(
GetStdHandle( STD_OUTPUT_HANDLE ),
prompt,
lstrlen( prompt ),
&count,
NULL
);
FlushConsoleInputBuffer( hstdin );
/* Get a single key RELEASE */
do ReadConsoleInput( hstdin, &inrec, 1, &count );
while ((inrec.EventType != KEY_EVENT) || inrec.Event.KeyEvent.bKeyDown);
/* Restore the original console mode */
SetConsoleMode( hstdin, mode );
return inrec.Event.KeyEvent.wVirtualKeyCode;
}
|
POSIX(Unix、Linux、Mac OSX等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
/* ---------------------------------------------------------------------------
* PressAnyKey()
* ---------------------------------------------------------------------------
* Copyright 2008 Michael Thomas Greer
* <a href="https://boost.ac.cn/LICENSE_1_0.txt">https://boost.ac.cn/LICENSE_1_0.txt</a>
*
* function
* Optionally print a message and and wait for the user to press (and
* release) a single key.
*
* arguments
* The message to print. If NULL, uses a default message. Specify the empty
* string "" to not print anything.
*
* returns
* The keycode for the key that was pressed.
*
* Extended key codes (like arrow keys) are properly handled, but their
* keycode is not understood; they are simply returned as the last code in
* the sequence, negated. For example, it is likely that the arrow keys are:
*
* UP_ARROW = -'A' = -65
* DOWN_ARROW = -'B' = -66
* RIGHT_ARROW = -'C' = -67
* LEFT_ARROW = -'D' = -68
*
* Exactly identifying the values for these keys requires a foray into the
* terminfo database, which is a subject for later. For now we'll leave it
* at this.
*/
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
int PressAnyKey( const char* prompt )
{
#define MAGIC_MAX_CHARS 18
struct termios initial_settings;
struct termios settings;
unsigned char keycodes[ MAGIC_MAX_CHARS ];
int count;
tcgetattr( STDIN_FILENO, &initial_settings );
settings = initial_settings;
/* Set the console mode to no-echo, raw input. */
/* The exact meaning of all this jazz will be discussed later. */
settings.c_cc[ VTIME ] = 1;
settings.c_cc[ VMIN ] = MAGIC_MAX_CHARS;
settings.c_iflag &= ~(IXOFF);
settings.c_lflag &= ~(ECHO | ICANON);
tcsetattr( STDIN_FILENO, TCSANOW, &settings );
printf( "%s", prompt ? prompt : "Press a key to continue..." );
count = read( stdin, (void*)keycodes, MAGIC_MAX_CHARS );
tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );
return (count == 1)
? keycodes[ 0 ]
: -(int)(keycodes[ count -1 ]);
}
|
如果您正在使用C++,您可以这样增加一些便利性
1 2 3 4 5 6 7
|
#if defined(__cplusplus)
#include <string>
inline int PressAnyKey( const std::string& prompt = "Press a key to continue..." )
{
return PressAnyKey( prompt.c_str() );
}
#endif
|
好了,就到这里吧。要了解更多关于无缓冲(也称为“原始”)输入的信息,请看看
读取单个按键作为输入。
好了,今天就到这里。