How do I have the cin buffer only accept a specific number of characters?

Pages: 12
I want to create a variable that only is able to take a specific number of characters from user and then will discard the rest. Here is the function in question:

1
2
3
4
5
6
7
8
9
10
11
string getGuess()
{
	string guess = "";

	cout << "Enter your guess: ";

	getline(cin, guess);
	cout << endl;

	return guess; 
}


I don't want the user to be able to enter more than 4 characters. How do I do that? std::cin.ignore() starts eliminating characters BEFORE a specific index. I need a function that will eliminate characters AFTER a specific index. Does anyone know what could solve my problem? I have been looking for different functions and have been unable to find one that accomplishes what I need.
The easiest way would be to just read the whole string and then shrink the string to the wanted size afterwards.

1
2
3
4
5
6
const int guess_max_length = 4;
getline(cin, guess);
if (guess.size() > guess_max_length)
{
	guess.resize(guess_max_length);
}

Awesome! I didn't know there was a resize function but now I do. Thanks!
The standard library sucks for stuff like this. Peter's code snippet still allows the user to type as long a string he wants, and the program will read the entire string, just that it's later trimmed to required size. And all inputs must be terminated by a '\n' (if not some other delimiter), sucks.

You can use your Operating system API or some user-written library to compensate.

If you're using Visual Studio, take inspiration from this function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <string> 
#include <thread> // for pause_program()
#include <chrono> // for pause_program()
#include <conio.h> // for _kbhit() & _getch()

inline void pause_program(unsigned short int duration) {
	std::this_thread::sleep_for(std::chrono::milliseconds(duration));
} // replace with your favorite sleep function

std::string input_of_length(size_t length) { // take input of specified length

	std::string input_string;
	char input_char;

	while (_kbhit()) { _getch(); _getch(); } // clears keyboard stream
	// 2 x _getch(); because VS2017's _getch(); must be called twice

	while (input_string.size() != length) { 

		if (_kbhit()) {
			input_char = _getch();
			_getch(); // getch(); needs to be called twice

			if (input_char == 8) { // 8 is backspace
				// Implement with <Windows.h> or a function that uses carriage return and spaces.
				// then trim length of input_string
			}
			else {
				std::cout << input_char;
				input_string += input_char;
			}
		}
		pause_program(50); // give the CPU some rest
	}
	return input_string;
}


Similarly you can take input and make sure it resembles a particular pattern or string by concurrently comparing every character typed.

The function will work with other compilers that have <conio.h> as well, but you need to eliminate a _getch(); call from the two places where _getch(); is used.

By the way if you don't know what the heck _kbhit() and _getch() are, _kbhit() returns true when there is something in the keyboard stream. _getch() takes the first character from the keyboard stream (VS2017 has a caveat where the _getch() function must be called twice, the second call would give a null).
@Grime
There’s nothing wrong with the Standard Library WRT limiting input.

The entire philosophy behind C and C++ streams — the entire design of operating systems — all are antithetical to the contextual jump here.

Your program does not control the input, nor does it have any right to.

What it does control is the way it accepts the input. Peter87’s answer is absolutely correct: it does exactly what the OP wants. Read a line of input, accept the first N characters, and discards the rest.

Input remains line-buffered, which is what it is supposed to be. The whole newline buffering thing is basic to properly signaled I/O stream behavior. Programs expect it. The OS caters to it. Users expect it.


#include <conio.h> // for _kbhit() & _getch()
If we’re gonna use Windows-specific stuff, skip the kiddie crap. #include <windows.h>

[stuff about _getch() needing to be called twice]

No it doesn’t. That would break the three-decade-old standard behavior of the function. getch() (and variants) returns the key code, or one of 0 or 0xFE (IIRC) to indicate an “extended” key code. Only then do you need to call it again.

// clears keyboard stream
No. https://docs.microsoft.com/en-us/windows/console/flushconsoleinputbuffer
But... don’t do that.
You’re throwing away all input that the user felt important enough to send your way. Poorly-behaved programs do that.

...and... throwing away waiting input before asking for more input is the same problem, only worse. Just... Don’t.


I have already posted on this stuff before.
http://www.cplusplus.com/forum/beginner/1988/4/#msg14423

And given raisins.
http://www.cplusplus.com/forum/beginner/1988/2/#msg10636
I've dealt with plenty of forms that will just ignore certain keys instead of issuing some sort of error for them.
For example, for things like entering birth dates {MM/DD/YYYY), I've seen it do validation in real-time against typing letters in, so that the user can't type in "Feb".
More freedom/choice = more confusion, more help center calls. I've never found it to be particularly annoying.

Or imagine something like a calculator -- pressing the + sign twice doesn't make an error occur, it just accepts it and essentially ignores it (well, maybe a bad example, a graphing calculator might still accept double ++ as input since you can move around more).

I admit there's only a few places where it makes sense to limit the user in this way, but I don't see how it violates a rule.
It would just be like not letting a user walk into a wall if they press the down arrow when they're already next to the bottom wall -- instead of giving an error after the fact, just don't let them walk into the wall in the first place. Or maybe I'm misunderstanding the essential point.

Another example I can think of is when a forum might want a max length for a name. Often times, it will put a limit on the number of characters that can be typed into the field, and might give a floating indicator that you've reached the max input if you try to type past it.

Yes, please burn <conio.h>, much better functionality is in <windows.h> for Command-line tinkering.
Last edited on
Yes, you are missing my point.

Programs like the forms applications that ignore keys are not streams applications, and they come with a whole ton of behind-the-scenes effort to manage input. My link touches on that.

Any application can ignore bad input, such as a doubled +, or keys that are not acceptable for an input field. This has nothing to do with modifying the system input, or unilaterally tossing input.

Neither of those examples involve limiting the user.
They are filtering bad input, and doing it in a way appropriate to the UI classification.
Thanks for the clarification.

(Essentially, stop trying to hack a command-line/stream input program to behave like a TUI/GUI; choose one or the other).
Last edited on
YES!

You know you’re awesome, right? No matter what everyone else says. <grin>
Yeah, I knew everyone else was full of sh--! :>
Last edited on
Input remains line-buffered, which is what it is supposed to be. The whole newline buffering thing is basic to properly signaled I/O stream behavior. Programs expect it. The OS caters to it. Users expect it.

That wouldn't mean that there wouldn't be need for programs that rely on taking input the 'wrong-way'. So people have to rely on non-standard stuff. If there were something for this kind of input with the standard, then it would help portability of code. Besides what doesn't C++ have by now?

If we’re gonna use Windows-specific stuff, skip the kiddie crap. #include <windows.h>

I'm not familiar with windows functions and too lazy to try and get equivalent windows functions. I did try to lookup windows functions but gave up like immediately man, from what I've found there's nothing like _kbhit(), but I won't say that because again, I'm not familiar with windows functions.

No it doesn’t. That would break the three-decade-old standard behavior of the function. getch() (and variants) returns the key code, or one of 0 or 0xFE (IIRC) to indicate an “extended” key code. Only then do you need to call it again.

Unfortunately it is so currently in Visual C++. After every key read by getch();, the next key will be a '\0'. I haven't bothered googling whether it's something Visual want to fix.

...and... throwing away waiting input before asking for more input is the same problem, only worse. Just... Don’t.

It is necessary. You don't want to take input that was typed in before the input routine was started.

I used getch & kbhit because I wasn't using windows functions anyway, so using getch and kbhit here would allow dos.h compilers to run the code (by eliminating one getch() of course).
Sigh.

That wouldn't mean that there wouldn't be need for programs that rely on taking input the 'wrong-way'.
Again, non-sequitur. Weird programs do exist; typically with really good reasons. Badly-behaved programs have no excuse. Those are three different situations; none preclude the existence of the other.

I'm not familiar with windows functions and too lazy to try and get equivalent windows functions. I did try to lookup windows functions but gave up like immediately man, from what I've found there's nothing like _kbhit(), but I won't say that because again, I'm not familiar with windows functions.
Short version: I don’t care to learn better, therefore my ignorance suffices.

Unfortunately it is so currently in Visual C++.
That would directly contradict the documentation:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=vs-2017
Further, I cannot replicate the failure using VS2017. So... there’s something more there that you are either not recognizing or not telling us. (Being honest, not charitable, I believe the former.)

It is necessary. You don't want to take input that was typed in before the input routine was started.
I don’t know what hell you are programming under, but I most certainly want input I gave the program to be used. Supplying the entirety of input before a program is even activated is common, normal, and expected. What you are suggesting is that people who expect that are mistaken about the correctness of that behavior. This includes people who designed this behavior, like Ritchie and Knuth.

I used getch & kbhit because I wasn't using windows functions anyway, so using getch and kbhit here would allow dos.h compilers to run the code (by eliminating one getch() of course).
Yeah, because we’re all using MS-DOS 20 years ago.

You already know I don’t care to compete with BS for very long. I’ll state my point and then let you write what you want. You already know you’re on my ignore list, so enjoy the little bit of attention your getting while you can. So sad, too, because I thought you had grown up some. I actually liked some of the help you’ve been giving people.
Again, non-sequitur. Weird programs do exist; typically with really good reasons. Badly-behaved programs have no excuse. Those are three different situations; none preclude the existence of the other.

Exactly and these weird programs (as you call it) could be more portable (code) if the standard accepted it. I'm not arguing just stating valid opposing points.

For every good point there's a valid opposing point. And I'm bringing that out because I think it's only fair, I'm not trying to "argue" with you, so I hope you will understand that. A discussion would be unbiased only when opposing views are also allowed to be expressed.

And yes the opposing point could be a very dumb one, but there is one.

Short version: I don’t care to learn better, therefore my ignorance suffices.

I did say that I "tried" to find something like _kbhit() but failed at it. Or maybe I could have decided that _kbhit() was a better option?

That would directly contradict the documentation:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/getch-getwch?view=vs-2017
Further, I cannot replicate the failure using VS2017. So... there’s something more there that you are either not recognizing or not telling us. (Being honest, not charitable, I believe the former.)

It works on my compiler that way, hence I posted it, why would I unnecessarily make up stuff like "getch needs to be called twice"? I have seen discussions that _getch() worked this way for Visual C++, maybe it's a bug, I didn't do that research.

I don’t know what hell you are programming under, but I most certainly want input I gave the program to be used. Supplying the entirety of input before a program is even activated is common, normal, and expected. What you are suggesting is that people who expect that are mistaken about the correctness of that behavior. This includes people who designed this behavior, like Ritchie and Knuth

No it is absolutely necessary for what this function does, which is take input real-time. I don't think it makes sense to expect the user to type input on the loading screen, when he doesn't even know what input to give! That would lead to unwanted behavior and results.

Yeah, because we’re all using MS-DOS 20 years ago.

Dev-C++ has conio.h which a lot of people use even at their homes. Moreover some people (including me) use Turbo-C++ at shcool (trust me, it's a lot of people), which has <conio.h>

You already know I don’t care to compete with BS for very long. I’ll state my point and then let you write what you want. You already know you’re on my ignore list, so enjoy the little bit of attention your getting while you can. So sad, too, because I thought you had grown up some. I actually liked some of the help you’ve been giving people.

You might have assumed that I knew that, I didn't. But I did assume that you would know that I thought this was a proper respected discussion, so I have to make sure my assumption was right, so was it?

I thought this discussion was good so far, apparently not for you. I am sure you won't tell me where this went to offend you, so I won't ask you, but I will still mention, so that for whatever miracle you might reply.

I am going to risk being rude now, but you need to calm down. You're a really good person and I know it because I've watched your very old posts and you're somebody I admire.

So understand that whatever I have written against you, was legitimate, for whatever reason you think it's not.

I'm still confused as to why you got offended.
So I am obviously far less experienced than everyone here so please excuse my ignorant questions.

1) Would it be bad for my program to dump any extraneous characters that the user inputs?

For context, the above function is part of a console game I am making. The console game is called Bull Cow Game and in the game, the user has to guess what the secret word is. The secret word is four characters long and so I do not want the user to be able to input more than 4 characters or, worse, enter too many characters (perhaps using an external program) to cause a buffer overflow. Also, because my program is comparing the secret word to the user's input, the user's input can't be more than 4 characters or else the program will erroneously try to access an array index location that does not exist.

2) Would using a (std::cin >> foo) boolean in a while loop be key in making sure the buffer does not accept too many characters from the user?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <string>
#include <iomanip>

int main ()
{
    const int NCHARS = 4 ;

    std::string guess ;

    // read in exactly four non white space characters into string guess
    guess.clear() ;
    while( guess.size() < NCHARS )
    {
        std::cout << "enter a word containing exactly " << NCHARS << " characters: " ;

        // do not accept more than the first NCHARS characters
        std::cin >> std::setw(NCHARS) >> guess ;

        // extract and throw away everything else in this input line
        std::cin.ignore( 1000000, '\n' ) ;
    }

    std::cout << "your guess is: " << std::quoted(guess) << '\n' ;
}
Thank you for posting that code, @JLBorges.

My question now would be:

why would I need to use std::cin.ignore() after std::setw() already refused to accept anything other than the first four characters in to the "guess" variable? Doesn't setw() prevent the user input after the first four characters from being placed in to the cin buffer?
std::setw() will only tell how many characters cin should read. The rest of the characters that was typed in by the user would still stay in the stream. So if they're not discarded then they will be read by the next attempt to read the stream.

Put this and comment out the cin.ignore statement.
1
2
3
    std::cout << "your guess is: " << std::quoted(guess) << '\n' ;
    getline(std::cin, guess);
    std::cout << guess;
Then try giving an input of larger than 4 characters and you'll see.
So is the stream and cin two different buffers?
Last edited on
Cin doesn't have a buffer.
Pages: 12