Contents
Introduction
This short article describes the method of clearing the console display of all text and positioning the text cursor in the home location (the upper-left corner).
Before becoming too comfortable doing this kind of thing blithely, make sure you read and understand about the
types and purposes of console applications (and
why it matters).
Throughout this article the code snippits will not assume either C or C++, so the #include section will be bracketed by the appropriate #ifdef tests depending on which language you are using. If you know yourself to be using just one, you can get rid of everything except for the proper #includes.
If you don't know what that entails, don't worry about it.
OS Agnostic Ways
The following methods are usually supported by a wide variety of platforms, but have significant tradeoffs in functionality or utility or both.
The Simple Answer
While simple, it really is a
Bad Thing. See
Why system() is evil for more information.
1 2 3 4 5 6 7
|
#ifdef __cplusplus__
#include <cstdlib>
#else
#include <stdlib.h>
#endif
if (system("CLS")) system("clear");
|
The Standard Way
This method is pathetic, but does the job, and it is usually correct.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#ifdef __cplusplus__
#include <iostream>
#include <string>
void ClearScreen()
{
cout << string( 100, '\n' );
}
#else
#include <stdio.h>
void ClearScreen()
{
int n;
for (n = 0; n < 10; n++)
printf( "\n\n\n\n\n\n\n\n\n\n" );
}
#endif
|
This works, of course, just by putting a hundred newlines to the display. Over a poorly-buffered network connection, this might be
s l o w. Alas.
Using Curses
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() and the like or
cout and the like with Curses. Use Standard I/O or Curses, but not both. (You can still employ Standard I/O with things other than the terminal, of course.)
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
|
#include <curses.h>
int main()
{
char users_name[ 100 ];
initscr();
(void)echo();
addstr( "What is your name> " );
refresh();
getnstr( users_name, sizeof( users_name ) - 1 );
/* Here is where we clear the screen. */
/* (Remember, when using Curses, no change will appear */
/* on the screen until <b>refresh</b>() is called. */
clear();
printw( "Greetings and salutations %s!\n", users_name );
refresh();
printw( "\n\n\nPress ENTER to quit." );
refresh();
getnstr( users_name, sizeof( users_name ) - 1 );
endwin();
return 0;
}
|
Again, if all you want to do is clear the screen on occasion, then it is complete overkill to use Curses. (If you
do use Curses, see
NCurses for Unix and Linux and other POSIX systems, and
PDCurses for DOS, Windows, OS/2, and some other random systems.)
Using <conio.h>
This library is severely deprecated, but it is so popular (due to
hysterical raisins) 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
Curses 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. Hence, for anything other than Windows programs it is also a sub-optimal solution. (See
Wikipedia's Conio article for a very succinct description of its limitations.)
If undaunted, then here is some code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <conio.h>
#include <stdio.h>
#include <string.h>
int main()
{
char users_name[ 100 ];
printf( "What is your name> " );
fgets( users_name, sizeof( users_name ), stdin );
*strchr( users_name, '\n' ) = '\0';
/* Here is where we clear the screen */
clrscr();
printf( "Greetings and salutations %s!\n", users_name );
printf( "\n\n\nPress ENTER to quit." );
fgets( users_name, sizeof( users_name ), stdin );
return 0;
}
|
Now, the enterprising among you may have already tried to compile this. If it worked for you, then you are lucky. If not, then you have learned firsthand the shortcomings of the <conio.h> library. Alas.
OS Specific Ways
So, on to the part for those of us who have the hack nature: we want to do it the
Right Way.
Windows API
The Windows Console has a specific-size
buffer of cell data, organized exactly the same as the old EGA/VGA/HGC cards but with user-specified dimensions: each "cell" contains attribute information (colors) and a character code (for simplicity, you can consider this the ASCII code -- its actual meaning depends on the current
Code Page). Clearing the screen is, therefore, a simple method of writing the current character attribute and a space character to every cell on the screen, then positioning the cursor at (0,0).
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
|
#include <windows.h>
void ClearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD count;
DWORD cellCount;
COORD homeCoords = { 0, 0 };
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
if (hStdOut == INVALID_HANDLE_VALUE) return;
/* Get the number of cells in the current buffer */
if (!GetConsoleScreenBufferInfo( hStdOut, &csbi )) return;
cellCount = csbi.dwSize.X *csbi.dwSize.Y;
/* Fill the entire buffer with spaces */
if (!FillConsoleOutputCharacter(
hStdOut,
(TCHAR) ' ',
cellCount,
homeCoords,
&count
)) return;
/* Fill the entire buffer with the current colors and attributes */
if (!FillConsoleOutputAttribute(
hStdOut,
csbi.wAttributes,
cellCount,
homeCoords,
&count
)) return;
/* Move the cursor home */
SetConsoleCursorPosition( hStdOut, homeCoords );
}
|
POSIX (Unix, Linux, Mac OSX, etc)
Unix systems are not so simple. While PC hardware follows a very strict standard, Unix systems work with more than a few different kinds of hardware. (Hundreds, actually.) In an effort to make writing programs for all these different types of terminals easier, a fellow by the name of Bill Joy wrote the
termcap library, which has been (long since) superceded by the
terminfo library, first programmed by Mark Horton and significantly updated and maintained by Eric S. Raymond.
The terminfo database and library makes querying and using advanced terminal features relatively easy. The caveat is, of course, you may be stuck on some ancient dinosaur that does not support the feature you desire, like "clear and home". (Fortunately, the vast majority of modern terminals do.)
Fortunately, since the terminal can do this stuff, the resulting code is quite a bit shorter than the Windows version:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#include <unistd.h>
#include <term.h>
void ClearScreen()
{
if (!cur_term)
{
int result;
setupterm( NULL, STDOUT_FILENO, &result );
if (result <= 0) return;
}
putp( tigetstr( "clear" ) );
}
|
You'll have to link to the proper library (one of
-lcurses
,
-lterminfo
, etc) to compile that last one. If neither of those work, you will have to ask your system administrator what to link to. I know that on some old SunSPARC workstations you have to link with
-lncurses
to get the proper library.
Other systems, like DOS
This article specifically addresses modern systems. If you are using an older system, such as DOS or something really weird, you will have to look up your system's documentation. For example, on DOS, you would have to use the
Video Interrupt functions to do it, or, as optimized programs often did, simply write directly to video memory. The ins and outs of this kind of thing are ancient, esoteric stuff. Good luck!
Addenda
This article, as it originally appeared, attracted some commentary, both good and bad. What follows is edited from that commentary to answer some valid questions.
ANSI Escape Codes
Why not just emit an ANSI Escape code, like
printf( "\033[2J" );
?
The answer is that it might not work. As explained above in
the introduction to the POSIX code, not all terminals take the ANSI/VT100+ escape sequences. (DOS and Windows, remember, has the suboptimal solution of requiring your
user to have loaded ANSI.SYS -- just to use a small subset of those escape sequences!) But beyond that, it is actually possible that the terminal gets something
other than what you think, because stuff that you
printf() might be modified some before it gets to the terminal itself!
The best way to do it on *nix systems is to use the
putp() function to properly communicate with the terminal, and to use the
tigetstr() function(s) to get the proper terminal escape sequence to send. It may very well be "\033[2J". It might not. If you use the terminfo database, your program will work almost everywhere, instead of mysteriously printing garbage or failing on a good number of systems.
On Windows, do things the Windows way.
Wait, how do I use this stuff?
This doesn't technically belong here, but the question came up about actually using this code. All the above examples are snippets, which you should know how to properly integrate into your program. For simple stuff, it is enough to just copy and paste the code into your program somewhere before it is used.
However, if you really want to get fancy and use multiple files, here is the quick-n-dirty:
Do not define functions in header files. You should only prototype them.
1 2 3 4 5 6 7 8 9
|
// clearscreen.h
// #include <disclaimer.h>
#ifndef CLEARSCREEN_H
#define CLEARSCREEN_H
void ClearScreen();
#endif
|
The source code goes in a separate .cpp file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
// clearscreen.cpp
// #include <disclaimer.h>
#include "clearscreen.h"
// Paste one of the above ClearScreen code snippets here.
// For example, here's the POSIX stuff:
#include <unistd.h>
#include <term.h>
void ClearScreen()
{
if (!cur_term)
{
int result;
setupterm( NULL, STDOUT_FILENO, &result );
if (result <= 0) return;
}
putp( tigetstr( "clear" ) );
}
|
To use the code, you need to do two things.
First, you need to #include "clearscreen.h" and use it as you would any other library.
1 2 3 4 5 6 7 8 9 10 11
|
#include <iostream>
#include <limits>
#include <clearscreen.h>
int main()
{
ClearScreen();
std::cout << "Hello world!\n\nPress ENTER to quit.";
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );
return 0;
}
|
Second, you must add "clearscreen.cpp" to your project so that it is compiled and linked also. If you port your code to another platform, all you need to do is compile a different "clearscreen.cpp" file to link with your code.
Well, that's it for now. Enjoy!