C++ from the beginning, input and output

Chris Noring - Nov 5 '21 - - Dev Community

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

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";
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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));
}
Enter fullscreen mode Exit fullscreen mode
  • << "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 function to_string().
  • printf. Here you use the library cstdio 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);
Enter fullscreen mode Exit fullscreen mode
  • 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";
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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:

  1. Save the above code in a file app.cpp
  2. Compile the program with g++ app.cpp
  3. Run the program:
   ./a.out # macOS, Linux
   a.out.exe # windows 
Enter fullscreen mode Exit fullscreen mode

You should see the program running like so:

   what's your name? chris
   Hi chris
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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";
}
Enter fullscreen mode Exit fullscreen mode

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player