cin.getline() problems

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
afaik
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 19
Joined: Mon Jun 16, 2008 11:13 pm

cin.getline() problems

Post 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");
}
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: cin.getline() problems

Post 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");
}
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
User avatar
MarauderIIC
Respected Programmer
Respected Programmer
Posts: 3406
Joined: Sat Jul 10, 2004 3:05 pm
Location: Maryland, USA

Re: cin.getline() problems

Post 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()
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.
afaik
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 19
Joined: Mon Jun 16, 2008 11:13 pm

Re: cin.getline() problems

Post 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.
afaik
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 19
Joined: Mon Jun 16, 2008 11:13 pm

Re: cin.getline() problems

Post 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;
}
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: cin.getline() problems

Post 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:
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
Post Reply