Background:
I need the user to type in an int "k" key for an encryption program. For the program to work right, the user entered int needs to be between 1-25. It can't be higher. The problem is if the user enters something other than an int, the program either just continues, or the program goes into an infinite loop. The int "t" just acts as a true/false for the loop.

do
{
  t=1;
  cout << "\nEnter the encryption key (1-25): ";
  cin >> k;
  if ((k<1)||(k>25))
  {
      cout << "\nERROR: Enter a valid number moron!\n";
      t=0;
  }
}
while (!t);

I tried converting the value to a tmp char and checking the char to be between SOH-EM, but that results in the same problems.


Any help greatly appreciated :cheesy: Btw, its my first post, I think.

Recommended Answers

All 26 Replies

It is continuing like that because cin is trying to convert the alpha character that is in the keyboard buffer to numeric, but it fails and leaves the key in the keyboard buffer. The easiest way to correct this is to get the integer as a string the convert the string to int. Something like this will work:

do
{
  t=1;
   std::string input;
  cout << "\nEnter the encryption key (1-25): ";
  getline(cin,input);
  k = atol(input.c_str());
  if ((k<1)||(k>25))
  {
      cout << "\nERROR: Enter a valid number moron!\n";
      t=0;
  }
}
while (!t);

Thanx alot Ancient Dragon. Works great. Out of curiosity, what's the "std::" for?

if you do not specify "using namespace std" then you have to identify the namespace if it is not in global namespace.

Thanx again. I used "namespace std".

Noob question...
why not just define k as an int without resorting to the fancy lib stuff?
int k;
cin >> k;
won't that restrict the input sufficiently?

At first I did have the user enter "k" without any conditions, but if they entered something other than a number, my program got screwed up. I'm doing a Caesar's Cipher adaptation, and I have to add "k" to a user entered string, so "k" has to be between 1-25 for the program to work, as I limited the user's string to only letters (caps and small).

Try it, JRM, enter 12A and see what happens. Be sure you put your cin in a loop.

You can check the fail state of the stream to assist with type validation rather than accept input as a string, validate, and convert if necessary. It's no simpler than the other version, but it works.

1)declare variable
   int k = 0; 
2)attempt input 
   std::cin > k;
3)check the state variable of the stream
   if(std::cin.fail())
4)Do something if in failed state
   {
5)Reassign a default value to k---say user entered 5Q instead of 51. 
cin would assign 5 to the value of k, which would be desired.
cin would then try to put Q in k which would cause a failed state, but wouldn't remove the 5 from k (so k would have an incorrect input, 5 vs 51, eventhough it is a valid int) and would leave the invalid input in the input stream .
      k = 0;
6)clear the state bit (aka fail flag) of the stream
    std::cin.clear();
7)clear the input stream buffer of all unwanted information.  If you want to use this format and don't know what the following means, ask.  
    std::cin.ignore(std::<numeric_limits<streamsize>::max());
8)notify user of invalid input
    cout << "invalid input" << endl;
9)move on to whatever's next
    }

>> std::cin.ignore(std::<numeric_limits<streamsize>::max());
illegal syntax at '<' character. But otherwise interesting way to clear the keyboard buffer, just please post a corrected version. Too bad it doesn't work. In the example below, enter 123al;skfjlsdkf <Enter> The keyboard buffer is not cleared.

#include <iostream>
#include <limits>
using namespace std;

int main(int argc, char* argv[])
{
	int a;
	cout << "enter something ...";
	cin >> a;
   std::cin.ignore(std::numeric_limits<streamsize>::max());
   cout << "\nenter something else";
   cin >> a;
   cout << "a = " << a << endl;

	return 0;
}

Try putting cin.clear( ) before the cin.ignore( ) stmt and see if it works...

Try putting cin.clear( ) before the cin.ignore( ) stmt and see if it works...

I did and it doesn't. New code below

#include <iostream>
#include <limits>
using namespace std;

int main(int argc, char* argv[])
{
	int a;
	cout << "enter something ...";
	cin >> a;
	cout << "you entered " << a << endl;
	std::cin.clear();
// never gets past the next line 
	std::cin.ignore(std::numeric_limits<streamsize>::max());
	cout << "\nenter something else";
	cin >> a;
	cout << "a = " << a << endl;

	return 0;
}
Member Avatar for iamthwee

You'd be better off using stringstream in c++ rather that atol.

I never can remember the whole thing without refering to my cheat sheet, which I don't have with me.

std::cin.ignore(std::numeric_limits<streamsize>::max());

See if removing the angled bracket before numeric_limits does the trick. Oh, you also need to include the limits and, I believe, the ios header files for it to work. BTW, the first person I saw use this syntax is a distinguished poster here. If I still don't have it correct, maybe she will assist.

I never can remember the whole thing without refering to my cheat sheet, which I don't have with me.

std::cin.ignore(std::numeric_limits<streamsize>::max());

See if removing the angled bracket before numeric_limits does the trick. Oh, you also need to include the limits and, I believe, the ios header files for it to work. BTW, the first person I saw use this syntax is a distinguished poster here. If I still don't have it correct, maybe she will assist.

As you can see from my previous two posts I figured out the syntax error problem. who is this "distinguished poster" ?

I did and it doesn't. New code below

Dont you think you are forgetting something... as in what to ignore.:cheesy:

int main(int argc, char* argv[])
{
    int a;
    cout << "enter something ...";
    cin >> a;
    cout << "you entered " << a << endl;
    std::cin.clear();
// never gets past the next line...coz you didnt specify what to ignore

     std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n' );
    cout << "\nenter something else";
    cin >> a;
    cout << "a = " << a << endl;

    return 0;
}

Narue.

Member Avatar for iamthwee

Alternatively if you expect everything as a string, you don't need to clear nuffin.

And just convert to double or int where you need to. Works every time.

Dont you think you are forgetting something... as in what to ignore.:cheesy:

AhHa! That's it. :cheesy:

Alternatively if you expect everything as a string, you don't need to clear nuffin.

And just convert to double or int where you need to. Works every time.

which is the soluition I original posted. But I like to find new ways of doing something -- learn something new every day will keep the doctor away. :cheesy:

Member Avatar for iamthwee

which is the soluition I original posted. But I like to find new ways of doing something -- learn something new every day will keep the doctor away. :cheesy:

Ah sorrie I never read the entire post properly.

iamthwee---Yes, it's clearly debatable which version of type validation is easier/prefered. They both take some effort.

AncientDragon----I usually just use cin.ignore() in my code, so I keep forgetting that, according to cppreference.com, the second parameter to ignore() defaults to EOF rather than newline. sorry.

s.o.s---Thanks for your assist! As I'm sure you're aware, but for those who aren't, and to refresh my memory yet again, ignore() will ignore all char in the input buffer, irrespective of the value of the char, up to the number of char indicated by the first parameter, unless it encounters the terminating char, indicated by the second parameter (which defaults to EOF, not newline as I had thought), or EOF first. So there are three ways ignore() will end, finding the indicated number of char, finding the non-default terminating char, or finding EOF, whichever comes first.

Try it, JRM, enter 12A and see what happens. Be sure you put your cin in a loop.

well, here's what I did;

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

    do
{
  t=1;
  cout << "\nEnter the encryption key (1-25): ";
  int k;
  cin >> k;
  if ((k<1)||(k>25))
  {
      cout << "\nERROR: Enter a valid number moron!\n";
      t=0;
  }
}
while (!t);
        return 0;
}

Rather than going into a infinite loop, it will just fall though.
If the operator is coherent enough to enter numbers only, it works completely as expected.
I tried adding ||(k==NULL) as a third condition, but the compiler gave me a stern warning, but compiled it anyway. It still worked as before.

That's exactly what I did, except I declared "k" as a global too. The problem is that the user may choose enter a char for whatever reason, and if they do, it gets screwed. I don't want that to happen.

That's exactly what I did, except I declared "k" as a global too. The problem is that the user may choose enter a char for whatever reason, and if they do, it gets screwed. I don't want that to happen.

which is why it is probably better to get keyboard input as a string so that you can parse the string to see if it contains any invalid characters (in your case any non-numeric digits). If it does, then display an error message and make them re-enter it. cin will not do that for you.

Try it, JRM, enter 12A and see what happens. Be sure you put your cin in a loop.

well, here's what I did;

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

    do
    {
        t=1;
        cout << "\nEnter the encryption key (1-25): ";
        int k;
        cin >> k;
        if ((k<1)||(k>25))
        {
            cout << "\nERROR: Enter a valid number moron!\n";
            t=0;
        }
    } while (!t);
    return 0;
}

** code reformatted to a more proper form**
Rather than going into a infinite loop, it will just fall though.

My mistake. Try entering just S (or any letter), or an invalid value followed by the letter, like 34B ;)

which is why it is probably better to get keyboard input as a string so that you can parse the string to see if it contains any invalid characters (in your case any non-numeric digits). If it does, then display an error message and make them re-enter it. cin will not do that for you.

There is no question that accepting input only as a string and validating the string for a given type by parsing the contents of the string works, and is a solution available to anyone who knows how to create and parse a string. However, checking the fail state of input stream will allow for input type validation as well. Just remember, if the stream is in a failed state after attempted input, then you can't trust the value of any variable read to by cin and you need to clear both the stream and the input buffer before you attempt to use cin again. Of course, once the type is validated, by either method, then you need to validate the value of the input, if desired. Using the fail state of cin will allow you to skip the type conversion from string to some other type, but in the long run both processes are complicated enough that it boils down to personal knowledge and personal choice. As always, attention to detail is the key to success in either strategy.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.