Page 1 of 1

cin.getline() problems

Posted: Fri Feb 13, 2009 2:05 am
by afaik
I'm having a problem with cin.getline(). I'm creating a char array of 20, but only want to store 4 of the characters for the name input. If the name is 4 characters or less, it works fine. If I input a name that is 5 or more characters, it will skip the next input, in this case cin.getline(city, 20, '\n'). It doesn't even store the extra characters that got cut off from the previous getline (as far as I'm aware), it outputs blanks . The compiler I'm using is DEV-C++. And yes, I did search online for suggestions, but I haven't found any clear answers yet. If anyone can take a quick look at the code below and see whats going on, I'll deeply appreciate you helping a noob. Thanks.

Code: Select all

#include <iostream>
using namespace std;

int main()
{
char name[20],
       city[20];

cout << "Hi, please enter your name: ";
cin.getline(name, 5, '\n');

cout << "Please enter your city: "; // << endl;
cin.getline(city, 20, '\n');


cout << endl << endl;
cout << "Your name is: " << name << endl;
cout << "You live in: " << city << endl << endl;
system("Pause");
}

Re: cin.getline() problems

Posted: Fri Feb 13, 2009 5:35 am
by Ginto8
Click here to see the hidden message (It might contain spoilers)

Code: Select all

#include <iostream>
#include <conio.h>
using namespace std;

int main()
{
char name[20],
       city[20];

cout << "Hi, please enter your name: ";
for(int i = 0; i < 4; ++i) name[i] = getch();

cout << "Please enter your city: "; // << endl;
for(int j = 0; j < 20; ++j) city[i] = getch();


cout << "\n\n";
cout << "Your name is: " << name << endl;
cout << "You live in: " << city << "\n\n";
getch();
}

Added some stuff, like for loops, \n (newline character), and getch(). ;) It should work fine now. :)

Though it won't wait for enter to be pressed... ah whatever. :lol:

But you could do this, just adding in a cin.clear():
Click here to see the hidden message (It might contain spoilers)

Code: Select all

#include <iostream>
using namespace std;

int main()
{
char name[20],
       city[20];

cout << "Hi, please enter your name: ";
cin.getline(name, 5, '\n');

cin.clear();
cout << "Please enter your city: "; // << endl;
cin.getline(city, 20, '\n');


cout << endl << endl;
cout << "Your name is: " << name << endl;
cout << "You live in: " << city << endl << endl;
system("Pause");
}

Re: cin.getline() problems

Posted: Fri Feb 13, 2009 12:11 pm
by MarauderIIC
All input goes to the input buffer before it is processed. What happens is that if you enter more than 5 characters, only 5 characters are taken from the input buffer -- and the rest stay on the input buffer. The next getline then sees there's stuff on the input buffer, and it can't tell whether or not it just got there or not. So, it takes what it can from the input buffer: and if what's there is less than 20 chars, it sees the newline that the last input left and says "okay, I got my line" and it gets "skipped". If there's more than 20 chars, it goes "okay I took what I could" and gets "skipped".

By the way, you would also see this problem if you combined "cin >>" and getline(), as cin, besides only pulling info until the first space, also leaves newlines on the buffer, while any form of getline eats them.

A solution that uses C++ strings would avoid this problem, as they (essentially) don't have a maximum size.

Code: Select all

#include <string>
using namespace std;

int main() {

    string name, city;

    cout << "Please enter your name: ";
    getline(cin, name); //'\n' is the default delimiter

    cout << "And your city: ";
    getline(cin, city);

    //the rest of the story goes here

    return 0;
}
http://www.cppreference.com/wiki/string/getline

Alternatively, do cin.clear()

Re: cin.getline() problems

Posted: Sat Feb 14, 2009 5:00 am
by afaik
Thanks guys for your input. I think I sort of got it working. I wanted to purposefully avoid using C++ strings at the moment since I'm learning c-strings now. I took cin.clear() and added cin.ignore(20, '\n') right after that, and it seems to work the way I intended.

cin.clear() seems to 'unclog' whatever was keeping it jammed there. If I had cin.clear without cin.ignore, it would input the first 4 and the next input statement would eat up the remaining characters. Once I added the cin.ignore(#, '\n'), it would properly ask me for name, clear the error, discard what I didn't need, and proceed to ask me for my city.

The description you gave me was helpful in visualizing the process. I did some more reading and found out that the input stream is in a 'fail state' which must be fixed by using cin.clear.

Source: http://www.velocityreviews.com/forums/t ... oblem.html
When 'cin' encounters a character that is invalid for the
type being extracted, not only does it not read the invalid
character, it goes into a 'fail' state. This is how it
informs you that something went wrong. You check for it
with e.g. if(!cin). The stream remains in this 'fail'
state until explicitly reset. That's what 'clear()' does,
sets the state back to 'good'.
...

A special member function of 'cin' intercepts this attempt
to determine it's 'value' and returns the stream's 'state'
instead. When evaluating 'cin' (or any stream object) in
a boolean context, (as in an if() expression), it produces
a value of 'true' if the stream is in the 'good' state, and
'false' if it is not.
Sorry if this is getting long, but I always like following up my questions if I figure it out with the solution and the sources used so it can be helpful to others if they come across this.

Fixed code:

Code: Select all

#include <iostream>
using namespace std;

int main()
{

char name[20], city[20]; 

if(cin)  cout << "OK!" << endl;
else  cerr << "BAD!" << endl;  // Not sure if I should be using cerr here.. 

cout << "Hi, please enter your name: "; // << endl;
cin.getline(name, 5, '\n');

if(cin)  cout << "OK!" << endl;
else  cerr << "BAD!" << endl;  // Not sure if I should be using cerr here..

cin.clear();                 // reset stream state to 'good
cin.ignore(20, '\n');   // remove remaining characters in stream for next input

cout << "Please enter your city: "; // << endl;
cin.getline(city, 20, '\n');

cout << endl << endl;
cout << "Your name is: " << name << endl;
cout << "You live in: " << city << endl << endl;

system("Pause");
}
EDIT: I've run into another problem now with the modification. While the above fixed my original problem with names greater than 4 characters, now I have a problem with less than 5... sigh, I'll post if I fix the problem.

Re: cin.getline() problems

Posted: Sat Feb 14, 2009 5:45 pm
by afaik
Just add if(!cin) around cin.clear and cin.ignore. Looks to work the way I want to now.

Code: Select all

if(!cin)
{
cin.clear();                    // reset stream state to 'good
cin.ignore(20, '\n');        // remove remaining characters in stream for next input
cout << endl << "FIXED! " << endl << endl;
}

Re: cin.getline() problems

Posted: Sun Feb 15, 2009 7:51 am
by Ginto8
afaik wrote:Just add if(!cin) around cin.clear and cin.ignore. Looks to work the way I want to now.

Code: Select all

if(!cin)
{
cin.clear();                    // reset stream state to 'good
cin.ignore(20, '\n');        // remove remaining characters in stream for next input
cout << endl << "FIXED! " << endl << endl;
}
Congratulations on fixing the problem. ;) If you have any more programming trouble, we'd gladly try to help.

Try being the key word. =P :lol: