Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to push an unknown number of strings into a vector, but my cin loop doesn't terminate

Tags:

c++

cin

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?

like image 302
cluelessguy Avatar asked Jan 23 '19 07:01

cluelessguy


3 Answers

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] = /////
like image 130
Stack Danny Avatar answered Nov 12 '22 06:11

Stack Danny


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.

like image 33
lubgr Avatar answered Nov 12 '22 05:11

lubgr


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.

like image 1
Ivaylo Strandjev Avatar answered Nov 12 '22 05:11

Ivaylo Strandjev