Commit 6a5296f9 authored by ROUVREAU Vincent's avatar ROUVREAU Vincent
Browse files

Fix typo

parent 31d60d58
%% Cell type:markdown id: tags:
# [Getting started in C++](/) - [Procedural programming](./0-main.ipynb) - [Input and output streams](./6-Streams.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Predefined-streams" data-toc-modified-id="Predefined-streams-1">Predefined streams</a></span><ul class="toc-item"><li><span><a href="#std::cout" data-toc-modified-id="std::cout-1.1"><code>std::cout</code></a></span></li><li><span><a href="#std::cerr" data-toc-modified-id="std::cerr-1.2"><code>std::cerr</code></a></span></li><li><span><a href="#std:cin" data-toc-modified-id="std:cin-1.3"><code>std:cin</code></a></span></li></ul></li><li><span><a href="#Input/output-with-files" data-toc-modified-id="Input/output-with-files-2">Input/output with files</a></span><ul class="toc-item"><li><span><a href="#getline()" data-toc-modified-id="getline()-2.1"><code>getline()</code></a></span></li></ul></li><li><span><a href="#ostream-and-istream" data-toc-modified-id="ostream-and-istream-3"><code>ostream</code> and <code>istream</code></a></span></li><li><span><a href="#Conversion" data-toc-modified-id="Conversion-4">Conversion</a></span></li><li><span><a href="#Formatting-and-manipulators" data-toc-modified-id="Formatting-and-manipulators-5">Formatting and manipulators</a></span></li></ul></div>
%% Cell type:markdown id: tags:
## Predefined streams
The standard C++ includes an input/output library that specifies a common interface for all data exchanges with the outside world, based in particular on the insertion `<<` and extraction `>>` operators.
### `std::cout`
We have already dealt profusely with `std::cout` which provide the link to the Unix channel `stdout`:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
std::cout << "Hello world!" << std::endl;
}
```
%%%% Output: stream
Hello world!
%% Cell type:markdown id: tags:
### `std::cerr`
There is also `std::cerr`, which is related to Unix `stderr`:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int n = -4;
if (n < 0)
std::cerr << "Positive or null value expected!" << std::endl;
}
```
%%%% Output: stream
Positive or null value expected!
%% Cell type:markdown id: tags:
### `std:cin`
And finally `std::cin`, related to Unix channel `stdin`. Line crossings are ignored (assimilated to spaces and tabs).
**WARNING** This works only with a recent version of Xeus-cling.
%% Cell type:code id: tags:
``` C++17
#include <random>
#include <iostream>
{
std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(0, 100);
auto hidden = dis(gen);
int guess = -1;
while (guess != hidden)
{
std::cout << "Find the value between 0 and 100: ";
std::cin >> guess;
if (guess > hidden)
std::cout << " Too high!" << std::endl;
else if (guess < hidden)
std::cout << " Too low!" << std::endl;
}
std::cout << "Congratulations! You have found the hidden number!" << std::endl;
}
```
%%%% Output: stream
Find the value between 0 and 100:
%%%% Output: stream
50
%%%% Output: stream
Too low!
Find the value between 0 and 100:
%%%% Output: stream
75
%%%% Output: stream
Too high!
Find the value between 0 and 100:
%%%% Output: stream
65
%%%% Output: stream
Too low!
Find the value between 0 and 100:
%%%% Output: stream
70
%%%% Output: stream
Too high!
Find the value between 0 and 100:
%%%% Output: stream
68
%%%% Output: stream
Too high!
Find the value between 0 and 100:
%%%% Output: stream
66
%%%% Output: stream
Congratulations! You have found the hidden number!
%% Cell type:markdown id: tags:
`std::cin` is a bit more tricky to use that the others, as the risk the operation fails is really higher. For instance, if you give a string in the code above it will become crazy and keep printing the same message "Too high!" or "Too low!" (be ready to restart the kernel...). The following code fixes this:
`std::cin` is a bit more tricky to use than the others, as the risk the operation fails is really higher. For instance, if you give a string in the code above it will become crazy and keep printing the same message "Too high!" or "Too low!" (be ready to restart the kernel...). The following code fixes this:
%% Cell type:code id: tags:
``` C++17
#include <random>
#include <iostream>
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(0, 100);
auto hidden = dis(gen);
int guess = -1;
while (guess != hidden)
{
do
{
if (!std::cin)
{
std::cin.clear(); // clear the states of std::cin, putting it back to `goodbit`.
std::cin.ignore(10000, '\n'); // clean-up what might remain in std::cin before using it again.
}
std::cout << "Find the value between 0 and 100: ";
std::cin >> guess;
} while (!std::cin);
if (guess > hidden)
std::cout << " Too high!" << std::endl;
else if (guess < hidden)
std::cout << " Too low!" << std::endl;
}
std::cout << "Congratulations! You have found the hidden number!" << std::endl;
}
```
%%%% Output: stream
Find the value between 0 and 100:
%%%% Output: stream
kd
%%%% Output: stream
Find the value between 0 and 100:
%%%% Output: stream
dlk
%%%% Output: stream
Find the value between 0 and 100:
%%%% Output: stream
50
%%%% Output: stream
Too low!
Find the value between 0 and 100:
%%%% Output: stream
75
%%%% Output: stream
Too low!
Find the value between 0 and 100:
%%%% Output: stream
87
%%%% Output: stream
Too high!
Find the value between 0 and 100:
%%%% Output: stream
82
%%%% Output: stream
Too high!
Find the value between 0 and 100:
%%%% Output: stream
78
%%%% Output: stream
Too low!
Find the value between 0 and 100:
%%%% Output: stream
80
%%%% Output: stream
Congratulations! You have found the hidden number!
%% Cell type:markdown id: tags:
If you want to learn more about `std::cin`, you might want to look at [this post](https://stackoverflow.com/questions/5131647/why-would-we-call-cin-clear-and-cin-ignore-after-reading-input) on StackOverflow.
If you need to use it extensively, you should look more deeply the behaviour of the bit flags (`goodbit`, `badbit`, `failbit`, `eofbit`).
%% Cell type:markdown id: tags:
## Input/output with files
The same syntax with operators `<<` and `>>` may be used to interact with files; the streams are built with `std::ofstream` for an output stream and `std::ifstream` for an input stream.
%% Cell type:code id: tags:
``` C++17
#include <fstream> // for std::ifstream and std::ofstream
#include <iostream>
{
std::ofstream out("File.tmp");
out << 5 << std::endl;
out << -7 << std::endl;
out << 9 << std::endl;
out.close(); // file is written on disk when closed; automatically done when `out` gets out of scope otherwise
std::ifstream in("File.tmp");
int value;
while (in >> value)
std::cout << value << std::endl;
}
```
%%%% Output: stream
5
-7
9
%% Cell type:markdown id: tags:
### `getline()`
When reading a file, if you want to interpret it line by line you should also consider `getline()`; this function may get a third argument to choose which separator to use (`\n` by default).
%% Cell type:code id: tags:
``` C++17
#include <iostream>
#include <fstream>
#include <string>
{
std::ifstream in("File.tmp"); // assumes previous cell has been played recently!
std::string line;
while (getline(in, line))
std::cout << line << std::endl;
}
```
%%%% Output: stream
5
-7
9
%% Cell type:markdown id: tags:
## `ostream` and `istream`
If you want to devise a function that may take as argument either a `std::cout` or a `std::ofstream`, you should use a `std::ostream` (we'll study [later](../2-ObjectProgramming/6-inheritance.ipynb) why this works but just take my word for now):
%% Cell type:code id: tags:
``` C++17
#include <iostream>
void PrintOnStream(std::ostream& out)
{
out << "Printed on the chosen stream!" << std::endl;
}
```
%% Cell type:code id: tags:
``` C++17
PrintOnStream(std::cout);
```
%%%% Output: stream
Printed on the chosen stream!
%% Cell type:code id: tags:
``` C++17
#include <string>
#include <fstream>
{
std::ofstream out("test_stream.txt");
PrintOnStream(out);
}
```
%% Cell type:code id: tags:
``` C++17
{
// Read the content of the line previously written.
std::ifstream in("test_stream.txt");
std::string line;
getline(in, line);
std::cout << line << std::endl;
}
```
%%%% Output: stream
Printed on the chosen stream!
%% Cell type:markdown id: tags:
## Conversion
Stream syntax was until C++ 11 the only way to convert:
- A string into a number with `std::istringstream`
- A number into a string with `std::ostringstream`; the `str()` method returns the content as a `std::string`.
%% Cell type:code id: tags:
``` C++17
#include <sstream> // for std::ostringstream and std::istringstream
#include <string>
{
std::string number_as_string = "657";
int number;
std::istringstream iconv(number_as_string);
iconv >> number;
std::cout << "Number + 1 = " << number + 1 << std::endl;
}
```
%%%% Output: stream
Number + 1 = 658
%% Cell type:code id: tags:
``` C++17
#include <sstream> // for std::ostringstream and std::istringstream
#include <string>
{
int number = 657;
std::ostringstream oconv;
oconv << "The number is " << number;
std::cout << oconv.str() << std::endl;
}
```
%%%% Output: stream
The number is 657
%% Cell type:markdown id: tags:
To reuse a `std::ostringstream`, you must set its content to an empty string with an overloaded `str()`:
%% Cell type:code id: tags:
``` C++17
#include <sstream> // for std::ostringstream and std::istringstream
#include <string>
{
int number = 657;
std::ostringstream oconv;
oconv << "The number is " << number;
std::cout << oconv.str() << std::endl;
oconv.str(""); // reset oconv
oconv << "My new content is now there!";
std::cout << oconv.str() << std::endl;
}
```
%%%% Output: stream
The number is 657
My new content is now there!
%% Cell type:markdown id: tags:
In C++ 11, `std::to_string()` and the [`stoi` (and similar functions for long, ](https://en.cppreference.com/w/cpp/string/basic_string/stol) were introduced to provide similar functionality with a more direct syntax:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
#include <string>
{
int number = 657;
std::string int_to_string("Number is ");
int_to_string += std::to_string(number);
std::cout << int_to_string << std::endl;
}
```
%%%% Output: stream
Number is 657
%% Cell type:code id: tags:
``` C++17
#include <iostream>
#include <string>
{
std::string number_as_string = "4557";
int number = stoi(number_as_string);
std::cout << "Number is " << number << std::endl;
}
```
%%%% Output: stream
Number is 4557
%% Cell type:markdown id: tags:
It is however useful to be aware of the pre-C++ 11 syntax, especially for the number to string conversion: 'arithmetic' operations between strings as `+` incur copies that are avoided with the `std::ostringstream` syntax.
%% Cell type:markdown id: tags:
## Formatting and manipulators
You may act upon the exact formatting of the output
I'll be honest: it's not what is the most refined tool in the C++ library, and you may long for the simplicity and power of something like Python (or even C `printf`, which while being a mess under the hood is much simpler to use...).
The difficulty is that some settings apply only to the next entry onto the stream (`width` here), while others change the behaviour permanently (until told otherwise of course, e.g. `precision` here). Here are few examples of these syntaxes:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
std::cout.setf(std::ios::showpos); // Add the `+` sign explicitly
std::cout.setf(std::ios::fixed, std::ios::floatfield); // use decimal notation only
std::cout.precision(2); // number of decimal digits
std::cout.width(8) ;
std::cout << 1.237 ;
std::cout.width(8) ;
std::cout << 100.1245 ;
std::cout.width(8) ;
std::cout << '\n' ;
std::cout.width(8) ;
std::cout << 1.5774e-2 ;
std::cout.width(8) ;
std::cout << 12. << '\n' ;
}
```
%%%% Output: stream
+1.24 +100.12
+0.02 +12.00
%% Cell type:markdown id: tags:
**Manipulators** provide a shorter syntax to add some of the properties as the `width` or the `precision`:
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
std::cout.setf(std::ios::showpos); // Add the `+` sign explicitly
std::cout.setf(std::ios::fixed, std::ios::floatfield); // use decimal notation only
std::cout << std::setprecision(2) << std::setw(8) << 1.237;
std::cout << std::setw(8) << 100.1245;
std::cout << '\n';
std::cout << std::setw(8) << 1.5774e-2;
std::cout << std::setw(8) << 12. << '\n';
}
```
%%%% Output: stream
+1.24 +100.12
+0.02 +12.00
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2020_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment