0

I have a file whose content looks like this :

Aadam
50
Aadam
0
Aad
0123
Waleed
12345

Now, I need to store first line in a string array and second line into an integer array. This is the source code that I have written....

ifstream infile ("File.txt");
string name [20];
int score [20};
for (int i = 0; !infile.eof(); i++)
            {
                getline(infile, name[i]);
                infile >> scores[i];
            }

Well, the program reads first line successfully but after that it does nothing. I tried another method first, in which I store the integer first as a temporary string and then I convert that string into an integer using "stoi", which worked like a charm. Like this :

for (int i = 0; !infile.eof(); i++)
            {
                getline(infile, name[i]);
                string temp;
                getline(infile, temp);
                scores[i] = stoi(temp);
            }

But the problem is that I can't use stoi. It works fine in my computer but I have to provide the source code to my teacher who may not have the compiler which supports C++11. Which may be a problem for me. So I need another way to input data from the file. So, Kindly if you know a way to do this, please show me the way.

4 Answers4

1

Instead of "stoi" use "atoi" instead:

scores[i] = atoi(temp.c_str());

http://en.cppreference.com/w/cpp/string/byte/atoi

It's been around since way before C++11.

Psycho
  • 66
  • 1
  • 9
1

If you can't use stoi, you can use string streams instead.

std::ifstream infile ("File.txt");
std::string name[20];
int score[20];
for (int i = 0; !infile.eof(); i++){
    getline(infile,name[i]);
    std::string temp;
    getline(infile,temp);

    std::stringstream s; 
    s << temp; 
    int integertemp; 
    s >> integertemp; // This will convert string to integer, just like how it is with iostreams.
    score[i] = integertemp;
}
wingerse
  • 3,411
  • 1
  • 19
  • 48
0

The problem is with getline after using >>.

To solve it you can add this method:

istream& eatwhites(istream& stream)
{
    // to define white spaces manually:
    //const string skip=" \t\r\n";
    //while(string::npos != skip.find(stream.peek())){
    //   stream.ignore();
    //}

    //or just use isspace:
    while(isspace(stream.peek())){
        stream.ignore();
    }

    return stream;
}

and write each getline like this:

string name;
getline( eatwhites(infile), name); 

and also with cin:

string name;
getline( eatwhites(cin), name); 
SHR
  • 7,149
  • 9
  • 32
  • 50
0

The gist of the problem is that if the input contains:

Aadam\n
50\n

and you do:

  getline(infile, name[i]);    // name[i] contains "Hello", \n consumed
  infile >> scores[i];         // scores[i] contains 50

then the input still contains:

\n

that was after the 50. The >> operator with int does not consume any trailing newlines or other characters after the number that it extracted.

Then for the next time around the loop, the input stream contains:

\n
Aadam\n
0\n

and you do:

  getline(infile, name[i]);    // name[i] contains "", \n consumed
  infile >> scores[i];         // input failure

Since Aadam (the second one) cannot be parsed as an int, the >> operator puts infile into a failure state. Your code never clears the failure state nor checks for it, so all subsequent operations fail and your code goes into an infinite loop.

Additional problems are that using eof() is a bad idea, and (if the reading was fixed) you have a buffer overflow if there are more than 20 pairs of items in your file.


To solve the I/O problem you could write it this way:

for (int i = 0; i < 20; ++i)
{
    getline(infile , name[i]);
    infile >> scores[i];
    infile.ignore(SIZE_MAX, '\n');

    if ( !infile )
        break;
}

The ignore line here means that after reading the number, it will consume the remainder of that line.

When the loop finishes, i will contain the number of pairs that successfully read. The condition to break out of the loop if input fails is important.

Community
  • 1
  • 1
M.M
  • 130,300
  • 18
  • 171
  • 314