Read character to int without crashing

Pages: 12
In C, is there a relatively simple way of stopping a program from crashing if a character value is entered into an integer variable?
Not with std::cin.
However, you can read a string value and convert it to an integer easily.
I would recommend looking at functions such as strtol. strtol returns 0 when the string cannot be parsed into a number.
http://www.cplusplus.com/reference/cstdlib/strtol/
scanf returns the number of arguments that was successfully read. Every time you use scanf check that the return value is correct and take appropriate actions if not.
Last edited on
By std::cin do you mean standard input in general, or just std::cin in C++?

I'm looking for a way in C, using scanf(). Also, it's important that I can do it without having to make the variable a string. When I change the data type of my variables, even if I then convert them to ints after input using atoi(), my program no longer works properly.
@Peter87:
How do I do that?
My apologies, I glanced over
In C,
in your first post.
Peter87 is talking about the integer return value that scanf returns. Scroll to the section labeled Return Value here:
http://www.cplusplus.com/reference/cstdio/scanf/
@kevinkjt2000:
No worries.


http://www.cplusplus.com/reference/cstdio/scanf/

I had a look, but I don't follow. Could you explain how I would stop reading characters into integer variables from crashing the program?
Last edited on
http://ideone.com/X9kLhE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main() {
	int x, number_read;
	do {
		number_read = scanf("%d", &x);
		if(number_read == 0) {
			//printf("Unable to read integer\n");
			scanf("%*s"); //discard invalid input
		} else {
			printf("The integer is: %d\n", x);
		}
	} while(number_read != EOF);
	
	return 0;
}

I will leave why the extra 5 prints at the end as an exercise for the reader.

Edit: I saw the SO link Peter87 posted and I changed fseek to be scanf("%*s")
Last edited on
It is not scanf but what happens after it that makes the program crash.

Here is an example of how you can test the return value of scanf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main()
{
	printf("How old are you?\n");
	int age;
	if (scanf ("%d", &age) < 1)
	{
		printf("Invalid age!\n");
	}
	else
	{
		printf("You are %d years old.\n", age);
	}
	return 0;
}


If you want the program to keep asking the user until a valid input is entered you might want to read this SO answer that I found:
http://stackoverflow.com/questions/25765040/c-programming-loop-until-user-inputs-number-scanf/25765167#25765167
Ok, this is what I've come up with based on your suggestions.
1
2
3
4
5
6
7
8
9
10
11
    while(scanf("%d", option) < 1)
    {
        if(*option < 1 || *option > 5)
        {
            printf("\nInvalid option.\nPlease choose an option(1 - 5): ");
        }

        printf("\nInvalid option.\nPlease choose an option(1 - 5): ");

	scanf("%*s");
    }


This is inside a function, option has been passed by reference. I want to only accept a number between 1 and 5, as well as no characters. What I have doesn't work. Any advice?
You should make the if condition part of the loop condition.
1
2
3
4
5
6
    while(scanf("%d", option) < 1 || (*option < 1 || *option > 5))
	{
	    scanf("%*s");

            printf("\nInvalid option.\nPlease choose an option(1 - 5): ");
	}


When I do this, it waits for two inputs when entering numbers outside the range. It handles characters fine though. Why?
That is because scanf happens twice for numbers such as 7.
You need to store the return value from the first scanf. Then you can wrap the second scanf in an if statement for the 0 return value case.
IMO you should just read a string and use strtol, because error checking is far easier.
@kevinkjt2000:
I appreciate the advice but I would really like to keep going the way you've shown me so far, at least just for this project.

I tried what you suggested, but I'm probably doing it wrong as it causes all error handling to break. I don't suppose you could change my last post above to demonstrate what you mean?
http://ideone.com/WagBeL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

int main(void) {
	char buffer[100];
	long num;
	bool error = false;
	
	do {
		if(error) printf("The number must be in the range 1 to 5.\n");
		fgets(buffer, sizeof(buffer), stdin);
		//scanf("%100s", buffer);
		num = strtol(buffer, NULL, 10);
		error = true;
	} while(num < 1 || num > 5);
	
	printf("chosen number: %ld", num);
	
	return 0;
}

I feel terrible when writing C code, but if I do have to use the C library I try to watch out for buffer overflows. scanf without a specified maximum length is vulnerable. commented underneath fgets is the safe scanf alternative, but the length of the buffer is hardcoded. I recommend using fgets instead.
I feel bad for saying this as I can see the effort you've gone to to help me out, but I don't understand how that code you just posted works and I 'm quite sure it doesn't fit into my design. Could you possibly change the last code I posted, with your previous suggestions.

You need to store the return value from the first scanf. Then you can wrap the second scanf in an if statement for the 0 return value case.

It must be possible if you suggested it, right?
Last edited on
My first example showed how you can check that 0 return case. All you need to add is a statement that breaks out of the loop if the number is in the range 1 to 5.

Here is my earlier example with that modification
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main() {
	int x, number_read;
	do {
		number_read = scanf("%d", &x);
		if(number_read == 0) {
			//printf("Unable to read integer\n");
			scanf("%*s"); //discard invalid input
		} else {
			if(1 <= x || x <=5) break;
			printf("Please enter a number in the range 1 to 5");
		}
	} while(number_read != EOF);
	printf("The integer is: %d\n", x);
	
	return 0;
}
Thanks @kevinkjt2000, that works a charm with some small modifications.

Now, as amazed as I am with how well this works, I would love to know just how scanf("%*s") works and what exactly is being read into number_read from scanf() and why. In all my (limited) experience I've never seen scanf() used that way.

Also, is 'EOF' what is returned to the integer number_read, if whatever is being read by scanf() is an invalid data type, based on the data type expected by the variable being read to?

Also also, is 'EOF' equivalent to 'NULL' in this regard?
I would love to know just how scanf("%*s") works

The scanf page talks about sub-specifiers such as *.

what exactly is being read into number_read from scanf()

Did you read that section labeled "Return Value" on the scanf page?

EOF stands for end-of-file. The "Return Value" section also mentions why EOF is returned.

Basically you should read this page that I linked to earlier:
http://www.cplusplus.com/reference/cstdio/scanf/
Do not worry about memorizing it, because that page is always there for reference. You could even print it to paper and tuck it away in a binder full of C stuff like I did.
I read the page but didn't find it very helpful. I thought you would be able to explain better, in 'plain english', so to speak.

From what I understand, though I'm probably wrong, 0 is the value returned from scanf() if an incorrect value was entered, based on the data type expected by the delimiter. You can choose to store this value and then create a condition that clears the stream if the value is 0, thereby stopping the program from entering into an infinite loop. Is that somewhat correct?
Pages: 12