Question

This is not homework, it is self study. I am getting an unexpected error that is think is the result of getline requesting after the end of file. I though I was checking to see if input was successful with the while(getline(inf,mystring)) but its not working. How do I effectively check for end of file if this is not the case?

This is my code

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int main(int argc, char** argv)
{
    string mystring, substring1 = "", substring2 = "";
    int sos;
    ifstream inf (argv[1]);  //open file for reading
    if (!inf)
    {
        // Print an error and exit
        cerr << "Uh oh, " << argv[1] << " could not be opened for reading!" << endl;
        exit(1);
    }
        while(getline(inf,mystring))
        {
                sos = mystring.find_first_not_of(" ");
                if (sos != 0)
                {
                    mystring = mystring.substr(sos, string::npos);
                }
                sos = mystring.find_first_of(" ");
                if (sos != 0)
                {
                    substring1 = mystring.substr(0,sos);
                    substring2 = mystring.substr(sos + 1, string::npos);
                }
                sos = substring2.find_first_of(" ");
                if (sos != 0)
                {
                    substring2 = substring2.substr(0, sos);
                }
                cout << substring2 << " " << substring1;

        }
    return 0;
}

This is the error

World Helloterminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr

This is the input file input.in

         Hello World
Was it helpful?

Solution

Before you extract a sub-string, you need to check that the range of the sub-string is physical (that is, the first index of a call to $substr$ comes before the last). I suspect that your file contains an empty line, in this case a call to $find_first_not_of$ will return $npos$ indicating that nothing was found before the end of the string.

I would suggest adding a check for $npos$ returned from $find_first_not_of$:

// Strip leading spaces
sos = mystring.find_first_not_of(" ");
/* sos == 0 would mean substr(0, npos) -> useless.
   sos == npos would mean substr(npos, npos) -> un-physical. */
if (sos != 0 && sos != string::npos)
{
    mystring = mystring.substr(sos, string::npos);
}

// Split string by first space
sos = mystring.find_first_of(" ");
substring1 = mystring.substr(0, sos); /* sos != 0, since strip leading spaces */
/* Check that sos+1 is inside the string. */
if (sos+1 < mystring.length())
{
    substring2 = mystring.substr(sos+1, string::npos);
}
else
{
    substring2 = "";
}

sos = substring2.find_first_of(" ");
/* sos == 0 would cause substr(0, 0) -> un-physical,
   sos == npos would cause substr(0, npos) -> useless. */
if (sos != 0 && sos != string::npos)
{
    substring2 = substring2.substr(0, sos);
}

count << substring2 << ' ' << substring1 << std::endl;

OTHER TIPS

Note that find_first_not_of returns string::npos when it doesn't find anything - not zero as you are testing. If you have a line with no spaces (or an empty line) then your test for find_first_not_of(" ") will return string::npos leading to

mystring = mystring.substr(string::npos, string::npos);

which will cause an exception.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top