Step 1 of 6
Parsing with istringstream
std::cin reads from the keyboard (or piped input). But a lot of text you need to parse is already sitting in a std::string: a line you just read, a command, a config value. A std::istringstream (from <sstream>) wraps a string so you can read from it exactly like std::cin.
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string line;
while (std::getline(std::cin, line)) {
std::istringstream in(line);
std::string item;
int qty;
double price;
if (!(in >> item >> qty >> price)) {
std::cout << "skipping bad line: [" << line << "]\n";
continue;
}
std::cout << item << " costs " << qty * price << "\n";
}
}
pen 3 1.5
oops
book 2 12
pen costs 4.5
skipping bad line: [oops]
book costs 24
Why read a line first?
std::cin >> x skips over newlines, so it can't tell where one line ends and the next begins. When the line structure matters (one record per line, a variable number of values per line), use this two-step pattern:
std::getline(std::cin, line)reads one whole line into a string (without the newline).- A fresh
std::istringstream in(line)parses just that line. When it runs out, you know the line is done.
Reading until the data runs out
A stream converts to false once a read fails. So this loop reads every number on a line, however many there are, including zero:
int x;
while (in >> x) { /* use x */ }
The loop also stops at something that isn't a number, like the word abc.
Common mistakes
- Reusing one
istringstreamfor several lines. After it hits the end, it's in a failed state. Create a new one inside the loop, as above. - Mixing
std::cin >> nwithstd::getline. The>>leaves the newline behind, so the nextgetlinereturns an empty line.
Your task
Each input line holds a player name followed by some round scores (possibly none). For each line print NAME TOTAL.
Challenge 2
Each line holds a player name followed by some round scores (maybe none). Print the name and the best score, or the name and - if there are no scores. Parse each line with a std::istringstream.
Challenge 3
Each line is a CSV row name,kills,deaths. Print name diff with the kills minus the deaths. Skip lines that don't have all three fields as numbers. Read the name up to the comma with std::getline(in, name, ','), then the numbers with >>, reading each comma into a char.