Console Closing Down

Pages: 1234567
There are two basic types of console application:

streams application
This is the default C/Unix style application. There is an unspecified (read: variable source) input stream of characters, and an unspecified output stream of characters. The only thing you know about these streams are that you can read and write characters to them. C and C++ are designed around this philosophy.

Streams applications are very powerful because they can be automated, or their output can be redirected to another program or to file, or their input can be generated by another program, etc. This flexibility was such a stroke of genius that it is considered one of the early revolutionary concepts that made Unix so popular, and was copied by almost every subsequent OS, and that enabled development of common 'modern' technologies like the internet and email.

To reiterate, the power of these applications are that it gives the user choices. It is not bound to any particular hardware or I/O device.

text user interface application
Unlike a streams application, a TUI (or more commonly, CUI) application expects a priori knowledge of the user's I/O devices. Generally speaking (since it is still possible to automate these programs using special software), CUI applications expect a human to be sitting at a terminal with at minimum a keyboard and a CRT.

The operative words here are "user interface". The "user" is expected to be a human. And, much like a Graphical User Interface, a CUI provides an interactive, visually-organized presentation of data and input.

The powerful feature of these applications is the convenience afforded the user when dealing with complex data. Early examples include vi and emacs, which display an entire screen of text at a time and permit the user to use arrow keys and mouse input to manipulate the file --whereas stream text editors like sed, while powerful, are considerably less convenient when revising a letter to your local congressman or your latest source code fixes.

The downside is the same as the upside: these applications have to know something special about your hardware. On DOS and Windows systems hardware is pretty standard, so it is not usually considered a problem. But on other PCs, Minis, Mainframes, and even supercomputers, hardware can vary widely. The development of the termcap (terminal capabilities) database, and later the terminfo database and ncurses libraries have mitigated some of these problems, but they are not a panacea.

In short, CUI applications are typically much more complex when dealing with I/O, and are less portable because of their dependance on specific hardware.

choice of platform
So, the ultimate question is: what kind of application am I writing? Streams or CUI? It is not typically a trivial task to say "both"; you must decide on one or the other.

For most homework assignments, or programs that calculate or analyze information or filter/modify data, a streams application is more appropriate. Examples include grep, awk, cc and c++, dir and ld, diff and patch, tee, tar and zip and compress, etc.

And, "hello world!".

For interactive games, text editors, web browsers, etc. a human is typically an essential part of the equation, and thus a CUI is most apropos.

So, to answer the question: which do you want?

In the case of a Tic-Tac-Toe game, either method is appropriate, depending on how you intend to interact with the user. If you want to clear the screen, go for it. Just do it safely. (In other words, do it Grey Wolf's way if you are on Windows, or use the terminfo database on *nix systems.) If anyone needs an example for Linux, let me know and I'll post one.

But if all the special stuff you want is to clear the screen, the desired effect can be accomplished much more simply by just printing 60 to 100 newlines.
cout << string( 100, '\n' );

Hope this helps.
Duoas,

Your wealth of knowledge brings such excitement to learning. I ask simply what should i do and you go above and beyond the call of duty, and I thank you for that.

I am indeed on a Linux system (Ubuntu Hardy Heron v8.04), and would greatly appreciate an example. I dont think the
cout << string(100, '\n');

would work, it seems to elementary, and really not what i want. I do see and agree with your point of doing it safely, thought the point of writing this program is to get me back into writing code (It's been a while since I took a Java class, 4 years I think) but writing code safely and to industry standards will come as I learn more.

My goal would never be to release the code for general use, thought it would be cool if someone that has done this for a while could look at it, and tell me where I could make improvements, or where potential bugs are, I don't know if anyone would ever do that, and if anyone would like to, let me know.

Thanks for all your help!

I wanted to make a short comment about how, in a certain instance, using string( 100,'\n') is as stupid, if not more, than system():
When using a virtual machine, each newline in the console is like watching baby seals being clubbed.
That's all. Thank you for your time.
Always something positive to add Helios!

:-)
clear the screen
It is actually fairly simple, but you need the terminfo/curses library.
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <unistd.h>
#include <term.h>

void clearscreen()
  {
  if (!cur_term)
    {
    int success;
    setupterm( NULL, STDOUT_FILENO, &success );
    if (success <= 0) return;
    }
  putp( tigetstr( "clear" ) );
  }

To compile, you'll have to link with one of the following libraries (whichever you have).
-lterminfo -lcurses -lncurses
For example on Debian systems (I use Kubuntu), I have to link with the second. On Solaris you need to link with the third.

Pause
Here's a bonus for you all: How to do it in Linux. (This is the "raw input" method instead of the "select" method, so it is a little longer --but it doesn't leave the key pressed unread in the input buffer.)
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
#include <unistd.h>
#include <termios.h>

// All commentary stripped out for size.
// See <http://www.lafn.org/~dave/linux/terminalIO.html> for details.

void raw( bool b )
  {
  struct termios settings;
  static struct termios initial_settings;
  static bool is_initialized = false;

  if (!is_initialized)
    {
    is_initialized = tcgetattr( STDIN_FILENO, &initial_settings ) == 0;
    if (!is_initialized) return;
    }

  if (b)
    {
    tcgetattr( STDIN_FILENO, &settings );
    settings.c_cc[ VTIME ] = 0;
    settings.c_cc[ VMIN  ] = 1;
    settings.c_iflag &= ~(BRKINT | ICRNL | INLCR | ISTRIP | IXOFF);
    settings.c_iflag |=   IGNBRK;
    settings.c_oflag &= ~(OPOST);
    settings.c_cflag &= ~(CSIZE | PARENB);
    settings.c_cflag |=   CS8;
    settings.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    }
  else
    settings = initial_settings;

  tcsetattr( STDIN_FILENO, TCSANOW, &settings );
  }

int pressanykey( const string& prompt = string() )
  {
  struct termios settings;

  tcgetattr( STDIN_FILENO, &settings );
  raw( true );

  printf( "%s", prompt.empty() ? "Press any key to continue..." : prompt.c_str() );
  int result = getchar();

  tcsetattr( STDIN_FILENO, TCSANOW, &settings );
  return result;
  }

I don't think I've typo-ed anything in there.
Sooner or later I've got to put all this stuff together into a console howto tutorial or article.

Enjoy!

[edit] Oh, before I forget. Assumed in all the above is that you have verified that you are dealing with a console and not some other redirected stream using the isatty() function. It is almost always found in <unistd.h>. (If it isn't, your system is messed up --IMHO.)
Last edited on
The pause on is way beyond me!!
well you can do this:

#include<iostream>
#include<cstdlib>

using std::cout;

int main()
{

cout<<"HELLO WORLD\n";
system("pause");
return 0;
}
Did you read the thread?
I'm sure not. ;)
tyler,

First reading the thread will help you to better add to the conversation. As Duoas has said before, system("pause") is bad practice, view his prior posts to see why.

I'm having issues with the code to pause. I am VERY new (few hours) and am going through some online tutorials, all of which seem to look over this issue(in several compilers). I am using Dev C++ and even with the code my console closes right away.

I've tried cin.get();
cin.ignore();

and the original solution but none work. Debugging doesn't show anything.
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
/*****************************
Program: Box Area
Purpose: Find the area of a box.
Date: 09/05/08
***************************/

#include <iostream>
#include <limits>
using namespace std;
typedef unsigned short Ushort;
//Function Prototype
Ushort FindArea (Ushort length, Ushort width);

//Get the dimentions from the User.
int main()
{
    
    Ushort length;
    Ushort width;
    Ushort area;
    
    cout << "\nHow long is your Box?";
    cin >> length;
    cout << "\nHow wide is your Box?";
    cin >> width;
    
    area = FindArea(length, width);
    
    cout << "\nYour yard is " << area <<" square feet.";
    
    cout << "Press ENTER to continue...";
    cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
    
    
    return 0;
    
}
//Function process when called.
Ushort FindArea (Ushort l, Ushort w)
{
       return l * w;
}
   

ignore() before get()ing.

I still don't understand why people don't just manually open a console.
System ("pause"); doesn't even work. Could it be an issue with my compiler?

From all the solutions on this page thread, I think I would have found one that works.

Edit: Bloodshed Software's download page says their latest version of Dev C++ is compatible up to XP. I am running Vista Home Premium; could this be an issue?
Last edited on
No, the issue is how you have pre-loaded the input.

A step-through will help:

1. cout << "Enter a number> "; cin >> number_one;
2. The user types
37
and presses ENTER.
3. That sequence of keypresses gets sent to the program as "37\n". (The ENTER key was translated into a newline character.)
4. The cin statement skips all leading whitespace (there isn't any), reads "37", translates it into the number 37, and sticks that in the number_one variable.
5. Notice that the "\n" is still waiting to be read by the program.

6. cout << "Enter another> "; cin >> number_two;
7. Again, the user types something like
-2
and presses ENTER.
8. That sequence gets sent to the program as "-2\n".

9. At this point, the list of characters waiting to be read by the program is "\n-7\n".

10. The cin statement skips all leading whitespace (reading and ignoring that first "\n", leaving "-7\n"), reads "-7", converts it into the number -7, and assigns that value to number_two.
11. Notice how there is yet again a lone "\n" waiting to be read by the program.

12. cout << "Press ENTER to continue..."; cin.ignore( ..., '\n' );
13. The cin statement now ignores everything up-to and including the next "\n".

14. But wait! There is a leftover "\n" sitting in the input buffer waiting to be read. So cin reads it (leaving "" in the input buffer), and the program terminates before the user can get his fingers to move.


And there lies the caveat to using cin >> anything when dealing with the user. Remember:

The user always expects to have to press ENTER after every input

(in a streams application). Unless the program shows him otherwise by immediately responding to keypresses (in a CUI application).


So, you have to be careful when getting input.

Method one
Once you are done any sequence of "cin >>"s you should cin.ignore() that lone newline before continuing with the rest of the program. In your program, input occurrs on lines 22..25, so a good place to ignore() that unread newline is right after line 25.

Method two
Don't "cin >>". Use getline() and std::stringstream instead. For example:
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
#include <ciso646>
#include <sstream>
#include <string>

template <typename ValueType>
std::istream& read( std::istream& ins, ValueType& value )
  {
  using namespace std;
  string s;
  getline( ins, s );
  if (ins.good())
    {
    stringstream ss( s );
    ss >> value;
    if (!ss.good())
      ins.setstate( ss.rdstate() );
    }
  return ins;
  }


#include <iostream>
using namespace std;
int main()
  {
  float f;
  integer i;

  cout << "Quiz!\nWhat is the average airspeed of an unladen European Swallow (in m/s)? ";
  read( cin, f );
  if (!cin or (f < 10.5) or (f > 11.5))  // [1]
    cout << "Aiiiieeeee!\n";
  else
    {
    cout << "What is the day of the month today? ";
    if (!read( cin, i ))
      cout << "Well at least guess...\n";
    else
      cout << "Close enough. :-)\n";
    }

  return 0;
  }

[1] http://answers.yahoo.com/question/index?qid=20070409040602AACDUk6

Hope this helps. :-]
You have opened my eyes.
There is something I don't understand, though. Why is there a '\n' in the buffer at the beginning of step 14? If the buffer was just "\n" before the ignore(), shouldn't it be "" after the ignore()?
Last edited on
Why is there a '\n' in the buffer at the beginning of step 14? [emphasis added]

The same reason there was one sitting there at the beginning of step 10: it hasn't yet been read (and discarded) by a "cin>>" or a "cin.ignore()".

If the buffer was just "\n" before the ignore(), shouldn't it be "" after the ignore()?

Exactly right. The problem is, the ignore() is reading the '\n' from the last time the user pressed ENTER. The program asked for the user to press ENTER again, but it forgot about that leftover '\n', and reads it instead of reading a new '\n' that the user hasn't had the chance to enter yet.

[edit]
Ideally, the input buffer should be "" before the program asks the user to "Press ENTER to continue...", so that the very next "\n" read is surely the one the user pressed after asking him to do it.
[/edit]

Clear as mud, right? :-P
Last edited on
I'm sorry, but I think I'm not quite following you yet.
12. cout << "Press ENTER to continue..."; cin.ignore( ..., '\n' );
13. The cin statement now ignores everything up-to and including the next "\n".
Okay, so now, in theory the buffer should be empty, right? Since there was only one '\n' left over from the second std::cin. So ignore() should have read it and ignored it, right?
So then why
There is a leftover "\n" sitting in the input buffer waiting to be read.
(Yawn. Sleep is great. /me wakes up)

You are right, but I think my statement ordering is what has mixxed you up. Step 10 is a "cin>>foo", which leaves (step 11) the buffer as "\n".

Step 12. Ask for a "cin.ignore()". The intent is to wait for the user to press ENTER sometime after step 12 is executed (which is what I meant by step 13).

However, because of the unread "\n" left over from step 10, (which is what step 14 is talking about), the "cin.ignore()" in step 12 doesn't wait, it just reads 10's "\n" and continues on its merry way, without waiting for the user to press a new ENTER.

Sorry to have confused you.

[edit]
Oh yeah, the "cin.ignore(...,'\n')" only discards the first newline it encounters. So if your unread input is "\nabc\n", then it becomes "abc\n".
Last edited on
Oh, I get it, now. I thought you were putting a get() after the ignore(), which is why I got confused.
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <conio.h>

int main() {
    cout << "Press any key to continue... ";

    _getch();

    return 0;
}
Pages: 1234567