Scanf() not able to detect wrong input - c

int i, f;
f = scanf("%d", &i);
When I enter input as 3333333333333333333333 (greater than the capacity of int). Shouldn't the value of f be 0?

Shouldnt the value of f be 0?
With standard C, no. With scanf("%d",&i), on int overflow, the result is undefined.
With scanf() in Unix (of which there are variations), I find no prevention of undefined behavior with overflow.
Best to ditch (not use) scanf() and use fgets() for all user input.
Code could try a textual width limit and a wider type:
intmax_t bigd;
// vv --- width limit
if (scanf("%18jd",&bigd) == 1 && bigd >= INT_MIN && bigd <= INT_MAX) {
d = (int) bigd;
} else {
puts("Oops");
}
Yet that has trouble on novel implementations where int is as wide as intmax_t.
scanf() returns 0 when no int textual input found.
A key design element missing from OP's questions is what should happen to user input that exceeds the int range? Stop reading after the first `"333333333"?
What is best, depends on how OP wants to handle, in detail, error conditions - something not yet stated.

No, it can't be detected that way.
The below is not a portable solution, but it works in gcc12.1, clang14.0 and msvc19.32. It may stop working in later releases.
You need to set errno = 0; first and then check it for range errors:
#include <errno.h>
// ...
errno = 0;
f = scanf("%d",&i);
if(f == 1 && errno != ERANGE) {
// success
}
For portability, read this from an early draft of the C2x standard:
Unless assignment suppression was indicated by a *, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a
conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
A better (as in portable) option to detect this would be to read into a char[] buffer first and then use strtol() to convert it to a number. From the same standard draft:
The strtol, strtoll, strtoul, and strtoull functions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any), and the value of the macro ERANGE is stored in errno.
Here's a demonstrative program using strtol() (which converts to long):
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// A wrapper around `strtol` to convert to `int`
int strtoi(const char *str, char **str_end, int base) {
int errno_save = errno;
errno = 0; // clear it from any previous error (must be done)
long result = strtol(str, str_end, base);
if(errno == ERANGE) return result == LONG_MAX ? INT_MAX : INT_MIN;
if(result > INT_MAX || result < INT_MIN) {
errno = ERANGE;
return result > INT_MAX ? INT_MAX : INT_MIN;
}
// success or no conversion could be performed
errno = errno_save; // restore errno
return (int)result;
}
#define Size(x) (sizeof (x) / sizeof *(x))
int main(void) {
const char* strings[] = {
"3333333333333333333333 foo",
"2147483647 will probably succeed",
"2147483648 will probably fail",
"32767 guaranteed success",
"32767xyz",
"xyz",
"123",
""
};
char *end; // this will point at where the conversion ended in the string
for(unsigned si = 0; si < Size(strings); ++si) {
printf("testing \"%s\"\n", strings[si]);
errno = 0; // clear it from any previous error (must be done)
int result = strtoi(strings[si], &end, 10);
if(errno == ERANGE) {
perror(" to big for an int");
} else if(strings[si] == end) {
fprintf(stderr, " no conversion could be done\n");
} else if(*end != '\0' && !isspace((unsigned char)*end)) {
fprintf(stderr, " conversion ok,"
" but followed by a rouge character\n");
} else {
printf(" success: %d rest=[%s]\n", result, end);
}
}
}
Possible output:
testing "3333333333333333333333 foo"
to big for an int: Numerical result out of range
testing "2147483647 will probably succeed"
success: 2147483647 rest=[ will probably succeed]
testing "2147483648 will probably fail"
to big for an int: Numerical result out of range
testing "32767 guaranteed success"
success: 32767 rest=[ guaranteed success]
testing "32767xyz"
conversion ok, but followed by a rouge character
testing "xyz"
no conversion could be done
testing "123"
success: 123 rest=[]
testing ""
no conversion could be done

scanf("%d", &i) does not detect overflow, worse even, scanf() has undefined behavior if the number exceeds the range of the destination type: depending on the implementation, the value of i could be -434809515, -1, 0, INT_MAX or any value including a trap value with or without some undesirable side effects.
The proper way to check the input is to read it as a line in an array of char and to parse it with strtol():
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char input[120];
char ch;
char *p;
long x;
int i;
printf("Enter an integer: ");
if (!fgets(input, sizeof input, stdin)) {
fprintf(stderr, "missing input\n");
return 1;
}
errno = 0;
x = strtol(input, &p, 0);
if (p == input) {
fprintf(stderr, "invalid input: %s", input);
return 1;
}
if (x < INT_MIN || x > INT_MAX) {
errno = ERANGE;
}
if (errno == ERANGE) {
fprintf(stderr, "number too large: %s", input);
return 1;
}
if (sscanf(p, " %c", &ch) == 1) {
fprintf(stderr, "trailing characters present: %s", input);
return 1;
}
i = (int)x; // we know `x` is in the proper range for this conversion
printf("The number is %d\n", i);
return 0;
}
You can encapsulate these tests in a getint() function:
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
/* read an int from a standard stream:
always update *res with the value read
return 0 on success
return -1 on out of range, value is clamped to INT_MIN or INT_MAX
return -2 on non a number, value is 0
only read characters as needed, like scanf
*/
int getint(FILE *fp, int *res) {
int n = 0;
int ret = 0;
int c;
while (isspace(c = getc(fp)))
continue;
if (c == '-') {
c = getc(fp);
if (!isdigit(c)) {
ret = -2;
} else {
while (isdigit(c)) {
int digit = '0' - c;
if (n > INT_MIN / 10 || (n == INT_MIN / 10 && digit >= INT_MIN % 10)) {
n = n * 10 + digit;
} else {
n = INT_MIN;
ret = -1;
}
c = getc(fp);
}
}
} else {
if (c == '+')
c = getc(fp);
if (!isdigit(c)) {
ret = -2;
} else {
while (isdigit(c)) {
int digit = c - '0';
if (n < INT_MAX / 10 || (n == INT_MAX / 10 && digit <= INT_MAX % 10)) {
n = n * 10 + digit;
} else {
n = INT_MAX;
ret = -1;
}
c = getc(fp);
}
}
}
if (c != EOF)
ungetc(c, fp);
*res = n;
return ret;
}
int main() {
int i, res;
printf("Enter an integer: ");
res = getint(stdin, &i);
switch (res) {
case 0:
printf("The number is %d.", i);
break;
case -1:
printf("Number out of range: %d, res=%d.\n", i, res);
break;
default:
printf("Invalid or missing input, res=%d.\n", res);
break;
}
return 0;
}

Related

Check if a number is an integer or not in C language

I want to check if a number given by a user is an integer or not in another way i want to verify if the input data is between −(2)^31= −2,147,483,648 and ((2)^31) - 1 =2,147,483,647
this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int x;
int y = pow(3,31) * (-1);
int z = pow(3,32) - 1;
printf("\n\ty = %d et z = %d \n\n", y, z);
scanf("%d", &x);
if ((x < y) || (x > z)) {
printf("x is not an integer");
}
else {
printf("x is an integer");
}
return 0;
}
But while running the program the result always showing me x is integer even if x is greater than 2,147,483,647 or lesser than −2,147,483,648.
Testing whether input is a valid int decimal numeral or is a decimal numeral in [-231, 231) is actually a bit complicated. The C standard does not provide a direct way to do this. What we can do is:
Read characters and check to see whether they are in the expected form: spaces, an optional minus sign (hyphen), and digits. (Any non-digits after the digits will be allowed and ignored.)
Try using strtol to convert the numeral to a long. We use strtol because there is no C-standard library routine for converting to an int (or your fixed bounds using 231) that provides error indications.
Compare the long produced by strtol to the int bounds.
Example code for int bounds follows. If you want bounds of -2147483648 and 2147483647 instead, substitute those for INT_MIN and INT_MAX. To be completely safe, the code should actually use long long and strtoll, since the C standard does not require long to be able to represent −2147483648.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
// Prepare a buffer.
size_t BufferSize = 100, BufferUsed = 0;
char *Buffer = malloc(BufferSize * sizeof *Buffer);
// Skip white space.
int c;
do
c = getchar();
while (isspace(c));
if (c == EOF)
{
printf("Input is not an int: EOF before \"-\" or digit seen.\n");
exit(EXIT_SUCCESS);
}
// Accept a hyphen as a minus sign.
if (c == '-')
{
Buffer[BufferUsed++] = c;
c = getchar();
}
// Accept digits.
while (isdigit(c))
{
Buffer[BufferUsed++] = c;
if (BufferSize <= BufferUsed)
{
BufferSize *= 2;
printf("Realloc: size = %zu, used = %zu.\n", BufferSize, BufferUsed);
char *NewBuffer = realloc(Buffer, BufferSize * sizeof *NewBuffer);
if (!NewBuffer)
{
fprintf(stderr, "Error, unable to allocate %zu bytes.\n",
BufferSize);
exit(EXIT_FAILURE);
}
Buffer = NewBuffer;
}
c = getchar();
}
// Ensure we saw at least one digit (input is not blank or just a hyphen).
if (BufferUsed == 0 || BufferUsed == 1 && Buffer[0] == '-')
{
printf("Input is not an int: No digits present.\n");
exit(EXIT_SUCCESS);
}
// Put back the unaccepted character, if any.
if (c != EOF)
ungetc(c, stdin);
// Terminate the string.
Buffer[BufferUsed] = 0;
// Attempt to convert the numeral to long.
char *End;
errno = 0;
long x = strtol(Buffer, &End, 10);
// Test whether strtol succeeded.
if (*End)
{
/* I do not expect this to occur since we already tested the input
characters.
*/
printf("Input is not an int: strtol rejected %c.\n", *End);
exit(EXIT_SUCCESS);
}
if (errno == ERANGE)
{
printf("Input is not an int: strtol reported out of range.\n");
exit(EXIT_SUCCESS);
}
if (x < INT_MIN || INT_MAX < x)
{
printf("Input is not an int: Value is outside bounds.\n");
exit(EXIT_SUCCESS);
}
printf("Input is an int, %ld.\n", x);
free(Buffer);
}
Maybe i think i should store the number on a char array and check if it contains the float character '.'
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
int main(){
char number[10];
int flag=0,i = 0;
printf("\n\nEnter a number: ");
scanf("%s", number);
while(number[i++] != '\0'){
if(number[i] == '.'){
flag = 1;
break;}}
if(flag)
printf("\n\n\n\tyou Entered a Floating Number not an integer number\n\n");
else
printf("\n\n\n\t you Entered an integer Number\n\n");
return 0;}

(C) Get safe int input

So I tasked myself to write a function, that:
overwrites an int with a safe value (not return gibberish if the
user decides to input char-s or anything bigger by absolute value
than (2^31-1)
if input exceeds (2^31 - 1) (meaning if the user inputs 8 or more
digits) the int must be overwritten with the upper value
Here is the code:
void getSafeIntWithBoundaries(int *dest, int lo, int hi, const char *message);
bool anyChars(const char *input, int len);
int main() {
int x;
getSafeIntWithBoundaries(&x, 1, 10, "Enter an integer between 0 and 10.");
printf("x = %d\n", x);
return 0;
}
void getSafeIntWithBoundaries(int * dest, int lo, int hi, const char * message) {
char input[33];
while (1) {
puts(message);
fgets(input, 33, stdin);
int len = strlen(input);
if (input[len - 1] == '\n') { input[len - 1] = '\0'; }
--len;
if (bool reset = anyChars(input, len)) {
puts("Try again.");
continue;
}
else {
int ret;
if (strcmp("2147483648", input) < 0) {
*dest = hi;
return;
}
sscanf(input, "%d", &ret);
ret = ret > hi ? hi : ret;
ret = ret < lo ? lo : ret;
*dest = ret;
break;
}
}
}
bool anyChars(const char * input, int len) {
for(int i = 0; i < len; i++) {
if (!isdigit(input[i])) {
return true;
}
}
return false;
}
A few more notes:
in getSafeIntWithBoundaries(...) I'm getting rid of the '\n', I'm
changing it for a '\0', respectively decreasing int len; which holds
the length of the input.
anyChars() checks whether the input contains any non digit char. If
it does, then the user has to re-enter. One of the problems is
however that in case of failure, message needs to be printed out only
once. If I input something ridiculously long, message will be printed
multiple times. I don't know how to fix this.
the strcmp() bit checks if the user entered a number bigger than
(2^31 - 1). If the user has, then the int must be overwritten with
the high value and the function needs to end. Problem is however, if
the user enters a very long number, the target int will be
overwritten with the low boundary. I don't know how to fix that
either.
2 ?s making sure the target int won't exceed its boundaries. I marked
the parts that I can't figure out with bold, essentially that's the
whole question.
Suggestions on improving the code are welcomed as well.
Suggestions on improving the code are welcomed
Code fails many cases
Overflow UB
When the range exceed int, sscanf(input, "%d", &ret) is undefined behavior.
Long lines not consumed
When input is more than 32 characters (including the '\n), left over input remains.
Null character input
Input starting with a null character '\0' lead to undefined behavior with input[len - 1]
Non ASCII input
isdigit(input[i]) is undefined behavior when input[i] < 0.
Assumed ranged
Code uses int assuming it covers the range 2^31 - 1. C requires int to have a
minimum range of [-32,767 ... 32,767].
Unclear goals
"if input exceeds (2^31 - 1) (meaning if the user inputs 8 or more digits)" --> What if input is `"0000000000000000000000000000000000001\n"? 35 zeros? It is in range yet exceeds 8 digits and exceed 33 character buffer.
End-of-file
puts("Try again."); does not make sense if input is closed. I'd expect int getSafeIntWithBoundaries() to return 1 on success, 0 on failure, EOF on end-of-file/input error.
Below is some untested code - will test later. I'll work on the message details later. It is certainty more than what one might think is needed to simply read an `int, but if you want robust code, it is work.
To read an entire line of input obliges reading until '\n' or EOF.
I'd tolerate leading and trailing spaces.
strtol() is good , but then the entire line needs to be read first. Recall valid input can have many leading spaces or zeros.
Do not overflow intmath- it is UB. Summing the value with negativesint` has greater range than the positive side.
Pre-C99 /,% has implementation defined behavior when the remainder is non-zero - so I avoided that.
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#define INT_MIN_LS_DIGIT ((-(INT_MIN + 10)) % 10)
#define INT_MIN_DIV_10 ((INT_MIN + INT_MIN_LS_DIGIT)/10)
int getSafeIntWithBoundaries(int * dest, int lo, int hi, const char *message) {
fputs(message, stdout);
fflush(stdout); // Insure data to sent out completely
int ch;
while (isspace((ch = fgetc(stdin))) && (ch != '\n')) {
;
}
bool positive = true;
if (ch == '-' || ch == '+') {
positive = ch == '+';
ch = fgetc(stdin);
}
bool digit_found = false;
bool overflow = false;
int sum = 0;
while (isdigit(ch)) {
digit_found = true;
int digit = ch = '0';
// Detect possible overflow
if (sum <= INT_MIN_DIV_10
&& (sum < INT_MIN_DIV_10 || digit > INT_MIN_LS_DIGIT)) {
sum = INT_MIN;
overflow = true;
} else {
sum = sum * 10 - digit;
}
}
if (positive) {
if (sum < -INT_MAX) {
sum = INT_MAX;
overflow = true;
} else {
sum = -sum;
}
}
if (sum > hi) {
sum = hi;
overflow = true;
}
if (sum < lo) {
sum = lo;
overflow = true;
}
*dest = sum;
while (isspace(ch) && ch != '\n') {
ch = fgetc(stdin);
}
if (ch == EOF && iserror(stdin)) {
return EOF; // Rare input error detected
}
if (!digit_found) {
return 1; // or a "No digit found" error code
}
if (overflow) {
errno = ERANGE;
return 1; // or a "Overflow" error code
}
if (ch != '\n' && ch != EOF) {
return 1; // or a "Extra trailing junk" error code
}
return 0;
}
strtol could be used to parse an integer from a string. It provides for overflow and the pointer to the last character allows for testing for valid terminating characters. This set the range to 0 and INT_MAX but any range from INT_MIN to INT_MAX could be used. The terminating character is nul but could be comma, semicolon or any appropriate character.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
//inputs
// char *line : pointer to text to be parsed
// char **next : pointer to pointer to allow modification of caller's pointer
// char *term : pointer to characters to be considered terminators
// int *value : pointer to int to allow modification of caller's int
// int min : minimum value of range
// int max : maximum value of range
// returns : 0 failure or 1 success
int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max)
{
long int input = 0;
char *end = NULL;//will point to end of parsed value
if ( line == NULL) {
return 0;
}
errno = 0;
input = strtol ( line, &end, 10);//get the integer from the line. end will point to the end of the parsed value
if ( end == line) {// nothing was parsed. no digits
printf ( "input [%s] MUST be a number\n", line);
return 0;// return failure
}
// *end is the character that end points to
if ( *end != '\0' && !( delim && strchr ( delim, *end))) {// is *end '\0' or is *end in the set of term characters
printf ( "problem with input: [%s] \n", line);
return 0;
}
if ( ( errno == ERANGE && ( input == LONG_MAX || input == LONG_MIN))
|| ( errno != 0 && input == 0)){// parsing error from strtol
perror ( "input");
return 0;
}
if ( input < min || input > max) {// parsed value is outside of range
printf ( "input out of range %d to %d\n", min, max);
return 0;
}
if ( next != NULL) {// if next is NULL, caller did not want pointer to end of parsed value
*next = end;// *next allows modification to caller's pointer
}
if ( value == NULL) {
return 0;
}
*value = input;// *value allows modification to callers int
return 1;// success
}
int main( int argc, char *argv[])
{
char line[900] = {'\0'};
int valid = 0;
int number = 0;
do {
printf ( "Enter number or enter quit\n");
fgets ( line, sizeof ( line), stdin);//read a line
if ( strcmp ( line, "quit\n") == 0) {
return 1;// if quit is entered, exit the program
}
line[strcspn ( line, "\n")] = '\0';//remove trailing newline
valid = get_int_range ( line, NULL, "", &number, 0, INT_MAX);// call to parse a value
} while ( !valid);// on failure, keep looping the above
printf ( "input is %d\n", number);
return 0;
}

Reading integers with commas between them

I assumed using strtok would be best because of the formatting of the input.
But I've run into a few problems when trying to detect errors:
an example of a line the program would read:
.data 123,456,89
.data 12, 34, 53 , 64
these are all ok.
My problem is when the input is incorrect, for example:
.data 200 4000 // no comma speration
.data 1, ,3 // ,3 should be an error
.data 4, // the extra , should be an error
.data 12.2 // the .2 should be an error
and so on
My code (SIZE is for buffer size = 30, valid_num goes through the token to see if all the chars are numbers), the idea was to first check the validity of the tokens and add them to a buffer, if all numbers are valid, add the numbers to my data base:
while((sptr = strtok(NULL, ", \t\n")) != NULL){ //this is after reading using strtok before.
if(i < SIZE && valid_num(sptr)){ //buffer is not full and the token contains only numbers
temp_num = atoi(sptr);
if(temp_num >= MIN_VAL && temp_num <= MAX_VAL){ //number is within the required size
buffer[i] = temp_num; /*fill buffer*/
i++;
}
else{
fprintf(stderr, "(%d) Error: %d is out of bounds. Valid numbers are between %d and %d\n", line_count, temp_num, MIN_VAL, MAX_VAL);
}
}
else{
fprintf(stderr, "(%d) Error: %s is not a valid number\n",line_count, sptr);
}
tok_count++;
}
if(i == tok_count){ //if all tokens were read correctly, add the data to database.
DC += add_data(buffer, tok_count, DC, data_Table);
}
else{
if(sptr != NULL){
fprintf(stderr, "(%d) Error: %s is not a digit, .data can only be used for integers\n", line_count, sptr);
}
}
Should I try to do the same but with sscanf, even though the length of the input is unknown?
How can I enforce a certain pattern? number - comma - number ...
Perhaps using a few different strtok inside the loop?
There are many ways to parse the line.
OP's temp_num = atoi(sptr); does not detect overflow as 1) overflow with atoi() is undefined and 2) there is no error return value.
I believe the below will cope with all hostile input. It does not use strtok(), but strtol() to find non-numeric input.
Making use of helper functions provides clarity of each step.
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
void consume_whitespace(char **input) {
while (isspace((unsigned char ) **input))
(*input)++;
}
int parse_int(char **input, int *dest) {
char *endptr;
errno = 0;
long y = strtol(*input, &endptr, 10);
if (*input == endptr) return -1; // no conversion
if (errno) return -1; // overflow
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (y < INT_MIN || y > INT_MAX) return -1; // overflow
#endif
*input = endptr;
*dest = (int) y;
return 0;
}
int parse_data_line(char *input, const char *prefix, int *dest, int n) {
size_t prefix_length = strlen(prefix);
if (memcmp(input, prefix, prefix_length)) return -1;
input += prefix_length;
int i;
for (i = 0; i < n; i++) {
consume_whitespace(&input);
if (*input == '\0') break;
if (i > 0 && *input++ != ',') return -1;
if (parse_int(&input, &dest[i])) return -1;
}
consume_whitespace(&input);
if (*input) return -1; // extra text
return i;
}
Example usage
#define SIZE 30
int main() {
int numbers[SIZE];
char *input = foo();
int count = parse_data_line(input, ".data", numbers, SIZE);
if (count < 0) puts("Fail");
else bar(numbers, count);
}

How to test input is sane

Consider the following simple C program.
//C test
#include<stdio.h>
int main()
{
int a, b, c;
printf("Enter two numbers to add\n");
scanf("%d%d",&a,&b);
c = a + b;
printf("Sum of entered numbers = %d\n",c);
return 0;
}
How do you check the values entered are actually two integers in some sensible range? Currently, if you just enter "a" and then return you get the output "Sum of entered numbers = 32767".
Examples of incorrect input I would like to prevent.
2 3 4 (wrong number of numbers)
apple (not a number)
11111111111111111111111111 1111111111111111111111111111111111111 (numbers out of range)
Or should I be using fgets and sscanf or even strtol ?
User input is evil. Parse per:
(optional whitespace)[decimal int][whitespace][decimal int](optional whitespace)
strtol() and family have better error handling than scanf().
Coda: Best to handle user input in a helper function. Break into 2 parts: I/O and parsing.
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// return 1 (success), -1 (EOF/IOError) or 0 (conversion failure)
int Readint(const char *prompt, int *dest, size_t n) {
char buf[n * 21 * 2]; // big enough for `n` 64-bit int and then 2x
fputs(prompt, stdout); // do not use printf here to avoid UB
fflush(stdout); // per #OP suggestion
if (fgets(buf, sizeof buf, stdin) == NULL) {
return -1;
}
const char *p = buf;
while (n-- > 0) {
char *endptr;
errno = 0;
long l = strtol(p, &endptr, 10);
if (errno || (p == endptr) || (l < INT_MIN) || (l > INT_MAX)) {
return 0;
}
*dest++ = (int) l;
p = endptr;
}
// Trailing whitespace OK
while (isspace((unsigned char) *p)) p++;
// Still more text
if (*p) return 0;
return 1;
}
int main() { // for testing
int Result;
do {
int dest[2] = { -1 };
Result = Readint("Enter two numbers to add\n", dest, 2);
printf("%d %d %d\n", Result, dest[0], dest[1]);
} while (Result >= 0);
return 0;
}
You can use like:
if( scanf("%d%d",&a,&b) == 2)
{
//two integer values has been read successfully
//do your stuff here
}
else
{
//Wrong input
}
Also you can do this to prevent anything after second number
int a,b;
char c;
if( scanf("%d%d%c", &a, &b, &c) == 3) {
if (c == '\n') {
puts("good");
}
} else {
puts("bad");
}
return 0;
}
You can use the following macro
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
and you call it in this way in the main
int main()
{
int a, b, c;
printf("Input first integer, valid choice between 0 and 10: ");
SCAN_ONEENTRY_WITHCHECK("%d",&a,(a>=0 && a<=10));
printf("Input second integer, valid choice between 0 and 10: ");
SCAN_ONEENTRY_WITHCHECK("%d",&b,(b>=0 && b<=10));
c = a + b;
printf("Sum of entered numbers = %d\n",c);
return 0;
}
for more detail concerning this macro please refer to: Common macro to read input data and check its validity
A simple way would be,
int a=0, b=0, c=0;
initialise them to 0
Additionally, the check suggested by Midhun is good to check if there are two inputs.
you can test this one.
#include <stdio.h>
int main(void)
{
int a, b, c;
printf("Enter two numbers to add\n");
scanf("%d%d",&a,&b);
if(scanf("%d%d",&a,&b) == 2)
{
c = a + b;
printf("Sum of entered numbers = %d\n",c);
}
return 0;
}

How to implement strict checking getInt() function?

I have written following code to get an integer from keyboard.
It will prompt an Error message until you give a valid integer value (either negative or positive ).
One condition is It has to check every possible test cases
like:
-3.2
5.0
984237.4329
0.343
.434
12344.
adfs34
233adds
3892710492374329
helloIamNotainteger
For all of this tests it should fail.It will pass only for int >=INT_MIN && int <=INT_MAX
value.
My Running code is :
#include<stdio.h>
#include<limits.h>
int min=INT_MIN;
int max=INT_MAX;
int main()
{
char str[50],c; //I have taken size 50 please ignore this
int check;
do
{
int flag=1,i=0,j=0,num=0;
check=0;
printf("Enter an Integer : ");
while((c=getchar())!='\n')
str[i++]=c;
if(str[0] == '-')
{
flag = -1;
j++;
}
for(;j<i;j++)
{
if(str[j] >= '0' && str[j] <= '9')
num=(str[j]-'0') + num*10;
else
break;
}
if(j<i)
{
printf("Not an Integer, Please input an integer \n");
}
else if(num < min || num >max)
{
printf("Integer is out of range,Please input an integer \n");
}
else
{
num *=flag;
printf("The given number is : %d\n",num);
check=1;
}
}while(check == 0);
return 0;
}
One example : For values like this.
83429439803248832409 (It's integer but it should fail because of range )but it passes and give some other integer value.
How to solve this within my code or any better idea to implement getInt() ?
The easiest way to do this is to use standard library functions.
#include <limits.h>
#include <stdlib.h>
int getInt (const char *s)
{
long int n = strtol (s, NULL, 10);
if (n < INT_MIN || n > INT_MAX)
/* handle overflows */
else
return (int) n;
}
To handle other errors, you can several conditions.
#include <errno.h>
int getInt (const char *s, size_t size)
{
const char *pEnd1 = s + size;
char *pEnd2;
long int n;
errno = 0;
n = strtol (s, &pEnd2, 10);
if (n < INT_MIN || n > INT_MAX || errno != 0 || pEnd1 != pEnd2)
/* error */
else
return (int) n;
}
Hey you are trying to store a value which is more than 32768 into the integer(not unsigned). So when you do that it will display some garbage value which was present in the storage variable. As you know that integers in c are having memory limits. Like int datatype of unsigned type can store values from 0 - 65535. So trying to store a number more than that will cause issues. If need to store bigger numbers try using long int datatype. Maybe it might help. But that datatype is also having memory restrictions with values close to 4lakh or something.
Hope that helps.
Although this would better fit as comment to Kirilenko well checking solution, my note would be to long so I'll be posting it at as answer.
The main problem with the converison functions is that it's difficult (strtol()) to impossible (atoi()) to test whether the conversion did what was expected.
So when trying to make things more reliable (as atoi()) and easier to use (as strtol()) solutions like Kirilenko's would be used.
Anyhow the approach provided by Omkant still suffers the misdesign of not being capable if something went wrong in the conversion (from the callers perspective).
So the interface should better be like that of lots of other system function, that return their outcome as function value:
/*
* Tryies to convert the first 'size' characters of 's' to an 'int' and optionally
* writes it to '*result'.
*
* Returns the number of characters converted or any qualified negative error code
* on failure.
*/
int getInt(
const char * s, /* source string to try to be converted to an integer */
size_z size, /* number of digits to be converted (shall not be > strlen(s)) */
int * result /* optional reference to an int to place the conversion result in */
);
And, As a notable side effect, by pass NULL as last parameter one is capable of simply testing whether the conversion would work, and in addtion one could receive the number of digits the resulting integer would need.
To then still be able to use this conversion function as if it was returning its result as a function value, what might be handy in situations, one might like to use the following macro:
GETINT(str, size, result, rc) \
(rc = getInt(str, size, &result), result)
Usage:
char s[] = "42";
int rc = 0;
int i = GETINT(s, 2, i, rc);
if (rc)
/* some error */
else
/* use i */
Here is the working code : please see this , I did that wihtout strtol and it satisfies all conditions and takes only int
#include<stdio.h>
#include<limits.h>
#include<string.h>
int main()
{
int num;
char str[500],c;
int check;
char max[12];
char min[12];
sprintf(max,"%d",INT_MAX);
sprintf(min,"%d",INT_MIN);
do
{
int flag=1,i=0,j=0;
num=0;
check=0;
printf("Enter an Integer : ");
while((c=getchar())!='\n')
str[i++]=c;
str[i]='\0';
if(str[0] == '-')
{
flag = -1;
j++;
}
for(;j<i;j++)
{
if(str[j] >= '0' && str[j] <= '9')
check = 1;
else
{
check = 0;
break;
}
}
if(check == 0)
{
printf("Not an Integer, Please input an integer \n");
}
/************Start of checking integer range **************/
else
{
if( (flag == -1 && (strlen(str) > strlen(min))) ||
(flag == 1 && (strlen(str) > strlen(max))) )
{
check = 0;
printf("Integer is out of range, \n");
}
else if(flag == -1 && (strlen(str) == strlen(min)) )
{
i=0;
while(min[i]!='\0')
{
if (str[i] > min[i])
{
check = 0;
printf("Integer is out of range \n");
break;
}
i++; }
if(check == 1)
{
for(j=1;j<strlen(str);j++)
num=(str[j]-'0')+num*10;
num *=flag;
printf("The given number is : %d\n",num);
}
}
else if(flag == 1 && (strlen(str) == strlen(max)) )
{
i=0;
while(max[i]!='\0')
{
if (str[i] > max[i])
{
check = 0;
printf("Integer is out of range\n");
break;
}
i++;
}
if(check == 1)
{
for(j=0;j<strlen(str);j++)
num=(str[j]-'0')+num*10;
num *=flag;
printf("The given number is : %d\n",num);
}
}
else
{
for(j=0;j<strlen(str);j++)
num=(str[j]-'0')+num*10;
num *=flag;
printf("The given number is : %d\n",num);
}
}
/************End of checking integer range ****************/
}while(check == 0);
return 0;
One easy way would be to compare them as strings. First of all, note that a 32 bit integer cannot be more than 10 digits (and a sign).
int32_t get_int32()
{
char input[13];
char check[12];
int32_t result;
if (scanf("%12s", input) != 1)
/* handle error */
/* ignore rest of number if any */
ungetc('x', stdin);
scanf("%*s");
/* if length is bigger than 11, error */
if (strlen(input) > 11)
/* handle error */
if (sscanf(input, "%"SCNd32, &result) != 1)
/* handle error */
sprintf(check, "%"PRId32, result);
if (strcmp(input, check) != 0)
/* handle error */
return result;
}
Note that the strlen check can be ignored and the strcmp will take care of that. Also note that if you get input and check large enough (say 25), you can safely use int instead of int32_t because you'd know that it can't be more than 64 bits (at least for many years).

Resources