fittaoee
fittaoee

Reputation: 145

C++: Reading lines of integers from cin

As I'm familiarizing myself with the I/O aspect of C++, I'm trying to write a program to read some lines of integers from std::cin. Say the input looks like this:

1 2 3
4 5 6
7 8 9
10 11 12

How can I read the above lines into a 2D vector?

vector<vector<int>> nums;
/* 
 ... some code here and nums will look like the following:
 nums = {
    {1,2,3},
    {4,5,6},
    {7,8,9},
    {10,11,12}
  }
*/

I've also tried to read the above lines of integers to a 1D vector, but I'm having some issues dealing with the '\n' character. My code is:

string rawInput;
vector<int> temp;
while(getline(cin, rawInput, ' ') ){
  int num = atoi( rawInput.c_str() );
  temp.push_back(num);
 }

And the final result I got by printing out all the elements in the "temp" vector is:

1 2 3 5 6 8 9 11 12   // 4, 7, 10 went missing

Any help is appreciated. Thank you.

Upvotes: 1

Views: 9250

Answers (5)

Andreas
Andreas

Reputation: 5301

Suprisingly none of the answers use the istream stream operator: http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/

When stream is empty eofbit is set, so run a while loop on that.

Works great for all types, and can be overloaded for custom types (such as 2D texture).

Upvotes: 0

SolaGratia
SolaGratia

Reputation: 309

I recently wrote an answer to another question but with a few adaptations it achieves exactly what you are looking for (I hope):

#ifndef _IOSTREAM_H
#include <iostream>
#endif
#ifndef _STRING_H
#include <string>
#endif
#ifndef _VECTOR_H
#include <vector>
#endif

using namespace std;

enum XYZ { X = 0, Y = 1, Z = 2 };

struct Vector {
    float x, y, z;
    Vector(float _x=0, float _y=0, float _z=0) {
        x = _x;
        y = _y;
        z = _z;
    }
    float& operator[](size_t index) {
        if (index == XYZ::X) return x;
        if (index == XYZ::Y) return y;
        if (index == XYZ::Z) return z;
        throw new exception;
    }
};



#define min(a, b) (((a) < (b)) ? (a) : (b))

bool isCharNumeric(char c) {
    const char* numbers = "0123456789";
    for (size_t index = 0; index < strlen(numbers); index++)
        if (c == numbers[index]) return true; return false;
}

vector<Vector> parseNumbers(string str_in) {
    str_in += "  "; //safe, no out of bounds
    vector<Vector> results = {};
    char currentChar;
    char skipChar = ' ';
    bool found_period = false;
    size_t count_len = 0;
    Vector vector_buffer(0,0,0);
    XYZ current_axis = (XYZ)0;
    for (size_t index = 0; index < str_in.length(); index++) {
        currentChar = str_in[index];
        if (currentChar == skipChar || currentChar == '\n' || currentChar == '\t')
            continue;

        else if (isCharNumeric(currentChar)) {
            string word = ""; //word buffer
            size_t word_len = min(min(str_in.find_first_of(' ', index + 1) - (index), str_in.find_first_of('\n', index + 1) - (index)), str_in.find_first_of('\t', index + 1) - (index)); //whatever char comes first; newline, tab or space
                                                                                                                                                              //append chars of following word checking if it is still valid number char
            if (word_len > 0) {
                size_t count_word_len = 0;
                for (count_word_len = 0; count_word_len < word_len; count_word_len++)
                    if (isCharNumeric(str_in[index + count_word_len])) {
                        word += str_in[index + count_word_len];
                    }
                    else if (str_in[index + count_word_len] == '.' && isCharNumeric(str_in[index + count_word_len + 1])) {
                        //Floating-point numbers
                        word += '.';
                        found_period = true;
                        continue;
                    }
                    else {
                        word = "";
                        continue;
                    }

                    vector_buffer[current_axis] = stof(word);


                    if (current_axis == XYZ::Z) {
                        current_axis = XYZ::X;
                        results.push_back(vector_buffer);
                    }
                    else {
                        current_axis = (XYZ)(current_axis + 1);
                    }


                    index += count_word_len;
                    word = "";
                    continue;
            }

        }
    }
    return results;
}

Example implementation:

int main(int argc, char** argv) {
    string user_input;
    cin >> user_input;
    vector<Vector> numbers = parseNumbers(user_input);
    for each (Vector v in numbers) {
        cout << "X=" << v.X << "\n";
        cout << "Y=" << v.Y << "\n";
        cout << "Z=" << v.Z << "\n\n";
    }
}

Upvotes: 0

bashrc
bashrc

Reputation: 4835

What is happening is since you are using only ' '(space) as deliminator, the input happens to be

1
2
3\n4 //<------ Newline also comes with the input

...

So, you are passing 3\n4, 6\n7 etc to atoi it returns 3,6 etc(atoi parses the input till first non-digit input) and the 4,7 is lost.

To achieve want you want you can use getline with istringstream (keeping the default deliminator as newline)

string rawInput;
vector<vector<int>> temp;
while(getline(cin, rawInput) ){
  istringstream bufferInput(rawInput); 
  temp.push_back(vector<int>{std::istream_iterator<int>{bufferInput}, std::istream_iterator<int>{}});
}

Upvotes: 2

Ryan Haining
Ryan Haining

Reputation: 36882

First use getline to grab an entire line, then you can use a istringstream to create a stream of ints just for that line.

At that point it's just a matter of creating each subvector of ints using the vector constructor that takes two iterators. An istream_iterator<int> on your istringstream gets this done:

std::vector<std::vector<int>> nums;
std::string line;
while (std::getline(std::cin, line)) {
    std::istringstream ss(line);
    nums.emplace_back(std::istream_iterator<int>{ss}, std::istream_iterator<int>{});
}

Upvotes: 2

ahmed_kamal1432
ahmed_kamal1432

Reputation: 49

you can use stringstream

string rawInput;
vector<int> temp;
stringstream ss;

while(getline(cin,rawInput)){
  ss<<rawInput;
  vector<int> temp;
  int x;
  
  while(ss>>x){
    temp.push_back(x);
  }
  
  num.push_back(temp)
}

Upvotes: 1

Related Questions