user2016393
user2016393

Reputation: 55

Cannot output vector<string> to a file

I am new to C++. I am having trouble outputting data to a file. I am using an iterator to print out a map. The print method takes i, a key value, and prints out it's corresponding vector. Now, this works perfectly fine when I output normally using cout<< but when I try to put the same output into a file, my program crashes. I know it is the *it that in the outfile<< line that is crashing it, because if I replace it with some random string it outputs it to the file fine. Also, I know the parameters in the print method are not causing any problems, because I can transfer that method directly to the main function of the program and get the same error. Any help would be greatly appreciated on how to fix this, thank you! Here is my print method where the error is happening:

    public: void print(int i, vector<string> in, ostream& outfile) // print method for printing a vector and it's key
{

    sort(in.begin(), in.end()); // sort the vector alphabetically first

    vector<string>::iterator it; 

    it= unique(in.begin(), in.end()); // makes sure there are no duplicate strings

    in.resize( distance(in.begin(),it) );

    for( it = in.begin(); it != in.end(); it++ ) // iterate through it

    cout << i << ": "<< *it<<endl; // and print out the key value and each string in the vector
   // outfile<< i << ":" << *it<< endl; // prints to file
}

Upvotes: 2

Views: 475

Answers (2)

Andy Prowl
Andy Prowl

Reputation: 126442

@slugonamission already gave you the correct answer, so I'm just going to point out that your function can actually be simplified and made less error-prone. I am writing this as an answer just because code formatting is required, otherwise I would post it in a comment:

void print(int i, vector<string> v, ostream& o)
{
    sort(begin(v), end(v));
    v.erase(unique(begin(v), end(v))); // Do this in one step, no iterator mess
    for (auto const& s : v) // Avoid manual iteration cycles if you can
    {
        o << i << ":" << s << endl;
        ...
    }
}

EDIT:

As @juanchopanza correctly points out, an even quicker way to achieve the same would be to transfer the vector's content into an associative container to ensure uniqueness. This would allow you to pass the vector by const &:

void print(int i, vector<string> const& v, ostream& o)
{
    unordered_set<string> c(begin(v), end(v));
    for (auto const& s : c)
    {
        o << i << ":" << s << endl;
    }
}

Upvotes: 2

slugonamission
slugonamission

Reputation: 9642

Are you using the cout line at the same time? If so, I think I know what it is.

The for loop, without braces will execute the next statement as its loop body. If you use both the cout line and the outfile line, you will print everything, then after the loop, it will be located just past the end of the array. You then try and dereference this and write it to a file, which of course fails since you're dereferencing an invalid iterator.

Short answer, wrap the statements in your for loop with braces.

For example, you have the following (when indented properly):

for( it = in.begin(); it != in.end(); it++ ) // iterate through it
    cout << i << ": "<< *it<<endl; 
outfile<< i << ":" << *it<< endl; // prints to file

On the last line of that, it = in.end(), where in.end() is the element just past the end of the vector. You then try and access the element at that location which doesn't exist (and is invalid), and hence it fails. Instead, you need to move that inside the loop, which should read

for( it = in.begin(); it != in.end(); it++ ) // iterate through it
{
    cout << i << ": "<< *it<<endl; // and print out the key value and each string in the vector
    outfile<< i << ":" << *it<< endl; // prints to file
}

Upvotes: 2

Related Questions