Line spacing after endl and cout?

jlcv picture jlcv · Mar 15, 2013 · Viewed 8.8k times · Source

I noticed that in the following code:

    cout << "Please enter your number: ";
    cin >> Number;
    cout << "Is this spaced";

The output in the command window for C++ automatically puts "Is this spaced" in the next line. It spaces whatever is after the cin line without needing to use the stream manipulator (why is this called a stream manipulator?) endl. Whereas if I just have the code:

    cout << "Please enter your number: ";
    cout << "Is this spaced";

It won't automatically space the line with "Is this spaced". Instead both lines are joined up. I am curious to know why this is the case because I always thought that you need endl in order to create a new line of space.

Thanks!

Answer

Tony Delroy picture Tony Delroy · Mar 15, 2013
cout << "Please enter your number: ";
cin >> Number;
cout << "Is this spaced";

There's more to this than meets the eye. std::cout and std::cin are - by default - tied streams. That means that std::cout is automatically flushed (i.e. any pending output flushed from any buffers inside your program out to the operating system) whenever std::cin is asked for input. That's why you can be sure to see "Please enter your number: " before the program pauses to wait for you to type. Of course, in most Operating Systems you can start typing before the program's waiting - it will echo it to the terminal and remember it to provide to std::cin later: that's also what happens when you invoke a program with a pipeline such as:

echo "123" | the_program

The input's available when the_program starts running, but sits there for cin >> Number; to attempt parsing. In this case though, there's no keyboard input for the terminal program to echo, and hence the "123\n" sequence isn't echoed to the screen between your two lines of output - without that newline "\n" your output will all appear on one line.

If you want to read from the keyboard without the keyboard input moving the cursor to the next line, you'd be best off using ncurses or some similar library. The libraries can use escape sequences appropriate to your terminal (if available) to reposition the cursor to your liking. It may be practical to code that up yourself if you have a very limited range of terminals to support (e.g. just xterm-compatible ones, VT220, or Windows command shells). It's also generally possible to suppress the printing of keyboard input, but then the user couldn't see themselves type the digits. Another option is to set the terminal to an input mode supporting character-by-character input reading (some terminals default to line-by-line so you can't see characters until return is pressed) - combining that with the suppressed echo above your program can print digits as they're typed, but not print the newline.

Separately, it's good practice to end your program's output with a newline, as some invocation environments won't show the final line otherwise. And, it's somewhat contentious but IMHO best practice not to use std::endl when you don't need to flush the output - just use \n and let the C++ iostream library buffer multiple lines and write them in efficiently sized chunks to the operating system.

Explanation of flushing

Say you have a program like this:

std::string h = "hello ";
std::string w = "world";

std::cout << h;
std::cout << w << '\n';

At some stage, the program needs to tell the Operating System (Linux, Windows etc.) about the text to be printed, letting it send it to a shell/cmd prompt (which might send it on to the screen and put it in buffers for scrollbars etc.), a file or whatever. In the grand scheme of things, it's slow for the program to tell the operating system to do this kind of thing, so the program as a whole will work faster if it remembers "hello ", adds "world" and \n (a newline) to it, then sends "hello world\n" to the operating system all at once. That intra-program storage and concatenation of data is called buffering, and the act of writing data from the buffer to the Operating System is called flushing.