Chris Noring
Posted on November 5, 2021
TLDR; this is part of the C++ from the beginning series. This part is about how to write a program that reads and writes to the console.
The full series
- Your first program
- Variables
- Working with input and output, you are here
- Functions
- Control flow
- Working with files
- Pointers
- Error management
- Structs and Classes
References
Here's some useful links to learn more:
Why console programs
Console programs are programs that work on the console, they have no user interface, but they are still heavily used and useful. No UI you say, how's that good? Well, console programs are fast, really fast. Additionally, they are easier to script and used in the context of a build server, if you need to send in args automatically and listen to the input as part of a build step, if you are practicing CI/CD for example.
Writing to the console
Ok, we know why console programs can be a good idea sometimes. How would I output to the console? There are many libraries that does that for you but two common alternatives are:
- iostream, stream-based library that's considered more C++.
- cstdio, more C-style formatting. Has similar functionality to iostream but some say it has issues like not checking interpolation properly and yea iostream being more future safe.
Your first output
To create a program that output to the console, you need iostream
and you need cout
like so:
#include <iostream>
using namespace std;
int main()
{
cout << "Print this";
}
Note how you use cout
and the stream operator that takes the <<
operator meaning it writes to a stream that's going to console.
Mixing types
Ok, so you mostly likely want to combine numbers and strings, like saying for example the sum is 8. How would you do that? The answer is to use the stream operator <<
to separate the two different data types like so:
#include <iostream>
using namespace std;
int main()
{
int sum = 8;
cout << "The sum is " << sum;
}
Is that the only way to do things, what if I want to write something like, "this program has run for 8 days", a clear mixture of string, int and string again, do I have to use <<
many times? There are a few different options, as illustrated in the below code:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int sum = 8;
cout << "The sum is " << sum << "\n";
cout << "This program has been running for " + to_string(sum) + "days";
printf("The program has been running for %d days", sum);
cout << format("The program has been running for {0} days", to_string(days));
}
-
<< "string" << number << "string"
. This is the version you've seen so far, separating different data types by<<
. -
"string" + to_string(number)
. In this version you concatenate string by first converting your number using the functionto_string()
. -
printf
. Here you use the librarycstdio
a c-style library that interpolates, allows you to mix strings and numbers by using a placeholder {0}. The 0 says what position it has as an argument, example:
printf("Here's a number {0}, and another one", 3, 5);
-
format()
. Here we are using a function introduced in C++ 20. Ensure you have upgraded C++ to be able to use this one.
Formatted output
There's a library iomanip
that enables you to format the output and with it you can do things such as:
- set alignment, you can decide on whether to align what you print to the left or to the right
- set width, you can have what you print take up N characters, thereby you can print output like a table
Here's an example program using many of iomanips
features:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setw(10) << "row1col1" << setw(20) << "row1col2" << "\n";
cout << setw(10) << "row2col1" << setw(20) << "row2col2" << "\n";
}
We have setw()
, set width, that's used to create two difference columns. Where you to run this, you get the following output:
row1col1 row1col2
row2col1 row2col2
There's more functionality than that, have a look at the "references" section at the top of the article.
Reading from the console
To read from the console, we can use cin
from iostream
. You use it like so:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string name;
cout << "what's your name? ";
cin >> name;
cout << "Hi " << name << endl;
return 0;
}
Here, cin >> name
, waits for the user to type a string and then a return key. Then the value will be stored in name
.
Lastly we type the value. To try this demo, take the following steps:
- Save the above code in a file app.cpp
- Compile the program with
g++ app.cpp
- Run the program:
./a.out # macOS, Linux
a.out.exe # windows
You should see the program running like so:
what's your name? chris
Hi chris
Multiple inputs
Imagine you have a situation where you need to collect multiple inputs. In the below program we have a calculation program:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no, no2;
cout << "--Add two numbers--\n";
cout << "First number: ";
cin >> no;
cout << "Second number: ";
cin >> no2;
cout << "The sum is: " << no + no2 << "\n";
return 0;
}
In the above code, you ask for one number, then the next. But what if you want to collect everything on one row? We can do that, just change the code to the following:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no, no2;
cout << "--Add two numbers--\n";
cout << "Input numbers (separated by space): ";
cin >> no >> no2;
cout << "The sum is: " << no + no2 << "\n";
return 0;
}
Note the row cin >> no >> no2;
where you separate the user input by >>
. The reason we do it like that is that cin
only takes the first value until the first space.
Another approach we could use is getline()
that reads the whole row, like in the below code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int sum;
string s_numbers;
cout << "--Add numbers--\n";
cout << "Input numbers (separated by space): ";
getline(cin, s_numbers);
// add code to split and convert numbers to int
cout << "The sum is: " << sum << "\n";
return 0;
}
getline()
reads the whole line, regardless of whether you use a space character or not. However, now you are in a situation where you need to parse s_numbers
because that line is stored as a string. How to fix?
First we need a split function:
vector<int> split(const string line, char delimiter)
{
stringstream ss(line);
string item;
vector<int> numbers;
while(getline(ss, item, delimiter))
{
numbers.push_back(stoi(item));
}
return numbers;
}
First thing we do is to read line
, that came from user input, into a stringstream
object. Imagine the user did an input that looks like so "1 2 3 4";
Now we iterate over the stringstream object using a while construct. This enables us to read every substring in that user string, so for each iteration you get "1" "2" "3" "4". However we need to convert that to an int, which we do with stoi()
, that takes a string and turns it into an int. Additionally we need to add each value to numbers
of type vector
(vector is a dynamic list that can take any number of items).
Ok, we solved half the problem. We now need to summarise the values in the vector, like so:
int sumNumbers(vector<int> v)
{
int sum = 0;
for(int i=0; i< v.size(); i++)
{
sum += v[i];
}
return sum;
}
Great, so we have something loops through the vector and we end up with an integer. Now for the full program:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
vector<int> split(const string line, char delimiter)
{
stringstream ss(line);
string item;
vector<int> numbers;
while(getline(ss, item, delimiter))
{
numbers.push_back(stoi(item));
}
return numbers;
}
int sumNumbers(vector<int> v)
{
int sum = 0;
for(int i=0; i< v.size(); i++)
{
sum += v[i];
}
return sum;
}
int main()
{
string s_numbers;
cout << "--Add numbers--\n";
cout << "Input numbers (separated by space): ";
getline(cin, s_numbers);
vector<int> numbers = split( s_numbers, ' ' );
cout << "Sum is: " << sumNumbers( numbers ) << "\n";
}
You were taken through cin
and getline
and as you saw, sometimes it's easier to just use cin
with a few operators >>
if the number of inputs are know. However, if we need to the user to write an unknown number of inputs, we need to write more code and use constructs like stringstream and vector to be able to handle it.
Summary
That was it for this article. Input and output using iostream and iomanip can take you far and with stringstream and vector you can go even further and create programs that are flexible too.
Posted on November 5, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.