vipin
vipin

Reputation: 43

C++ Vector iteration failing for single element input

I am trying to get a txt file with entries part1/1 part2/4 etc... from user and store in vectors "part_name" and "rev_id". So "part_name" contains part1 part2 ... and "rev_id" contains 1 4..... The program is run as program.exe list.txt in command prompt.

The program works fine when the txt file has 2 or more inputs , but when it has single input the vector size is shown as 2 (but must be 1).
i.e.

if list.txt contains part1/1 part2/4 => part_name.size() is 2

if list.txt contains part1/1 => part_name.size() is still 2.

Can someone help me resolve this ?

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;

int main(int argc, char*argv[])
{

std::string s ;
std::string delimiter = "/";
size_t pos;
std::vector<std::string> part_name;
std::vector<std::string> rev_id;
std::string token1,token2;


ifstream readFile (argv[1]);
if (readFile.is_open()) 
{
 while (!readFile.eof()) 
{
    readFile >> s;
    pos=s.find(delimiter);
    if((pos!=std::string::npos)&&(pos!=0))
    {

    token1 = s.substr(0, s.find(delimiter));
    token2 = s.substr(pos + delimiter.length());

    part_name.push_back(token1);
    rev_id.push_back(token2);
    }
 }
}
else{

   std::cout<<"Cannot open file"<<endl;
}
readFile.close();

  for (unsigned j=0; j < part_name.size(); j++)
 {
    cout<<part_name.size()<<endl;
    cout<<"part name j is " <<part_name[j]<<endl;
    cout<<"part id j is " <<rev_id[j]<<endl;
 }


}

Upvotes: 0

Views: 68

Answers (4)

MaxP
MaxP

Reputation: 3044

eof() returns true not when the file position is at the end, but after you attempt a read at the end of the file. So the first time in the loop you consume the input up to the eof (not included). Now eof() is false. For this reason the loop is entered again and this time the extractor (>>) hits the end of file. The read operation fails and the string is not changed (that's why you see the same values twice).

A better (and more idiomatic to modern C++) way to code is by using stream iterators

#include <iterator>

// [...]

std::istream_iterator<std::string> scan( readFile );
std::istream_iteartor<std::string> eof;
while( scan != eof )
{
    s = *scan++;
    // s is your string
}

Also it would be better to have the loop in the second part to run from 0 upward, since elements in vectors are numbered starting from 0.

Upvotes: 1

George Houpis
George Houpis

Reputation: 1729

Your last read is probably not reading anything. Try:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;

int main(int argc, char*argv[])
{
    std::string s ;
    std::string delimiter = "/";
    size_t pos;
    std::vector<std::string> part_name;
    std::vector<std::string> rev_id;
    std::string token1,token2;

    ifstream readFile (argv[1]);
    if (readFile.is_open()) 
    {
        while( ( readFile >> s ).good() )
        {
            std::cerr << "Field '" << s << "'  and " << readFile.good() << std::endl;
            pos=s.find(delimiter);
            if((pos!=std::string::npos)&&(pos!=0))
            {
                token1 = s.substr(0, pos);
                token2 = s.substr(pos + delimiter.length());
                part_name.push_back(token1);
                rev_id.push_back(token2);
            }
        }
    }
    else {
        std::cout<<"Cannot open file"<<endl;
    }
    readFile.close();

    for (unsigned j=0; j < part_name.size(); j++)
    {
        cout<<part_name.size()<<endl;
        cout<<"part name j is " <<part_name[j]<<endl;
        cout<<"part id j is " <<rev_id[j]<<endl;
    }
}

Upvotes: 1

Ajay
Ajay

Reputation: 785

I think the problem lies here

while (!readFile.eof()) 
{
readFile >> s;
pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{

token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());

part_name.push_back(token1);
rev_id.push_back(token2);
}

change above to

 while (readFile >> s) 
{

pos=s.find(delimiter);
if((pos!=std::string::npos)&&(pos!=0))
{

token1 = s.substr(0, s.find(delimiter));
token2 = s.substr(pos + delimiter.length());

part_name.push_back(token1);
rev_id.push_back(token2);
}

Upvotes: 3

Alexis Le Provost
Alexis Le Provost

Reputation: 2073

There are some lines than make me suspicious.. Why start your iteration loop by the index 1 ?

  for (unsigned j=1; j < part_name.size(); j++)
 {
    cout<<part_name.size()<<endl;
    cout<<"part name j is " <<part_name[j]<<endl;
    cout<<"part id j is " <<rev_id[j]<<endl;
 }

You always skip the first element of yours vectors.

Upvotes: 0

Related Questions