10

I am trying to take strings as input from cin, and then push the string into a vector each time. However, my loop doesn't terminate even when I put a '\' at the end of all my input.

int main(void) {
    string row;
    vector<string> log;
    while (cin >> row) {
        if (row == "\n") {
            break;
        }
        log.push_back(row);
    }
    return 0;
}

I've tried replacing the (cin >> row) with (getline(cin,row)), but it didn't make any difference. I've tried using stringstream, but I don't really know how it works. How do I go about resolving this?

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
cluelessguy
  • 101
  • 3

3 Answers3

10

As commented by @SidS, the whitespace is discarded. So you have to think about another strategy. You could instead check if row is empty. But that will only work with std::getline:

#include <vector>
#include <string>
#include <iostream>

int main() {
    std::string row;
    std::vector<std::string> log;
    while (std::getline(std::cin, row)) {
        if (row.empty()) {
            break;
        }
        log.push_back(row);
    }
    std::cout << "done\n";
}

OP, in case you want to save single words (rather than a whole line), you can use regex to single-handedly push each of them into log after input:

#include <vector>
#include <string>
#include <iostream>
#include <regex>

int main() {
    const std::regex words_reg{ "[^\\s]+" };

    std::string row;
    std::vector<std::string> log;
    while (std::getline(std::cin, row)) {
        if (row.empty()) {
            break;
        }
        for (auto it = std::sregex_iterator(row.begin(), row.end(), words_reg); it != std::sregex_iterator(); ++it){
            log.push_back((*it)[0]);
        }
    }
    for (unsigned i = 0u; i < log.size(); ++i) {
        std::cout << "log[" << i << "] = " << log[i] << '\n';
    }
}

Example run:

hello you
a b c d e f g
18939823
@_@_@ /////

log[0] = hello
log[1] = you
log[2] = a
log[3] = b
log[4] = c
log[5] = d
log[6] = e
log[7] = f
log[8] = g
log[9] = 18939823
log[10] = @_@_@
log[11] = /////
Stack Danny
  • 7,754
  • 2
  • 26
  • 55
  • Isn't the OP's original goal to store an individual token as a `std::string` in the container, rather than each line? There should be an additional step to split each row according to a given delimiter. – lubgr Jan 23 '19 at 08:06
  • @lubgr yeah you're right, I will add some regex for the curious, too – Stack Danny Jan 23 '19 at 08:11
  • @lubgr in fact I am not certain what is the original intent of the OP, as the variable name is row I think storing the whole line is more plausible – Ivaylo Strandjev Jan 23 '19 at 08:14
2

If you want to store the tokens of one line from std::cin, separated by the standard mechanism as in the operator>> overloads from <iostream> (i.e., split by whitespace/newline), you can do it like this:

std::string line;
std::getline(std::cin, line);
std::stringstream ss{line};

const std::vector<std::string> tokens{std::istream_iterator<std::string>{ss},
    std::istream_iterator<std::string>{}};

Note that this is not the most efficient solution, but it should work as expected: process only one line and use an existing mechanism to split this line into individual std::string objects.

lubgr
  • 37,368
  • 3
  • 66
  • 117
1

You can't read newline by using the istream& operator >> of string. This operator ignores whitespaces and will never return the string "\n". Consider using getline instead.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176