C++ Detect Buffer Overrun

So here is what I have:

The user enters a number into an int. Now, I've solved if the user enters a character first, however, if there is a number first, I can't seem to figure out how to detect it.

So if the user enters a123, the programs returns an error.
But if the user enters 123a, then no error is returned. Instead, 123 is put into the int, and a is left to be caught the next time around, as if the user entered a123 the second time.

So what I need to detect is if there is any buffer left. Kinda like using sync, but if I use that, then it clears it, and then tells me that it was there, so that doesn't help because I need it left in the buffer, which should explain itself in part of my program run below.

I've added commentsfor clarifacation
1
2
3
4
5
6
7
Please enter number of A's: 12 //valid input
Please enter number of B's: a12 //Bad input
Error! "a12" is invalid. //Bad input told to user
Please enter a valid number: 12 //valid input
Please enter number of C's: 12a //Invalid input, yet C is gived valud of 12
Please enter number of D's: Error! "a" is invalid. //D gets left buffer of 'a'
Please enter a valid number:


As you see, C gets 12, and then D goes to run, but then gets the buffer of 'a' and returns an error.
What does your code look like?
This kind of question gets asked a lot.

The trick is to remember that the user expects to press ENTER after every input.
Hence, you need to read the entire line of input, then check it for errors.

Here's a thread where I offer a fancy solution to that.
http://www.cplusplus.com/forum/beginner/13044/page1.html (thread)
http://www.cplusplus.com/forum/beginner/13044/page1.html#msg62827 (solution)

You can do the same thing with a simple function though, to take an input string and convert it to an integer or indicate failure (via an exception or something).

Hope this helps.
You can do the same thing with a simple function though


So would this be a good way to do it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int good(char*);
//...
int n;
char ch[99];
cin>>ch;
n=good(ch);
//...
int good(char *ch){
  int n=NULL;
  for(int x=0;x<strlen(ch);x++){
    if(!isdigit(ch[x]))
      return 0; //0 gives n false value
  }
  else n=(n*10)+(ch[x]-48);//-48 convers from ASCII to number; n*10 allows 1+2=12
  return n;
}


Good or bad?

Note: If there are any errors in it, sorry. I just typed it in without testing it.

I might use your code, but I don't really understand it, and I perfer to only use code I understand. For bugs, as well as I would like it to be my code, not a code I just copy and paste without having a clue how it works.
Last edited on
You've got the right idea. You need to be careful about how you type stuff up though. You also have to be able to distinguish a valid integer from something else. You can use exceptions. Or you can use a reference argument to get the actual value and return the success/failure as boolean.

On line 9, don't use NULL, as you aren't working with pointers. (Use of the word 'NULL' hints at pointers.)
int n=0;

On line 14, don't use ASCII values directly. The compiler can do that for you.
n=(n*10)+(ch[x]-'0');

Your code doesn't consider the possibility that the user will enter a negative number. If such a response is valid, you will need to handle that.

'Good' is not a very good name for your routine -- be more specific.

Here is a good prototype for your routine:
bool convert_int( const string &s, int &result );
(I have renamed your variables a bit. 'ch' --> s, and 'n' --> result. This is more readable.)
Now, if the routine fails, return false. The caller can use the routine easily now:
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
#include <cctype>
#include <iostream>
#include <string>
using namespace std;

bool convert_int( const string &s, int &result );

int main() {
  string users_input;
  int    users_number;

  // Give the user explicit initial instructions and get his response
  cout << "Please enter an integer> " << flush;
  getline( cin, users_input );

  // Validate his response into a number
  while (!convert_int( users_input, users_number )) {

    // As long as his response is not correct, give him more explicit
    // instructions and get his new response
    cout << "Please, enter an INTEGER> " << flush;
    getline( cin, users_input );
  }

  // Give the user a cookie.
  cout << "Good job! You entered the number " << users_number << ".\n";
  return 0;
}

Hope this helps.
Last edited on
That help a LOT!

I'm not having to worry about negative numbers, because if the user enters a -, it returns false.

I am having one problem, if the user enters nothing, then it is still valid. I tried adding

1
2
3
4
5
s=="";
!s;
s=='\0';
s=="\0";
s=="\n";


to the end of the if statement that retuns false if it find a character, but each one either returns an error at compile time, or they just don't do anything.

My code

1
2
3
4
for(i=0;i<s.length();i++){
  if(!isdigit(s[i]) || s=="\n") return false;
  result=(result*10)+(s[i]-'0');
}


The rest is what you suggested. :)
Since the argument is a std::string, you can use the empty() method to check for an empty string.
1
2
if (s.empty())
  return false;

Glad to be of help.
Ahh, okay! I guess I should go learn about the rest of strings functions. I just finally went and looked up how to do strings, sence the book I'm using hasn't (for some reason) taught it yet.

Edit: Hmm, still not working.
Edit: Got it, had to put the statement in the while loop though, not in the function.

And one more question if you don't mind. If you don't have an answer off the top of your head, then I'll work on figuring it out, no need for you to. :)

My Problem is that if the user enters 0, then this here:

1
2
3
4
5
6
7
else if(ch=='\n'&&p==0){
  cout<<"\n\aError! \""<<name<<"\" has been corrupted.\n"
  <<"To repair, repeat setup process.\n\n"
  <<"Press Enter to terminate program.\n";
  cin.get();
  exit(1);
}

Gives an error when it reads it, because the value is 0, or no value.
This is reading from a file which the other function makes, and so if it hits the new line, without getting a value, then it returns an error.
Last edited on
Okay, I got a solution.
I added a boolian, and set it to false. Then, I added that it be true, once a value for P is found.


Here is the the code

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//...
void read(){
  char ch;
  int x=0,value=0;
  bool valid=false;

  fstream read(name,ios::in);
  if(!read)cout<<"\nError: Could not open "<<name<<"\n\n";

  while(read.get(ch)){
    if(isdigit(ch)){
      value=(value*10)+(ch-'0');//ch-'0' converts from ASCII to number
      valid=true;//Numrical value found, file not corrupt
    }
    else if(ch=='\n'&&valid==0){
      cout<<"\n\aError! \""<<name<<"\" has been corrupted.\n"
      <<"To repair, repeat setup process.\n\n"
      <<"Press Enter to terminate program.\n";
      cin.get();
      exit(1);
    }
    else if(ch=='\n'){
      //var.a[x]=value;
      cout<<var.a[x]<<endl;
      x++;
      value=0;
      valid=false;
    }
  }
  read.close();
}
//....
void writeTo(){
  int x;
  string user_input;
  int result;

  for(x=0;x<26;x++){
    cout<<"Please enter number of "<<char(x+'A')<<"'s: ";
    getline(cin,user_input);
    while(!chk_num(user_input, result) || user_input.empty()){
      cout<<"\nError: Please enter a valid number: "<<flush;
      getline(cin,user_input);
    }
    var.a[x]=result;
  }
//...
}
bool chk_num(const string &s, int &result){
  int i;
  result=0;
  for(i=0;i<s.length();i++){
    if(!isdigit(s[i])) return false;
    result=(result*10)+(s[i]-'0');
  }
  return true;
}


Thanks for all the help!
Last edited on
Topic archived. No new replies allowed.