Anyway of telling what is in the buffer or the size of the string?

To clarify, I've been getting questions about the use of std::cin and ways to "error" or "dummy" proof it. I know to use the ignore function, but I was working with failbits on a previous post and I was unable to find a way to make cin throw a failbit when inputting a character variable. To give you an example that might help, I provided this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>

int main() {
   std::cout << "Please enter a character: ";
   char myChar;
   std::cin >> myChar;

   // Unable to set failbit flag with char
   while(std::cin.fail()) {
      // Clear any flags
      std::cin.clear();
      // Remove garbage from the buffer
      std::cin.ignore(80, '\n');

      std::cout << "Bad input. Please try again: ";
      std::cin >> myChar;
   }
   
   std::cout << "myChar = " << myChar;

   return 0;
}
Please enter a character: Hello
myChar = H


Obviously what was entered was a character, and as far as I was able to test (even tried using unicode characters) no flags can be thrown for a character in the input stream. I know you can manually set the flags, and let's say I want to make sure they didn't enter a string (like "Hello" in my example), is there anyway to check the buffer to see if there is more in it (is this the purpose of std::cin.peek())? Is there a way to get the entire length of the buffer or everything that's stored in the buffer (maybe they entered a number at spot 10 and I want to store just that number)?

Edit: Possibly a way to return everything in the buffer as a string without having to use the string stream (I don't believe they share the same buffer though).

I don't see that using a loop to just read everything in the buffer is the best option, but I'm not sure there is any alternatives. Using a boost library for something like this is feasible, but I'd prefer to use something from the standard library. I'm hoping someone can help clarify this for me.
Last edited on
If you just want to ignore the rest of the line, just use this:

std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
I know how to ignore, I'm asking is there a way to get the information in the buffer. I found the istream read and gcount functions, and I believe they're what I want, so I'll type up a small program and if it works correctly, I'll paste back demonstrating what I meant.
You could extract the contents of the buffer (if any) into a std::string.
no flags can be thrown for a character in the input stream

The only time cin >> for chars sets the failbit is if eofbit is already set, or if the attempt to read the char fails due to the eof condition. You can see that if you enter Ctrl+D (Unix) / Ctrl-Z (Windows) as your input.

Is there anyway to check the buffer to see if there is more in it

Yes, cin.rdbuf()->in_avail() does that. But it won't give you what you expect for std::cin since it is forbidden to buffer anything unless cin.sync_with_stdio(false) was called. (which is another reason why cin.sync() is meaningless)

Oh, wow, PathScale (Ekopath) C++ actually buffers it up and returns non-zero from in_avail() (and, obviously, totally fails at maintaining stdio synchronization)

maybe they entered a number at spot 10 and I want to store just that number

Streams are not arrays! Read (or discard, which is a form of read) those first 9 bytes and you will have your number.
Last edited on
Is it really wrong to think of a stream as a set of continuous characters (or whatever is in them) since it's really how it works (or do I have that all wrong)?

I just stumbled across the in_avail() on this site, and the example shows that it should work, but doesn't work as intended on my system. Aside from unsyncing with stdio, what alternatives exist aside from stepping through the stream? I just look at that as not being as effective as what I'd like to do with it.

My first scenario:
When I ask a user for a character, I want to see if they input a string and set the failbit manually that way.

My second scenario:
It would be nice to specify the number of items in the stream when using cin.ignore() instead of just saying to add a whole new header file just to use limits or instead of using a magic number (like 80 when I demonstrate).

My third scenario:
When asking a user to enter an int and they enter a floating point value instead, I would like to check against that. I believe this is the same situation as my first scenario though.

Maybe I'm just refusing to do the simple solution and use the get function like I probably should be, but it doesn't look nice and I don't feel that's exactly what it's meant for.

Cubbi wrote:
But it does not apply to std::cin since it is forbidden to buffer anything

If that's the case, why is it that when you enter a string with spaces and don't use cin.getline, it overflows into the next cin call? There has to be a buffer of some sort there. Is it just not available to us?
My first scenario:
When I ask a user for a character, I want to see if they input a string and set the failbit manually that way.


If you want to do this, then get the entire line then parse it yourself.

My second scenario:
It would be nice to specify the number of items in the stream when using cin.ignore() instead of just saying to add a whole new header file just to use limits or instead of using a magic number (like 80 when I demonstrate).


You could just use getline() into a string to read a line or whatever if you want to. It'll overlap is with the solution to #1.

My third scenario:
When asking a user to enter an int and they enter a floating point value instead, I would like to check against that. I believe this is the same situation as my first scenario though.


Basically do the same thing as #1. Read it into a string and parse it yourself if you want special behavior.
That's an even worse idea (in my mind) than using the get/peek/read method to read from the stream. I'd much rather find a simple solution for doing it than what you had mentioned. I'd also rather find at least a way to get the number of objects that are still in the buffer.
But it does not apply to std::cin since it is forbidden to buffer anything

If that's the case, why is it that when you enter a string with spaces and don't use cin.getline, it overflows into the next cin call? There has to be a buffer of some sort there. Is it just not available to us?


It isn't std::cin's buffer. It's the stdin's buffer. Try this for a demo:

1
2
3
4
5
6
int n;
cin >> n; 
char c = getchar(); std::cout << c;
std::cin >> c; std::cout << c;
char c = getchar(); std::cout << c;
std::cin >> c; std::cout << c;

and enter something like 1 test

demo: http://ideone.com/yz5Uf
That looks just like what I would have done with get or peek. This is my thought process on how the input stream works. You're asked for input of some sort. Whatever you type is added to the buffer. Once you press enter, the stream reads from the buffer what it needs (or sets a failbit if it can't find what it needs). As long as their is still "garbage" in the buffer, the next time the stream needs input, it checks the buffer. If there is something in it, it tries to read from the buffer again (this causes the undesired side effects that beginners start seeing). If there is nothing in the buffer, it allows the user (or file) to input into the buffer again.

Is that logic wrong? If not, why is the buffer so elusive? Why can't I read everything from the buffer? Is there even a way to tell when there is nothing in the buffer?

What is stdin? Is that istream? Is there a way to get information back from the buffer that way? Maybe I'm just being stubborn and thinking about this in all of the wrong ways, but I know I couldn't have been the first person to be curious about it. I thought that iostream being one of the basic building blocks of just about any language, there should be a lot of control over what us as the coders can do with it.

So far the best solution has been to peek. And I very well might come up with something that actually satisfies me. I really appreciate the ideas so far. My final goal is to dummy proof my code.
Topic archived. No new replies allowed.