Thread: Why is this hapening?

  1. #1
    Registered User
    Join Date
    Jul 2013
    Posts
    18

    Why is this hapening?

    Hey guys as some of you know I'm new to c I was experimenting a bit today just seeing what would happen if I input a char instead of an integer, expecting an error message as with Python and most other languages but I got something completely unexpected, the code I used is a basic calculator taking two integers and adding them together before printing the result:
    Code:
    #include <stdio.h>
    
    int main(void)
    {
        int num1; 
        int num2; 
        int sum; 
        
        printf("Enter the first integer: "); 
        scanf("%d", &num1); 
        printf("Enter second integer: ");
        scanf("%d", &num2);
        
        sum = num1 + num2; 
        printf("The sum of the two numbers is: %d\n ", sum); 
         
        getchar();   
        return 0;  
        
    }
    So I compiled and ran this and everything worked as expected until I thought to myself "This program expects a numeric value, I wonder what will happen if I just type a letter instead" expecting one of two things to happen:

    1 Some kind of error message and exit - The one I thought most likely.
    2 The program treats the characters as 1 and returning an end result of 2.

    However when I did this the output was:
    Code:
    Enter the first integer: s
    Enter second integer: The sum of the two numbers is: 32767
    and the program then exits. My question is what just happened? why does the program skip asking for another integer and return a value of 32767. I know it's a bit of a dumb question but it's intrigued me.

  2. #2
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    You can use ctype.h to check if the input you got is ok.
    Code - functions and small libraries I use


    It’s 2014 and I still use printf() for debugging.


    "Programs must be written for people to read, and only incidentally for machines to execute. " —Harold Abelson

  3. #3
    Registered User
    Join Date
    Jul 2013
    Posts
    18
    Not really sure how to use that as of yet but will look into it, although rather than preventing characters I don't want I was more interested in the result where did 32767 and why does it not generate an error and exit?

  4. #4
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    You can use ctype.h to check if the input you got is ok.
    Not really. If you enter a character for a numeric speifier scanf() will fail. The value of the variable is unchanged and until these "bad" entries are removed from the buffer any further numeric input will also fail.

    You should be checking the return value from scanf(), it should be equal to the number of format specifiers.

    Since your two variables are uninitialized the output of the program would be undefined.

    Jim

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    When scanf is reading a number, it stops reading when it encounters a non-digit character. By entering a single letter, you cause scanf to not read anything at all into num1. The letter is still sitting in the input buffer when the second scanf is called and of course assigns nothing to num2, leaving the letter in the buffer.

    Since your variables are uninitialized, you end up with the sum of whatever happened to be in num1 and num2 originally. If you initialize your vars to 0, you'll get 0 instead.

    You may have noticed that your getchar() is not keeping the console open. This is because, even when you enter numbers, a final newline character is left in the stream. You could hold the console like this:
    Code:
    while (getchar() != '\n') ;  // consume the rest of the line
    getchar();                   // wait for enter key

  6. #6
    Registered User
    Join Date
    Jul 2013
    Posts
    18
    I see that makes sense and thanks for the tip I hadn't really noticed that to be honest as I ran it from the terminal to start with but will keep that in mind for the future, why doesn't the program simply spit out an error message and quit though?

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    It does provide an error indication, but you ignore it by not checking the return value scanf() provides. Since this is a recoveralble error the compiler leaves it up to you, the programmer, to decide what to do about this problem. But since you ignore the error the program just continues.

    Jim

  8. #8
    Registered User
    Join Date
    Jul 2013
    Posts
    18
    I see thanks for the reply helpful as ever.

  9. #9
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    To expand on what jimblumberg and oogabooga said:

    If you want your program to complain when the input is not what is expected, you have to check if the input is what you expected. The way your code is written now just assumes the input was as expected.

    Code:
    #include <stdio.h>
    
    int main(void)
    {
        int num1; 
        int num2; 
        int sum; 
        
        printf("Enter the first integer: ");
        if (scanf("%d", &num1) != 1) {
            printf("That's not an integer.\n");
            return 1;
        }
    
        printf("Enter second integer: ");
        if (scanf("%d", &num2) != 1) {
            printf("That's not an integer.\n");
            return 1;
        }
        
        sum = num1 + num2; 
        printf("The sum of the two numbers is: %d\n ", sum); 
         
        getchar();   
        return 0;  
    }
    Since scanf() or fscanf() do not consume input they cannot convert, the non-number the user specified stays in the input buffer. You could read it and display it, if you wanted to. Because input is normally line-buffered, it's best to consume the un-scannable input up to (and including) a newline or EOF:
    Code:
    #include <stdio.h>
    
    int main(void)
    {
        int num1, num2, sum, c;
    
        printf("Enter the first integer: ");
        if (scanf("%d", &num1) != 1) {
            c = getchar();
            while (c != EOF && c != '\n') {
                putchar(c);
                c = getchar();
            }
            printf(": Not an integer.\n");
            return 1;
        }
    
        printf("Enter second integer: ");
        if (scanf("%d", &num2) != 1) {
            c = getchar();
            while (c != EOF && c != '\n') {
                putchar(c);
                c = getchar();
            }
            printf(": Not an integer.\n");
            return 1;
        }
        
        sum = num1 + num2; 
        printf("The sum of the two numbers is: %d\n ", sum); 
         
        getchar();   
        return 0;  
    }

  10. #10
    Registered User
    Join Date
    Jul 2013
    Posts
    18
    Sorry, but I only started learning C yesterday and do not understand what this does exactly, I understand the theory behind it as it checks if the input is indeed an integer but i don't understand how or why this works. Sorry for being stupid I do actually feel bad for asking all these questions without contributing a thing but could you please explain to me the idea behind the syntax? again I apologize just trying to learn as much as I can.

  11. #11
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    scanf() will return the number of items it has scanned, and successfully stored into a variable. If you use the %d format specifier for scanf(), it will NOT succeed in storing an entered value that is not an integer.

    So, the only problem is, the bad value that was entered, was also not removed from the input stream (keyboard buffer in this case), which you don't want. The while loop is needed to remove it, and then the "Not an integer" message is printed, and the outer loop is ready for another try at correct data being entered.

  12. #12
    Registered User SCRIPT_KITTEH's Avatar
    Join Date
    Apr 2013
    Posts
    74
    Code:
    if(scanf("%d", &num1) != 1)
    {
    get rid of bad input
    }
    When scanf tries to read input, it "returns" the number of correctly read items. So scanf("%d", &num1) != 1 means, scanf did not successfully return 1 item. scanf("%d", &num1) = 0 would effectively be the same. So imagine inbetween scanf and your keyboard there is a virtual pathway called a "stream." You send "s" into the stream by typing "s" and then the enter key. Because the integer specifier, %d is in this scanf, it's not going to accept "s." Where will it go? It's just stuck in the stream. getchar() pulls it out. putchar() prints it before the "not an integer" message, in Nominal's example.

    By the way, in case you did not know, EOF means end of file, and in C keyboard input is treated as if it were a file.

  13. #13
    Registered User
    Join Date
    Jul 2013
    Posts
    18
    Quote Originally Posted by SCRIPT_KITTEH View Post
    Code:
    if(scanf("%d", &num1) != 1)
    {
    get rid of bad input
    }
    When scanf tries to read input, it "returns" the number of correctly read items. So scanf("%d", &num1) != 1 means, scanf did not successfully return 1 item. scanf("%d", &num1) = 0 would effectively be the same. So imagine inbetween scanf and your keyboard there is a virtual pathway called a "stream." You send "s" into the stream by typing "s" and then the enter key. Because the integer specifier, %d is in this scanf, it's not going to accept "s." Where will it go? It's just stuck in the stream. getchar() pulls it out. putchar() prints it before the "not an integer" message, in Nominal's example.

    By the way, in case you did not know, EOF means end of file, and in C keyboard input is treated as if it were a file.
    A very clear explanation thank you for taking the time to answer, you must get questions like this a lot and again I apologize for my ignorance I do genuinely feel bad for leeching but I'm keen to learn and hope to be able to make up for it later.

  14. #14
    Registered User SCRIPT_KITTEH's Avatar
    Join Date
    Apr 2013
    Posts
    74
    No problem, I'm pretty new at this too

  15. #15
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    The following snippet will (hopefully) show you all the potential errors you'd need to deal with to ensure that your program will run successfully and give you correct output.

    Code:
    #include <errno.h>     // For errno and ERANGE.
    #include <limits.h>    // For INT_MAX and INT_MIN
    #include <stdio.h>
    #include <stdlib.h>    // For EXIT_FAILURE.
    
    int main(void)
    {
        int a, b, rval;
    
        // scanf's potential return values:
        // EOF: End-of-file or error occurred on stdin.
        // 0: No numbers were successfully matched.
        // 1: Only one number was successfully matched.
        // 2: Two numbers were successfully matched.
        if ((rval = scanf("%d %d", &a, &b)) != 2) {
            fprintf(stderr,
                "error: invalid input (scanf returned %d)\n", rval);
    
            // Indicate to the host environment that the program terminated
            // unsuccessfully. (Useful for shell scripts and such.)
            return EXIT_FAILURE;
        }
    
        // If the value that was converted is larger than INT_MAX or less than
        // INT_MIN, scanf will assign ERANGE to errno. It will also set the
        // value of the int to INT_MAX or INT_MIN depending on the sign of the
        // value.
        if (errno == ERANGE) {
            fprintf(stderr, "error: value is out of int's range\n");
            return EXIT_FAILURE;
        }
    
        // Beyond this point, we can be sure that two values were successfully
        // converted.
    
        // Since we can't make any assumptions about the values that were read,
        // we need to ensure that the addition operation won't cause an
        // overflow.
        if ((a > 0 && b > INT_MAX - a) || (a < 0 && b < INT_MIN - a)) {
            fprintf(stderr, "error: addition will overflow\n");
            return EXIT_FAILURE;
        }
    
        // The resulting value can finally be computed and emitted without any
        // undesirable consequences.
        printf("%d\n", a + b);
    
        // Indicate to the host environment that the program terminated
        // successfully.
        return 0;
    }
    If you were writing this as a serious project, some of the things here wouldn't be needed since you'd use an arbitrary precision library instead of relying on C's standard types, but I hope this will be helpful anyway.
    Last edited by Barney McGrew; 07-27-2013 at 08:05 PM. Reason: Fixed a few mistakes.

Popular pages Recent additions subscribe to a feed