• Articles
  • Keep the console open long enough to see
Published by
Jan 28, 2009 (last update: Jan 31, 2009)

Keep the console open long enough to see your program's output

Score: 4.0/5 (55 votes)
*****
Press any key to continue . . .
This is typically a problem on Windows, caused by really dumb IDEs that don't know enough to keep the console open after the program finishes. However, it does strike right at one of the main philosophical problems with the way you are thinking about programming. After all, a console program should be run from the console --else once it terminates, the console should disappear. We'll get to fixing that later. For now, we'll stick with the immediate problem.


- - - - - - - - - - - - - - - - The Simple Answer - - - - - - - - - - - - - - - -
While simple, it really is a Bad Thing. See Why system() is evil for more.

1
2
3
4
5
6
7
#ifdef __cplusplus__
  #include <cstdlib>
#else
  #include <stdlib.h>
#endif

system("PAUSE");

It is also Windows-only. To do the same thing in Linux, you'd need to use the read shell command
1
2

system("read -p \"Press a key to continue...\" -n 1 -s");



- - - - - - - - - - - - - - - - The Standard Way - - - - - - - - - - - - - - - -
The most correct way to do it is something like:
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));
  }

Thereafter, simply place a call to it at the end of your program:
1
2
3
4
5
6
7
8
#include <stdio.h>

int main()
  {
  puts( "Hello world!" );
  PressEnterToContinue();
  return 0;
  }

The main problem with this approach is that it only works when input is properly synchronized. If it isn't, you will need to Flush Stdin. Learn more about proper synchronization with Issues When Reading User Input.

Also, it requires the user to press the Enter key to continue. This isn't such a bad problem as you might think. The mythical Any key has befuddled a lot of people. (A better phrase would have been "Press a key to continue..." --at worst people will press the A key.) Remember, non-programmers are almost always your target audience. And even if they aren't, what you are thinking isn't often as obvious as you think. Make sure to give clear instructions to the user about what kind of input your program wants next.


- - - - - - - - - - - - - - - - Using NCurses - - - - - - - - - - - - - - - -
The Curses library is designed for working with the console. Advantages: it is cross-platform. Disadvantages: it doesn't interact well with the standard streams. In other words, you shouldn't mix printf(), etc or cout, etc with curses. Use one or the other, not both.
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;
  }
There are some other things you must be aware of when using [w]getch(). Make sure you read through Getting Started with Curses.

So if all you want to do is pause your program once or twice then using Curses is overkill.


- - - - - - - - - - - - - - - - Using <conio.h> - - - - - - - - - - - - - - - -
Well, first some code.
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;
  }
This library is severely deprecated, but it is so popular that some form of it exists on most 80x86 hardware compilers --almost always on Windows compilers, and there exist Linux versions too. However, given the choice, use NCurses instead...

The caveat is that it is non-standard, meaning that the actual functions it provides vary a lot and they don't always behave just right. (Microsoft invented it years ago. That's right, not Borland --though Borland is [in]famous for it).

Hence, for anything other than Windows programs it is also a sub-optimal solution. See Using <conio.h> for more.

- - - - - - - - - - - - - - - - OS-specific ways - - - - - - - - - - - - - - - -
To do it any better, you need to do something OS-specific. Part of the design philosophy behind C and particularly C++ is something to the effect that the OS doesn't exist (or if it does, it is a magical black box). So to do something special with the console (C and C++ don't know what a console is, remember) means you will have to write code that is special to your operating system.

Here is a function that really lets you press any key, and returns the key that was pressed. Windows provides some nice, simple functions for playing with the console. It takes a little more magic on Linux, but it is just about as easy.

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="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/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, etc)
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="http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/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 ]);
  }

If you are using C++, you can add some convenience this way:
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 

Well, that's enough of that. To learn more about unbuffered (AKA "raw") input, take a gander at Read a single key for input.

Well, that's enough for now.