Learn C++ with Qt, Part 004: Console Input


This part of the C++ with Qt tutorial is about basic forms of data input in console (terminal) programs. In order to store the input and to process it inside the program, we also need variables, so I'll start with an introduction to variables here.

Introduction to variables

In the examples for formatted output with “sprintf()” and single character output with “putc()” in part 3 of this tutorial I already used some variable definitions. Variables are needed if you want to process any kind of data, either data which is read into the program as an input, or data which is part of some kind of computation.

Variable definition

In any C or C++ program, a variable can be defined by a variable type keyword like “int” (for integer) or “char” (for characters), followed by a blank space and the variable name. This is followed by either a comma if further variable definitions follow, or by a semicolon, which closes the variable definition.

So if you want to define a variable for integer values with the name “MyAge”, the definition looks like this:

int MyAge;

You can assign an initial value to the variable in the same step as you are defining it, like this:

int MyAge=42;

If no initial value is assigned, the variable automatically is assigned a default value that depends on the data type of the variable. Numeric variable types like “int”, “float” or “double” usually have an initial value of zero, while character-based variables like single characters or strings are initialized with either a blank space or a “zero-character” literal.

You will find more information about different data types in a later part of this tutorial.

Internal handling of variables

Any variable definition inside a program is translated by the computer, just like any other code command.

In the case of a variable definition, the computer reserves a piece of memory (inside the RAM) when the program is running. The internal address of this memory is assigned to the variable name. The amount of the reserved memory depends on the data type of the variable. Any value that lies within the boundaries of the used data type can be stored inside the reserved memory location.

If an initial value is assigned to the variable, this value is automatically stored inside the reserved memory location.

When you exit from the program, the reserved memory is freed up again – unless some very specific circumstances stop this process or the program does not terminate properly. For standard data types, we can safely assume that the memory is freed up properly. The free memory parts can then be used by other programs or for a new start of the same program.

Text input of strings

In order to read in some text as a direct keyboard input from the user, we need to define a character or string variable that stores the input.

Let’s start with a string variable for reading the name of the user:

string username;

In order to let the user know that we want her/him to enter her/his name, we can use the text output function “cout” from the last tutorial:

cout << “Please enter your name: “;

To read the name and use it later on there are some different options:

First, we can use the input operator “cin” in a similar way to the output operator “cout”:

cin >> username;

This redirects data from the standard input stream – which is direct keyboard input inside the current terminal window - into the memory location allocated to the “username” variable. In order to stop the input, you only have to press the return button.

The downside of this form of input is that any data is only transferred into the storage variable up to the point where there is a blank space. So if you input several words separated by blank spaces, only the first word is stored inside the variable.

For longer inputs including blank spaces we can use the “getline” input function as a second input option:

getline (cin, username);

This allows us to enter the full first and last name(s) separated by blank spaces as the username. As before, the input is terminated by pressing the return or enter button.

The third option of reading an input string is the “getstr” function from the classic C language. However, its proper use requires some understanding of pointers, which are a little more tricky to use than other types of variables. I’ll leave this option for a later part of this tutorial.

String input demonstration

The following demonstration program combines text output with the text input options mentioned above. As we use some string functionality, the string library has to be included alongside the “iostream” and “QCoreApplication” libraries:

#include <QCoreApplication> #include <iostream> #include <string> using namespace std; int main(int argc, char *argv[]) { string username, nickname; QCoreApplication a(argc, argv); cout << “Please enter your username: “; getline (cin, username); cout << “Hello “ << username << endl; cout << “What is your nickname? “; cin >> nickname; cout << endl << “So, “ << username << “ is called “ << nickname << “?” << endl; cout << “Ok…” << endl; return a.exec(); }

Text input of single characters

Apart from complete strings, single characters can also be read in from the keyboard input with the help of “cin”.

Instead of defining a string for the input, we have to define a single character variable:

char inchar;

or

int inchar2;

The first way to read in a single character is to use the “cin” operator for the standard input in combination with a character variable:

cin << inchar;

Just like a string input, the data which is entered by keyboard is transferred into the variable after the enter key is pressed. Due to the variable type “char” however, only the very first character is stored. Any additional input is ignored.

As a second option, there is also a “getc” function which reads in a single character, similar to the “putc” function for output of single characters.

This function reads a single character from the defined input stream which is passed as a parameter, and returns the value of the character.

So the usage looks like this:

inchar = getc(stdin);

There is also another, similar input option in the form of the “getchar” function. It automatically reads from the standard input stream (keyboard), and returns the character as output value:

inchar = getchar();

Now let’s try out this simple program:

#include <QCoreApplication> #include <stdio.h> #include <iostream> #include <string> using namespace std; int main(int argc, char *argv[]) { char favchar1, favchar2, favchar3; QCoreApplication a(argc, argv); cout << "What is your favorite character? "; cin >> favchar1; cout << "And what is your second favorite character? "; favchar2 = getc(stdin); cout << "And the third favorite character? "; favchar3 = getchar(); cout << endl << "Your favorite characters are " << favchar1; cout << ", " << favchar2 << " and " << favchar3 << endl; return a.exec(); }

If you start this program, it should print out the questions about your favorite characters and read in three single characters. At the end, you should see a final sentence with a list of the characters you entered.

But that’s not what happens. Instead, the output looks like this:

Strange, isn’t it? It seems that the second character input is skipped and only the first and the last input are used.

This is actually caused by the default behavior of the standard input and output streams.

Clean input

When you enter the first character using “cin”, you have to press the enter/return key in order to terminate the input. Even if you really just entered one character, the return key automatically enters a second character, namely the “newline” character (ASCII value “10”). This is stored in the standard input stream, but not directly read in by the program.

Once the program executes the “getc(stdin)” function, the stored newline character is read in from the input stream, before you can enter another character. So the second input seems to be skipped, and you can only enter the third and last character before the list is printed on the screen.

In order to suppress this behavior here, we can clear the input stream before the character input function is called. This is done with the standard function "fflush" which operates on a given stream:

fflush(stdin);

The above statement deletes any data from the standard input stream (stdin) which has not yet been processed. So in the case of our little character input program, it deletes the newline character and anything else that may have been entered after the first input character.

With this, the program can be changed as follows:

#include <QCoreApplication> #include <stdio.h> #include <iostream> #include <string> using namespace std; int main(int argc, char *argv[]) { char favchar1, favchar2, favchar3; QCoreApplication a(argc, argv); cout << "What is your favorite character? "; cin >> favchar1; fflush(stdin); cout << "And what is your second favorite character? "; favchar2 = getc(stdin); fflush(stdin); cout << "And the third favorite character? "; favchar3 = getchar(); cout << endl << "Your favorite characters are " << favchar1; cout << ", " << favchar2 << " and " << favchar3 << endl; return a.exec(); }

Now when you run this modified program, it operates like expected, waiting for you to enter each of the three single characters.

The "fflush" function can also be used for other types of streams. It's useful if you want to be sure that any previous and unwanted data from the stream in question is deleted before you start with the proper processing of the input or output.

String streams

As a last addition to input and output, let's have a look at string streams.

By adding the "sstream" library to your program as an additional standard include ("#include <sstream>") you can add a stream function called "stringstream" to the program.

This function allows any string to be handled like a standard input stream. By doing this, the stream operator ">>" can be used to extract data from a string and copy it into a variable of another type, thus converting it.

Here is a short example for a "stringstream" conversion:

#include <QCoreApplication> #include <iostream> #include <string> #include <sstream> using namespace std; int main(int argc, char *argv[]) { string myinput; float price = 0; int amount = 0; QCoreApplication a(argc, argv); fflush(stdin); cout << "Sell your apples..." << endl; cout << "Please enter your price per apple: "; getline(cin, myinput); stringstream(myinput) >> price; cout << "How many apples do you want to sell? "; getline(cin, myinput); stringstream(myinput) >> amount; cout << "If you sell all of them, you will earn: " << price*amount << endl; return a.exec(); }

In this example, the strings entered for the price and amount of apples are converted into a float and an integer value. With these kind of variables, arithmetic operations can be performed, so the earnings can be calculated. If you use unconverted strings instead, you can output the strings, but cannot use them for any calculations.

There are also some other ways to convert values from one data type into another, but the "stringstream" is an easy way to do it if you have strings that contain the data to be converted.

Next up...

I hope you could follow me so far. I have added the code from the examples above to the "Console_IO" subdirectory within the tutorial repository on GitHub, so if you download it from there (as a ZIP archive or a git repository), you can experiment with the code.

In order to give you some additional insight about the handling of different kinds of variables, the next part(s) of the C++ with Qt tutorial will focus on this area.

I hope to see you around!