Search code examples
c++vectorifstream

why using a ifstream object twice causes error?


I want to output the times that a words occurs in a text and output the lines that contains the word, but when I output vector[*beg] I found that vector is empty!

I think the problem lie in using ifstream &ifs twice:

auto wordMap=setMap(ifs);
std::vector<std::string> vvector = read_to_vector(ifs);

If I exchange the two statements, it broke down immediately

I want to know where the problem lies and how to solve.

#include <iostream>
#include<vector>
#include <fstream>
#include <string>
#include <set>
#include <map>
#include <sstream>
#include <memory>

std::vector<std::string> read_to_vector(std::ifstream &ifs)
{
    std::string lines;
    std::vector<std::string> sentences;
    while (std::getline(ifs, lines))
    {
        sentences.push_back(lines);
    }
    return sentences;
}


std::map<std::string,std::set<size_t>> setMap(std::ifstream &ifs)
{
    std::vector<std::string> word_vector = read_to_vector(ifs);
    std::string lines, words;
    std::map < std::string, std::set<size_t> > word_map;
    for (size_t i = 0; i < word_vector.size(); i++)
    {
        //i is the current line_num
        std::istringstream stream(word_vector[i]);
        while (stream >> words)
        {
            word_map[words].insert(i);
        }
    }
    return word_map;
}
void print(std::ifstream &ifs)
{
    auto wordMap=setMap(ifs);
    std::vector<std::string> vvector = read_to_vector(ifs);
    std::string search;
    std::cout << "please input the word that you wanna search" << "\n";
    std::cin >> search;
    auto findw = wordMap.find(search);
    if (findw != wordMap.cend())
        std::cout << search << " occurs " << findw->second.size() 
                  << " times : " << std::endl;
    std::set<size_t> lineNum = findw->second;
    //it is a set
    auto beg = lineNum.begin();
    while (beg != lineNum.end())
    {
        std::cout << *beg;
        //std::cout<<vvector[*beg];
        beg++;
    }   
    for (auto c : vvector)
        std::cout << c << std::endl;

    if (vvector.empty())
        std::cout << "vector is empty!";
    //WTF!!! vector is empty!!!
}

int main()
{
    std::ifstream ifs;
    ifs.open("text.txt",std::ios::in);
    print(ifs);
    ifs.close();
}

Solution

  • When you call read_to_vector for first time (in setMap) it reaches to the end of file, so when next time you call it(in print), vector will be empty. reset the cursor before reading the lines in read_to_vector. Change it to:

    std::vector<std::string> read_to_vector(std::ifstream &ifs)
    {
       ifs.seekg (0, ifs.beg);//add this
       std::string lines;
       std::vector<std::string> sentences;
       while (std::getline(ifs, lines))
       {
          sentences.push_back(lines);
       }
       return sentences;
    }
    

    Suggestion

    I think it's better read the file once and then pass the vector around:

    std::map<std::string,std::set<size_t>> setMap(std::vector<std::string> word_vector )
    {
       //std::vector<std::string> word_vector = read_to_vector(ifs);
       std::string lines, words;
       std::map < std::string, std::set<size_t> > word_map;
       //some code
    }
    

    and then

    void print(std::ifstream &ifs)
    {
        std::vector<std::string> vvector = read_to_vector(ifs);
        auto wordMap=setMap(vvector);
    
        // some code
    }