C++ input (easy question)

Started by
5 comments, last by stonemetal 16 years, 4 months ago
Okay, easy question, perhaps I'm just being a dummy and it's needlessly perplexing me. I was trying to avoid using cin >> for getting input, so I was looking at things like cin.get() and cin.getline(), but the part that's confusing the heck out of me is that it seems to be sending back a char type? Isn't cin.get()'s return type an int??? For example I'm using: int tmpInt; tempInt = cin.get(); cin.ignore(1000, '\n'); if I enter say, 1, it spits out 49 (correspoding to the ascii code?). I tried (int)'ing the output and that doesn't work either. What's the deal? How do I convert the char type back to an int type? The corollary question is: Is there an easier way to do this? I'm not doing anything difficult, just cout'ing a series of options to the user then asking them to select one (represented by an integer). Any easier tricks for doing this?
Advertisement
cin.get() returns a char, because what it reads are characters. Even if you type '1' on your keyboard, you're still entering the character 1, not the number 1.

And you're right, casting that to an int only gives you the ASCII value of the character '1', which isn't what you want.

There are several ways to do what you want:

1 - The nice way: Download the Boost libraries, and use boost::lexical_cast.
That will allow you to simply do something like this:
int i = boost::lexical_cast<int>(cin.get());

Nice and clean and avoids using old C functions that no one likes [grin]

2 - The plain C++ way: Use std::stringstream:
std::stringstream s;s << cin.get(); // Put the character into the stringstreamint i;s >> i; // Extract an integer from the stringstream

... Not so nice and clean, (on the other hand, stringstreams are a lot more flexible, but when you don't need that flexibility, they're just messy)

3 - The C way: Use atoi() (ASCII to Integer, I believe it means)
int i = atoi(cin.get());

It's C, we don't particularly like that here... but it's more compact than messing with stringstreams...

Of course you need to include a header or two for each of these.


I personally prefer option #1. Of course, it means you have to download and configure Boost, but you'll have to do that sooner or later anyway. Gives you a ton of handy tools to work around all the shortcomings of the language [grin]

If you just want the solution that's simplest *right now*, go for #3.

Quote:just cout'ing a series of options to the user then asking them to select one (represented by an integer). Any easier tricks for doing this?

Well, the obvious answer would be "Do you really need the integer value"?
Can't you just test whether the character entered by the user was '1', rather than testing whether it was the integer 1?

Instead of doing this:
char c = cin.get();// Do magic stuff to get an int i;if (i == 1){ cout << "You selected option 1" << endl;}

you could simply do this:
char c = cin.get();if (c == '1'){ cout << "You selected option 1" << endl;}

Quote:Original post by Spoonbender
Quote:just cout'ing a series of options to the user then asking them to select one (represented by an integer). Any easier tricks for doing this?

you could simply do this:
char c = cin.get();if (c == '1'){ cout << "You selected option 1" << endl;}


Or the deliciously evil:
char c = std::cin.get();int i = c - '0';if (i < 0 || i > 9)	error();if (c == 1)	std::cout << "You entered 1" << std::endl;


Of course, both of these approaches require that you never have more than 10 options, as they only support single characters. In general, more than 10 menu options is a great indication that you need to redesign, so it shouldn't be a problem.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Quote:Original post by StrideKnight
Okay, easy question, perhaps I'm just being a dummy and it's needlessly perplexing me.

I was trying to avoid using cin >> for getting input


Why?

Quote:, so I was looking at things like cin.get() and cin.getline(),


Don't use the member function cin.getline() under normal circumstances. Instead, use the free function, std::getline(). It reads into a std::string (instead of a char[] buffer).

Quote:but the part that's confusing the heck out of me is that it seems to be sending back a char type?

Isn't cin.get()'s return type an int???


There are a couple versions of cin.get(). The one you're using takes no arguments and returns an int: 'int istream::get()'. But it *reads* a char - it simply stuffs that char into an int. The reason is simple: if you try to .get() on a stream that has already reached the end, it will return -1 (instead of some positive value corresponding to an actual char) - this allows you to detect what has happened.

However, that's kind of an old fashioned way of doing things. Most C++ code that iteratively reads input will use the read (one of the reads) itself as the loop condition.

The "new" style cin.get() is 'istream& cin.get(char&)'. You pass it a char variable, and after calling the function, your variable holds the read-in char. (If the file reached the end, the old value of the variable is untouched). This takes advantage of the C++ feature of "passing by reference". The stream itself gets returned (again using "returning by reference"), which allows you to "chain" calls to the function: cin.get(x).get(y).get(z), and also to check whether the file reached the end (just because your variable's value didn't change doesn't mean anything; the input might have just happened to supply the same char).

So for example, you can handle things this way:

char option;if (std::cin.get(option)) {  // do something with it} else {  // The user hit control-Z on windows, or control-D on linux, to "end" the std::cin stream}// clean up here with ignore(), etc.


Personally though, I always recommend handling std::cin a line at a time:

std::string input;while (input.empty() && std::getline(std::cin, input)) {  // do nothing; just skip blank lines - maybe you want to re-print a prompt instead}if (!std::cin) {  // stream was closed; often a good idea to quit the program}char option = input[0];
Do you think this issue is more difficult in C or C++ programming?
Quote:Original post by Spoonbender
you could simply do this:
char c = cin.get();if (c == '1'){ cout << "You selected option 1" << endl;}


LOL, TY, classic case of KISS.

Zahlman:

Thanks! It makes sense now why it returns the ascii code if it uses a -1 indicator. The only reason I wasn't using
cin >> i;
was because earlier I was working with strings and I wanted it buffered and not whitespace delimited. But I guess here where I'm just grabbing the integer directly there's really no problem with using that method.
Quote:was because earlier I was working with strings and I wanted it buffered and not whitespace delimited. But I guess here where I'm just grabbing the integer directly there's really no problem with using that method.



if you go with what Zahlman pointed out with the getline(cin,string) function you get that.

This topic is closed to new replies.

Advertisement