1

I have a text file in this format:

Petroleum Engineering       94600   175500 

Marine Engineering  73900   123200 

Economics and Mathematics   60000   122900 

Geophysics  54100   122200 

Cognitive Science   54000   121900 

What I have is course name, average early career pay, and mid career pay, all separated by tabs. The course names with multiple words are separated by spaces.

I want to read the course name and put it in one variable, the first pay in a second variable, and the third pay in a third variable.

    int main(){
        ifstream in;
        in.open("Salaries.txt");
        string course;
        int mid;
        int avg;
        if (in.fail()){
        cout<< "failed to open file";
        exit(1);
        }
        while(!in.eof()){
           in >> course >> avg >> mid;
           cout << course<<endl;
        }
      in.close();
     }

When I compile this code, it outputs nothing, and the program does not exit or terminate.

Someone in comments pointed out that using eof() is not recommended, so I tried thus instead:

        while(in >> course >> sm >> lg){     
            cout << course << endl;
       }

The process exits without outputting anything to the screen. I tried it on a input file that looks something like this:

NCORES 1

NEW   0 

CORE   100   
INPUT 5000  
CORE 20

And it takes the string and puts it into one variable, and takes the number and puts it into another variable, and prints the correct output. So the problem is the white space between the words in the cours name in the original file, and I don't know how to account for that.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Dees
  • 45
  • 1
  • 7
  • And debugging line by line shows the program doing what? – Sami Kuhmonen Mar 03 '18 at 03:59
  • Single-step through the program and see where it does not do what you expected it to. Think about it, look at the variable values, and figure out why. If you want to become a developer learning to debug is a requirement not just a nice idea. If there is some valid reason why you can't use a debugger then add print / cout / trace / logging code to get the same information. – Dave S Mar 03 '18 at 04:04
  • 3
    [Why using `eof()` in the loop condition is wrong](https://stackoverflow.com/q/5605125/9254539). – eesiraed Mar 03 '18 at 04:06
  • to keep the while loop running until it gets to the end of the file @FeiXiang – Dees Mar 03 '18 at 04:15
  • @Dees: Click the link he provided, and read the page it leads to. – Jerry Coffin Mar 03 '18 at 04:16

2 Answers2

3

Although your code does have other problems, the problem you're running into is from the fact that operator>> for a string stops reading at the first white space it encounters. That means on the first line, it reads Petroleum into course, then tries to read Engineering into avg. Since avg is a number, that doesn't work, so the conversion fails. From there, all further attempts at reading from the stream fail.

To fix that, you probably want to use std::getline to read the course name. It allows you to specify the character that will end the string it reads. In this case, you apparently want to pass a tab character ('\t') for that parameter.

If I were doing it, I'd probably put the three items into a struct, and overload operator>> for that struct:

struct course {
    std::string name;
    long early_pay;
    long mid_pay;

    friend std::istream &operator>>(std::istream &is, course &c) { 
        if (std::getline(is, c.name, '\t')) {
            std::string temp;
            std::getline(is, temp, '\t');
            c.early_pay = std::stol(temp);
            std::getline(is, temp);
            c.mid_pay = std::stol(temp);
        }
        return is;
    }
};

Then reading the data and printing out the course names would look something like this:

int main() {
    std::istringstream input(
R"(Petroleum Engineering    94600   175500 
Marine Engineering  73900   123200 
Economics and Mathematics   60000   122900 
Geophysics  54100   122200 
Cognitive Science   54000   121900 )");

    course c;

    while (input >> c)
        std::cout << c.name << '\n';
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
2

Use std::getline() to read lines from the file, and use std::istringstream to parse each line. You can then use std::getline() to read tab-delimited strings from each line. For example:

int main() {
    ifstream in("Salaries.txt");
    if (!in.is_open()) {
        cout<< "failed to open file";
        exit(1);
    }

    string line course;
    int mid, avg;

    while (getline(in, line)) {
        istringstream iss(line);
        getline(iss, course, '\t');
        iss >> avg >> mid;
        cout << course << endl;
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • is there a reason why we use stringstream instead of the name of the file? – Dees Mar 03 '18 at 04:57
  • @Dees the `getline` on the outer loop has advanced the `ifstream` past the line that was read, so you can't use the `ifstream` to read the individual values. Using the `istringstream` allows parsing values from the line that was read. You CAN read values from just the `ifstream` by itself, but it is more work, and risks corrupted parsing if the file is not formatted correctly. This way is safer for everything. – Remy Lebeau Mar 03 '18 at 05:15