-1

I would like to fill a vector array with some lines but I don't get the same back. What is the problem with my code?

using namespace std;

vector<string> calling(int n){
    vector<string> file(n);
    int a=0;

    while(n){
       getline(cin,file[a]);
       cin.ignore();
       a++;
       n--;
    }
    return file;
}

int main() {
    int n;
    cin >> n;
    vector<string> hrml = calling(n);
    int a=0;
    while(n){
        cout << hrml[a] <<endl;
        a++;
        n--;
     }
     return 0;
}

The input:

3
aaaa aaa aa
bb b bbbb
c cc ccc

The output:

aaaa aaa aa
bb b bbbb
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Mat
  • 461
  • 4
  • 14

4 Answers4

1

You don't need std::cin.ignore() after getline() as the latter 'eats' the new line character from the stream. As per the getline() docs:

Extracts characters from input and appends them to str until one of the following occurs (checked in the order listed): (...)

b) the next available input character is delim, as tested by Traits::eq(c, delim), in which case the delimiter character is extracted from input, but is not appended to str.

You do need std::cin.ignore() after std::cin >> n though as by pressing enter you've put the newline character into the stream and it's going to get eaten by getline, which will return an empty string as a result.

KjMag
  • 2,650
  • 16
  • 16
1

@DimChtz answered your question, but I thought I'd show you how to use for loops since you seem to be fond of clunky while loops:

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

using namespace std;

vector<string> calling(int n)
{
    vector<string> file(n);

    //for loop
    for (int i=0; i<n; i++) {
        getline(cin, file[i]);
    }

    return file;
}

int main() {
    int n;
    cin >> n;
    cin.ignore();

    vector<string> hrml = calling(n);

    //for each loop (C++11)
    for (auto & str : hrml) {
        cout << str << endl;
    }

    return 0;
}
Gillespie
  • 5,780
  • 3
  • 32
  • 54
1

It's a combination of a few factors.

Reading the first number in the input, 3, doesn't move the "cursor" to the next line; it simply moves it past the number. When you next call getline, it returns a std::string of size 0, because it grabs the space between the end of the character and the end of the line, which is nothing.

Then, because you're using that number as an explicit number of strings to read, you're reading exactly 3 lines: "", "aaaa aaa aa", and "bb b bbbb".

Hence your output missing the line of 'c''s.

The simplest solution here is to force an extra call to getline before you call calling. (I've removed using namespace std; from your code because it's bad practice)

int main() {
    int n;
    std::cin >> n;
    std::string line;
    std::getline(std::cin, line);

Then, we can rewrite calling to not need an integer parameter:

std::vector<std::string> calling(){
    std::vector<std::string> file;
    std::string line;
    while(std::getline(std::cin, line)){
        file.push_back(std::move(line));
    }
    return file;
}

(If you're testing in your console, and you need something to mark the end of the line, use Ctrl+Z on Windows or Ctrl+D on UNIX.)

Which changes the calling line to this:

std::vector<std::string> hrml = calling();

Or this, if you're using C++11 (and don't mind the loss of explicitly visible type declaration):

auto hrml = calling();

And as long as we're here, we can write a better loop for printing the contents of our vector:

for(size_t i = 0; i < hrml.size(); i++) {
    std::cout << hrml[i] << std::endl;
}

Or, if we're using C++11:

for(std::string const& line : hrml) {
    std::cout << line << std::endl;
}

And, if you're allowed to change the format of your input file, we can ditch the reading of the number in the first place, yielding a much smaller and easier to debug program:

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

std::vector<std::string> calling(){
    std::vector<std::string> file;
    std::string line;
    while(std::getline(std::cin, line)) {
        file.push_back(std::move(line));
    }
    return file;
}

int main() {
    std::vector<std::string> hrml = calling();

    for(std::string const& line : hrml) {
        std::cout << line << std::endl;
    }
    return 0;
}
Xirema
  • 19,889
  • 4
  • 32
  • 68
  • What about using `std::cin.ignore(1000,'\n');` after reading the number? – Thomas Matthews Jul 25 '17 at 20:20
  • @ThomasMatthews There's nothing stopping you from doing that (... Except for input files whose lines are longer than 1000 characters...) but the code I've written is somewhat more idiomatic. – Xirema Jul 25 '17 at 20:22
1

This statement

cin >> n;

does not remove the new line character from the input buffer. As result the following call of the function getline reads an empty string until the new line character is encountered.

This statement in the function

cin.ignore();

does not make sense. You should place a similar statement after this statement

cin >> n;

Also if you are dealing with an object of type int you should check that it is not less than zero.

Taking this into account the program can look the following way.

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

using namespace std;

vector<string> calling( int n )
{
    vector<string> file;

    if ( n > 0 )
    {
        file.reserve( n );
        string s;

        while ( n-- && getline( cin, s ) ) file.push_back( s );
    }

    return file;
}

int main() 
{
    int n = 0;

    cin >> n;

    cin.ignore( numeric_limits<streamsize>::max(), '\n' );

    vector<string> hrml = calling(n);

    for ( const string &s : hrml ) cout << s << '\n';

    return 0;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335