for loop skipping getline

12,706

Solution 1

The reason what you're doing doesn't work is that the '>>' operators the first time through don't extract the trailing '\n', the next getline sees it, and returns immediately with an empty line.

The simple answer is: don't mix getline and >>. If the input is line oriented, use getline. If you need to parse data in the line using >>, use the string read by getline to initialize a std::istringstream, and use >> on it.

Solution 2

Put

cin.ignore();

at the end of the loop.

Solution 3

Look up C++ FAQ on iostreams.

Item 15.6 specifically deals with your problem ("Why is my program ignoring my input request after the first iteration?"), but you may find the whole page useful.

HTH,

Share:
12,706
sircrisp
Author by

sircrisp

Dumb csci student that doesn't know anything at all.

Updated on November 21, 2022

Comments

  • sircrisp
    sircrisp over 1 year

    Hello everyone I am doing a programming assignment on structured data and I believe I understand how structs work.

    I am trying to read in a list of student names, ID numbers (A-Numbers), and their balances.

    When I compile my code though, it will read everything in the first time around, but the second time around the loop and every time after, it prompts for the username but skips the getline and goes straight to A-Number and A-number entry.

    Any help would be appreciated. Just trying to figure out how to make the getline work every time the loop goes around.

    #include <iostream>
    #include <string>
    #include <iomanip>
    using namespace std;
    
    
    int main(){
        const int maxStudents = 30;
        struct Students{
            string studentName;
            int aNumber;
            double outstandingBalance;};
    
        Students students[maxStudents];
    
        for(int count = 0; count < maxStudents-1; count++)
        {
            cout<<"Student Name:";
                    cin.ignore();
            getline(cin,students[count].studentName);
            cout<<"\nA-Number:";
            cin>>students[count].aNumber;
            if(students[count].aNumber == -999)
                break;
            cout<<"\nOutstanding Balance:";
            cin>>students[count].outstandingBalance;
        }
    
        cout<<setw(20)<<"A-Number"<<"Name"<<"Balance";
    
        for(int count2 = 29; count2 >= maxStudents-1; count2--)
            cout<<setw(20)<<students[count2].aNumber<<students[count2].studentName<<students[count2].outstandingBalance;
    
    
        system("pause");
        return 0;
    }
    
    • Neox
      Neox about 12 years
      can't you just use cin>>students[count].studentName;. It works btw
    • matth
      matth about 12 years
      @Neox - not if the student's name has a space in it, like 'John Hancock' does.
  • sircrisp
    sircrisp about 12 years
    I understand what I did wrong but the rest of your answer has left me completely confused as to what youre trying to tell me to do.
  • sircrisp
    sircrisp about 12 years
    I used a cin.ignore(); before getline to fix my problem.
  • Xeo
    Xeo about 12 years
    @sircrisp: Create an std::istringstream from the std::string that contains the line read. You can then exctract space-seperated items from the stream the same way you do with std::cin: istr >> item;
  • sircrisp
    sircrisp about 12 years
    Nice! Thanks for the tip. Can't use it for this particular program though because of the requirements for homework. Has to be a string.
  • James Kanze
    James Kanze about 12 years
    What has to be a string? Mixing getline and >> is not a good technique. It is extremely fragile, and will cause all sorts of problems with unexpected input. The only viable solution is to use getline after each prompt; when you need an int or a double, put the line (which should have type std::string) into a std::istringstream, and use >> on that.
  • James Kanze
    James Kanze about 12 years
    with regards to the ignore: it's not as robust as just using getline, but if you do go that route, the ignore should follow the >>, not precede the getline. The idea is to ensure that after every input, the last character extracted is tne '\n'.
  • James Kanze
    James Kanze about 12 years
    Also: check the state of the stream after every input. Your code will behave very funny if someone inputs "abc" when they should input a number. (This is, in fact, a major benefit of the getline/istringstream approach. The error in such cases will be on the istringstream, which is local to the loop. And regardless of what happens, the main input remains synchronized on the lines.)