for loop skipping getline
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,
sircrisp
Dumb csci student that doesn't know anything at all.
Updated on November 21, 2022Comments
-
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 about 12 yearscan't you just use
cin>>students[count].studentName;
. It works btw -
matth about 12 years@Neox - not if the student's name has a space in it, like 'John Hancock' does.
-
-
sircrisp about 12 yearsI 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 about 12 yearsI used a cin.ignore(); before getline to fix my problem.
-
Xeo about 12 years@sircrisp: Create an
std::istringstream
from thestd::string
that contains the line read. You can then exctract space-seperated items from the stream the same way you do withstd::cin
:istr >> item;
-
sircrisp about 12 yearsNice! 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 about 12 yearsWhat 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 usegetline
after each prompt; when you need anint
or adouble
, put the line (which should have typestd::string
) into astd::istringstream
, and use>>
on that. -
James Kanze about 12 yearswith regards to the
ignore
: it's not as robust as just usinggetline
, but if you do go that route, theignore
should follow the>>
, not precede thegetline
. The idea is to ensure that after every input, the last character extracted is tne'\n'
. -
James Kanze about 12 yearsAlso: 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 thegetline
/istringstream
approach. The error in such cases will be on theistringstream
, which is local to the loop. And regardless of what happens, the main input remains synchronized on the lines.)