Sign in to follow this  
Levistus

cin.get() and cin.getline() problem

Recommended Posts

Hi. I need some help to understand what's going on with these codes. I have a problem with cin.get() and cin.getline(). First Code I used cin.getline() and on the Second Code I used cin.get(). First Code:
#include <iostream>
int main()
{
using namespace std;
const int ArSize = 20;
char name[ArSize];
char dessert[ArSize];
cout << "Enter your name:\n";
cin.getline(name, ArSize); // reads through newline
cout << "Enter your favorite dessert:\n";
cin.getline(dessert, ArSize);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
system("PAUSE");
return 0;
}



Result: Enter your name: Levi Enter your favorite dessert: Leche Flan I have some delicious Leche Flan for you, Levi. Press any key to continue... Second Code:
#include <iostream>
int main()
{
using namespace std;
const int ArSize = 20;
char name[ArSize];
char dessert[ArSize];
cout << "Enter your name:\n";
cin.get(name, ArSize); // reads through newline
cout << "Enter your favorite dessert:\n";
cin.get(dessert, ArSize);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
system("PAUSE");
return 0;
}



Result: Enter your name: Levi I have some delicious for you, Levi. Press any key to continue... My Question is what happened in the 2nd code? Why didn't it ask me for my favorite dessert? In the book I'm reading it says I should add an extra cin.get() for it to work. But what I want to know is what really happened not just how to fix it. Thank you.

Share this post


Link to post
Share on other sites
Quote:
Source
istream& get (char* s, streamsize n );
Extracts characters from the stream and stores them as a c-string into the array beginning at s. Characters are extracted until either (n - 1) characters have been extracted or the delimiting character '\n' is found. The extraction also stops if the end of file is reached in the input sequence or if an error occurs during the input operation.

If the delimiting character is found, it is not extracted from the input sequence and remains as the next character to be extracted. Use getline if you want this character to be extracted (and discarded).

The ending null character that signals the end of a c-string is automatically appended at the end of the content stored in s.


Emphasis mine.

Share this post


Link to post
Share on other sites
cin.get() doesn't do exactly what you think it does. It retrieves the specified number of characters from the input stream and if that happens to be empty, the user is prompted to enter something. What basically happens here is that there's still some characters left in the input stream (cin) after you've read the users name. These can be discarded with the ignore() function (cin.ignore()), which would solve your problem.

However, since you're programming in C++, consider using std::string's instead of char arrays and stream operators instead of get functions:

#include <iostream>
#include <string>

using namespace std;

int main()
{
string name;
string dessert;

cout << "Enter your name:\n";
cin >> name;
cout << "Enter your favorite dessert:\n";
cin >> dessert;
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
system("PAUSE");
return 0;
}

Share this post


Link to post
Share on other sites
Ok I have tried something to see what really is going on. Here's the code.


#include <iostream>
using namespace std;
int main()
{
const int size = 5;
char name[size];
char name2[size];
cout << "What is your name?" << endl;
cin.get( name, size );
cout << name << endl;
cin.get( name2, size );
cout << name2 << endl;
system("PAUSE");
return 0;
}



Result:
What is your name?
Levistus
Levi
stus
Press any key to continue...

I used cin.get() and the first name can only take 5 right? So the leftovers went to name2. Then in my first post, what happened in my code 2 in the dessert part? I had a 20 limit. What got sent to dessert automatically? If theres something left behind when using cin.get() then why not just always use cin.getline()?

Thanks for answering. I just want everything clear.

Share this post


Link to post
Share on other sites
Going with std:.string would really help you here, it would simplify a lot.

I believe what was left is the stream was '\0', since cin.get() doesn't extract/discard this character (see rip-off's post). So on the next call of cin.get(), it reads from 0 to the next '\0'. Seeing there is still a '\0' left from the last call, cin extracts absolutely nothing.


Use std::string, it makes things easier. Also, instead of using cin.get(), I recommend using getline( std::stream&, std::string& ).


#include <iostream>
#include <string>
int main()
{
using namespace std;
string name;
string dessert;
cout << "Enter your name:\n";
getline(cin, name); // reads one line from cin and discards it
cout << "Enter your favorite dessert:\n";
getline(cin, dessert);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
system("PAUSE");
return 0;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
Going with std:.string would really help you here, it would simplify a lot.

I believe what was left is the stream was '\0', since cin.get() doesn't extract/discard this character (see rip-off's post). So on the next call of cin.get(), it reads from 0 to the next '\0'. Seeing there is still a '\0' left from the last call, cin extracts absolutely nothing.


Use std::string, it makes things easier. Also, instead of using cin.get(), I recommend using getline( std::stream&, std::string& ).


*** Source Snippet Removed ***


Ok thanks. It's just that I'm following the book maybe I'll get to strings someday and I wanted more than 1 word so I used cin.get(). Thanks guys you can close this now I understand now. God Bless.

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
Going with std:.string would really help you here, it would simplify a lot.

I believe what was left is the stream was '\0', since cin.get() doesn't extract/discard this character (see rip-off's post). So on the next call of cin.get(), it reads from 0 to the next '\0'. Seeing there is still a '\0' left from the last call, cin extracts absolutely nothing.


'\n' (a return character), not '\0' (a null terminator). std::cin doesn't normally ever contain any \0's because there isn't a decent way to type them.

What happens is, cin.get(name, ArSize) reads 'Levistus' into name, adds a '\0' after those 8 characters, and leaves the '\n' on the stream. Then cin.get(dessert, ArSize) sees the '\n' right at the start of the stream, so it does exactly what it is told - reads '' into dessert, adds a '\0' after those 0 characters, and leaves the '\n' on the stream.

Anyway, "following a book" is usually a bad way to learn a language; working with std::string is easier than all this nonsense, and the fact that your book has you work through any of it (let alone start off with it!) is a sign that it is very much out of date.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Quote:
Original post by c4c0d3m0n
Going with std:.string would really help you here, it would simplify a lot.

I believe what was left is the stream was '\0', since cin.get() doesn't extract/discard this character (see rip-off's post). So on the next call of cin.get(), it reads from 0 to the next '\0'. Seeing there is still a '\0' left from the last call, cin extracts absolutely nothing.


'\n' (a return character), not '\0' (a null terminator). std::cin doesn't normally ever contain any \0's because there isn't a decent way to type them.

What happens is, cin.get(name, ArSize) reads 'Levistus' into name, adds a '\0' after those 8 characters, and leaves the '\n' on the stream. Then cin.get(dessert, ArSize) sees the '\n' right at the start of the stream, so it does exactly what it is told - reads '' into dessert, adds a '\0' after those 0 characters, and leaves the '\n' on the stream.

Anyway, "following a book" is usually a bad way to learn a language; working with std::string is easier than all this nonsense, and the fact that your book has you work through any of it (let alone start off with it!) is a sign that it is very much out of date.


The book I'm reading is C++ Primer Plus 5th Edition by Stephen Prata, Sams Publishing (2005). The reviews about this book seems really good so I got it. Maybe you can recommend me a more recent book. Thanks.

Share this post


Link to post
Share on other sites
Quote:
The book I'm reading is C++ Primer Plus 5th Edition by Stephen Prata, Sams Publishing (2005). The reviews about this book seems really good so I got it. Maybe you can recommend me a more recent book.
I thought Prata’s book deals with std::string. Maybe it’s a bit later in the book.

If you want a good set of books. Accelerated C++ by Koenig and C++ Primer (not Prata’s Primer Plus), 4th Edition, by Lippman. The first one if you don’t want to get both.

Share this post


Link to post
Share on other sites
Ok I have researched for an alternative to cin.get/getline that can store words with whitespaces and also to be able to use strings. Here's my new code:


#include <iostream>
#include <string>
using namespace std;
int main()
{

string name;
string dessert;
cout << "Enter your name:\n";
getline(cin, name);
cout << "Enter your favorite dessert:\n";
getline(cin, dessert);
cout << "I have some delicious " << dessert;
cout << " for you, " << name << ".\n";
system("PAUSE");
return 0;
}



Result:
Enter your name:
Leche Flan Monster
Enter your favorite dessert:
Leche Flan
I have some delicious Leche Flan for you, Leche Flan Monster.

Yea! it worked! Now I ask if there is another better alternative to what im trying to do? Or is getline(not cin.getline) the best? I just want to be able to print on the screen words with spaces. Thanks guys.

Share this post


Link to post
Share on other sites
getline( std::istream&, std::string& ) is from the <string> library. It was designed for std::strings in the first place.

I've always found cin by itself a bit dodgy. It confused me as a beginner, because I was unaware of the fact that it is a stream. I just thought it was a method to get some input.


cin >> starts being funky when you have more than one word (white space is delimiting)
cin.get() starts being funky when you have more than one line (newline isnt flushed)
cin.getline() needs to know how much you're reading from the stream maximal

getline() from <string> just reads one line into a string, no matter if there is multiple words, multiple lines, or very long lines.


@Zahlman: Thanks for the update, I guess I learned a detail again ;)

Share this post


Link to post
Share on other sites
Sup guys I made a new program and I used cin to enter the menu choice and getline to get the name of the player. I used getline to I can use spaces.


#include <iostream>
#include <string>

using namespace std;

void welcome();
void game();

int main()
{
welcome();
char choice;
cout << "Enter a to Start game or b to exit:" << endl;
cin >> choice;
if ( choice == 'a' )
{
game();
}
else
{
system("CLS");
cout << "Thank you for playing. Goodbye brave adventurer!" << endl << endl;
}

system("PAUSE");
return 0;
}


void welcome()
{
cout << " " << endl;
cout << " " << endl;
cout << " L E V I S T U S R P G " << endl;
cout << " " << endl;
cout << " a.Start Game " << endl;
cout << " b.Exit Game " << endl;
cout << " " << endl;
}

void game()
{
system("CLS");
cout << "Welcome Adventurer! What is your name?" << endl << endl;
string name;
string mystery;
getline(cin, mystery);
getline(cin, name);
cout << "Nice to meet you," << mystery << "!" << endl << endl;
cout << "Nice to meet you, " << name << "!" << endl;
}



I have 2 string, name for the name of the player and mystery so I can print the mystery character that's being left in the stream because of the cin earlier in the menu.

Result:
(I enter a to start the game())
Welcome Adventurer! What is your name?

(I type Levistus of Stygia)
Nice to meet you,!

Nice to meet you, Levistus of Stygia!
(END)

What was that something which is nothing really(not even a space)that got saved in the stream? What do you call it? I thought \n makes a newline? The mystery thing is not even a space. When I enter aaa into the menu the other a's get to mystery. Now I'm understanding a little about the stream but what is that nothing thing that got entered on the string mystery? What is it called?

Thank you so much guys! I'm still confused you know I want to know every detail and what terms, what you call the things I'm encountering. Please be patient with me.





Share this post


Link to post
Share on other sites
It is a newline that is left in the buffer.

You are using getline() to read into mystery. getline() reads every character up to the newline into the string then discards the final newline.

Since, in this case, there is only a newline in the buffer, the result is an empty string.

You could use cin.ignore() to get rid of the remaining newline. Personally I'd use a stringstream:


#include <sstream>

int main()
{
welcome();
cout << "Enter a to Start game or b to exit:" << endl;

string s;
getline(cin,s); // read a whole line of input

istringstream is(s); // put the whole line in a stringstream

char choice;
is >> choice; // get the option out of the stringstream

if ( choice == 'a' )
{
game();
}
else
{
system("CLS");
cout << "Thank you for playing. Goodbye brave adventurer!" << endl << endl;
}

system("PAUSE");
return 0;
}


This will ensure that an entire line is read when you prompt for a choice, and that anything after the entered option will then be discarded.

Generally, using the .get() and >> methods on cin tend to lead to problems unless you are very familiar with the fact that cin is a stream, whereas what you are reading from is a keyboard.

I personally always find it easier to read a line at a time from cin (which is how we conceptually expect keyboard input to work) then do any actual processing of the input using a stringstream.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this