During the CS 106L course, I learned a lot of C++ streams. This document describes how to use basic_stringstream
to get an integer from a string.
The basic unit of communication between a program and its environment is a stream. A stream is a channel between a source and destination which allows the source to push formatted data to the destination.
Overview of string stream
To create a string stream, we need to include the <sstream>
header file. Then, we can create a string stream object using the following code:
#include <sstream>
int main() {
std::istringstream iss("9.15 pounds.");
std::ostringstream oss("The price of the shirt is ");
}
For C++ beginners, we usually use std::cin
to get input from the user and use std::cout
to output something to the console. Here, std::cin
and std::cout
are both streams. The following is an example:
#include <iostream>
int main() {
int value;
std::cin >> value;
std::cout << value << std::endl;
}
In the preceding example, >>
is the stream extraction operator, and <<
is the stream insertion operator. For string streams, we also use >>
and <<
to extract and insert data.
To extract the price and unit from the string stream iss
, use the following code:
- Extract price (double) and unit
- Output
#include <iostream>
#include <sstream>
int main() {
std::istringstream iss("9.15 pounds.");
std::ostringstream oss("The price of the shirt is ");
double price;
std::string unit;
iss >> price >> unit;
std::cout << oss.str() << price << " " << unit << std::endl;
}
The price of the shirt is 9.15 pounds.
What is the behavior of iss >> price >> unit
? We can modify the type of price
to int
and see what happens:
- Extract price (int) and unit
- Output
#include <iostream>
#include <sstream>
int main() {
std::istringstream iss("9.15 pounds.");
std::ostringstream oss("The price of the shirt is ");
int price;
std::string unit;
iss >> price >> unit;
std::cout << oss.str() << price << " " << unit << std::endl;
}
The price of the shirt is 9 .15
The output shows that the value of price
is 9
, and the value of unit
is .15
. This is because the >>
operator will stop extracting data when it encounters a whitespace or an invalid character for the type. In this case, the >>
operator in iss >> price
stops extracting data at .
. Then, the >>
operator in iss >> unit
extracts .15
into unit
and stops extracting data at
.
Implement stringToInteger()
without error-checking
Now, we can use >>
to extract an integer from a string. Let's implement a function stringToInteger()
to convert a string to an integer. The code is as follows:
- Extract an integer from a string
- Output
#include <iostream>
#include <sstream>
int stringToInteger(const std::string& str) {
std::istringstream iss(str);
int value;
iss >> value;
return value;
}
int main() {
std::string str = "123";
int value = stringToInteger(str);
std::cout << "The value is: " << value << std::endl;
}
The value is: 123
Stream state
What if the string contains invalid characters? For example, the string "123abc"
contains non-numeric characters. In this case, the >>
operator stops extracting data at a
. Then, the value of value
will be 123
. However, we want to return an error message to the user. To do this, we need to check whether any error occurs during the extraction process.
A new concept is introduced here: stream state. There are four stream states:
- good: no error occurs. The I/O operations are available.
- eof: reaching the end of the stream.
- fail: the input/output operation failed and all future operations frozen, such as the type mismatch.
- bad: irrecoverable stream error. For example, the file you are reading is deleted suddenly.
To check the stream state, we can use the good()
, eof()
, fail()
, and bad()
functions. The following shows some examples:
- Check stream state
- Output
#include <iostream>
#include <sstream>
#include <vector>
void get_stream_state(std::istringstream &iss) {
if (iss.good()) {
std::cout << "G";
}
if (iss.eof()) {
std::cout << "E";
}
if (iss.fail()) {
std::cout << "F";
}
if (iss.bad()) {
std::cout << "B";
}
std::cout << std::endl;
}
int stringToInteger(const std::string &str) {
std::istringstream iss(str);
std::cout << "Before: ";
get_stream_state(iss);
int value;
iss >> value;
std::cout << "After: ";
get_stream_state(iss);
return value;
}
int main() {
std::vector<std::string> test_strings{"123", "123abc", "abc123", ""};
for (const auto &str : test_strings) {
std::cout << "stringToInteger(\"" << str << "\"):\n"
<< stringToInteger(str) << std::endl;
}
}