简体   繁体   中英

entering a char using scanf and saving it in an int can cause undefined behaviour?

I am working on a code, and I tried to enter a char instead of integer, and the result was '2' regardless of the character I entered, is it undefined behaviour or some thing else ?

The code:

#include <stdio.h>
int f1(int n);
int f2(void);

int main(void)
{
    int t;

    printf("Enter a number: ");
    scanf("%d", &t);
    /* print proper message */
    t ? f1(t) + f2() : printf("zero entered.\n");
    return 0;
}

int f1(int n)
{
    printf("%d ", n);
    return 0;
}

int f2(void)
{
    printf("entered.\n");
    return 0;
}

when I entered a , the result was "2 entered", and when I entered g the result was "2 entered" and when I entered i,h,k,..... the result was the same. What is that?

If scanf() encounters something it cannot parse based on the specified format string, it simply stops and returns early. So it never writes anything to t (you're just seeing whatever indeterminate value t had before the call).

To handle this, you should always examine the return value of scanf .

The problem is, as you say, that scanf using %d format is expecting you to enter one or more ascii digits. It stops scanning the input at a non-digit character, so it never reads what you type and t has whatever value it had before the scant was called.

You need to check the return code of scanf . Have a look at the manpage :

Return Value

These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.

In other words, scanf does not write anything into t , it's uninitialized the whole time.

So, instead of this:

scanf("%d", &t);

try this:

int items_matched = scanf("%d", &t);
if (items_matched != 1) {
    printf("bad number entered\n");
    exit(1);
}

It is because scanf failed to parse you input. It expects you to enter a decimal digits since you used %d .

You have to check the return value of scanf to avoid this kind of behavior :

On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.

So :

int items_matched;

// ...
items_matched = scanf("%d", &t);   // Get the return value

if ( items_matched != 1 )          // Check it
{
    printf("Matching failure with scanf.\n");
    return 0;
}
else
{
    if ( t == 0 )
        printf("zero entered\n");
    else
        printf("%d entered\n", t);
}

You don't need your f1(t) + f2() who is quite confusing...

From the Linux man page

The format string consists of a sequence of directives which describe how to process the sequence of input characters. If processing of a directive fails, no further input is read , and scanf() returns. A "failure" can be either of the following: input failure, meaning that input characters were unavailable, or matching failure, meaning that the input was inappropriate.

In the C11 standard description of scanf ( 7.21.6.4 The scanf function ) section 3:

The scanf function returns the value of the macro EOF if an input failure occurs before the first conversion (if any) has completed. Otherwise, the scanf function returns the number of input items assigned, which can be fewer than provided for, or even zero, in the event of an early matching failure .

Emphasis is mine . So as @oli charlesworth said you should check the return value of scanf when in doubt :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM