Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

C Programming - why does scanf do this?

  • 22-10-2010 11:19am
    #1
    Registered Users, Registered Users 2 Posts: 3,745 ✭✭✭


    I'm writing a program, in C, that accepts user input twice. My code looks like this:
    #include <stdio.h>
    
    int main()
    {
        double a=0,b=0,c=0,A=0,B=0;
    
        printf("Enter a comma-seperated list of co-efficients a,b,c: ");
        scanf("%lf,%lf,%lf",&a,&b,&c);
        printf("a=%lf, b=%lf, c=%lf\n",a,b,c);
    
        printf("Enter the interval in the form [A,B]: ");
        scanf("[%lf,%lf]",&A,&B);
        printf("Interval: [%lf,%lf]\n",A,B);
    }
    

    When I compile and run it, it prompts me for a,b and c, so I type, say, "1.2,3,5.42" and hit enter. But then when it comes to the next scanf it just skips right along, never letting me input data, but just taking A and B to be both 0.0. So a sample output:
    Enter a comma-seperated list of co-efficients a,b,c: [U]2,3,4[/U]
    a=2.000000, b=3.000000, c=4.000000
    Enter the interval in the form [A,B]: Interval: [0.000000,0.000000]
    

    (underline indicates user input)


    Why is this?

    Following advise on the net, I'm going to read a line at a time into a string, and then use sscanf, but I'm still curious as to this behaviour.

    And I'm sorry if this is a totally stupid question!

    I'm doing this on a GNU/Linux box, for what it's worth.


Comments

  • Registered Users, Registered Users 2 Posts: 363 ✭✭Rockn


    AFAIK when you call scanf the first time it will read the first 3 doubles but any input after that will remain in the input buffer including the newline character. So the second time you call scanf it's reading that and not finding what you want.


  • Registered Users, Registered Users 2 Posts: 2,082 ✭✭✭Tobias Greeshman


    [snip]
    Why is this?

    Following advise on the net, I'm going to read a line at a time into a string, and then use sscanf, but I'm still curious as to this behaviour.

    I don't have a solution for you on this, but I can tell you the problem. The issue is those square brackets in scanf. If you take them out, then you your program should work fine prompting you for input.

    The square brackets are a special case in scanf format strings, where they're used for character classes (referred to scan-sets), however under some cases they cause the format specifiers to be ignored, which is what I think is happening in your case. I can't seem to find anyway of escaping them.

    Have a look here about the square bracket: here.

    Using sscanf is going to still cause issues for you because it will use the same format specifiers/flags than scanf uses.


  • Registered Users, Registered Users 2 Posts: 2,426 ✭✭✭ressem


    You can flush after use...
    #include <stdio.h>
    
    int main()
    {
    
        double a=0,b=0,c=0,A=0,B=0;
    
        printf("Enter a comma-seperated list of co-efficients a,b,c: ");
        scanf("%lf,%lf,%lf",&a,&b,&c);
        flushall();
        printf("a=%lf, b=%lf, c=%lf\n",a,b,c);
    
        printf("Enter the interval in the form [A,B]: ");
        scanf("[%lf,%lf]",&A,&B);
        flushall();
        printf("Interval: [%lf,%lf]\n",A,B);
    
        return 0;
    }
    

    To save everyone else the effort.
    health warning. flushall is not part of the stdio.h spec. May cause issues with your code on some compilers.

    --edit--

    An alternative is replacing flushall() with
    scanf("%*c");

    which will clear out the newline left by the scanf, but not if any whitespace was inserted beforehand.


  • Registered Users, Registered Users 2 Posts: 7,893 ✭✭✭The_B_Man


    or fflush(stdin);


  • Closed Accounts Posts: 4,564 ✭✭✭Naikon


    The_B_Man wrote: »
    or fflush(stdin);

    Don't want to be a moaning micheal, but DO NOT use fflush(stdin) as fflush() is designed to be used with output streams only. Since you are using stdin, undefined results will come to light when you least expect it. You do something similar as per the following link, but even then, It's probably not 100% for buffered I/O: http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1044873249&id=1043284392


  • Advertisement
  • Closed Accounts Posts: 4,564 ✭✭✭Naikon


    I'm writing a program, in C, that accepts user input twice. My code looks like this:
    #include <stdio.h>
    
    int main()
    {
        double a=0,b=0,c=0,A=0,B=0;
    
        printf("Enter a comma-seperated list of co-efficients a,b,c: ");
        scanf("%lf,%lf,%lf",&a,&b,&c);
        printf("a=%lf, b=%lf, c=%lf\n",a,b,c);
    
        printf("Enter the interval in the form [A,B]: ");
        scanf("[%lf,%lf]",&A,&B);
        printf("Interval: [%lf,%lf]\n",A,B);
    }
    

    When I compile and run it, it prompts me for a,b and c, so I type, say, "1.2,3,5.42" and hit enter. But then when it comes to the next scanf it just skips right along, never letting me input data, but just taking A and B to be both 0.0. So a sample output:
    Enter a comma-seperated list of co-efficients a,b,c: [U]2,3,4[/U]
    a=2.000000, b=3.000000, c=4.000000
    Enter the interval in the form [A,B]: Interval: [0.000000,0.000000]
    

    (underline indicates user input)


    Why is this?

    Following advise on the net, I'm going to read a line at a time into a string, and then use sscanf, but I'm still curious as to this behaviour.

    And I'm sorry if this is a totally stupid question!

    I'm doing this on a GNU/Linux box, for what it's worth.

    Yep, you are correct. Best method is to never use scanf inputted user values directly. Basically, you want to assume any user input is hostile(could contain shellcode and other nastiles among other crap input, and if the input does not match the format specified by scanf, good luck). It's way better to store the input line which is recorded as a string and simply use sscanf to record the parsed values into another mem location.

    You should probably also assign the return value of those library calls to an another int to represent the error states. Now because the user is only entering data into a string, it's safer than assuming the user will input an int(which he won't). scanf assumes the user is perfect with input. What happens if a char is entered when an int is expected? You could solve this by more err handling(cast bad values, but will require more code), but fgets/sscanf with error handling is probably better. This ain't a stupid question by the way plenty of 'experienced' programmers probably overlook this stuff at the best of times. C/C++ land you are in now.

    Something like this should be expected:
    fgets(buf, sizeof(buf), stdin)   /*Overkill for a single value mind you*/
    sscanf(buf, "%d", &int_var);
    

    BTW, the Open Group online specs for library/syscalls are probably your best friend on a POSIX box. Microsoft.com if you are windows :D


  • Registered Users, Registered Users 2 Posts: 3,745 ✭✭✭Eliot Rosewater


    Thanks for the comments folks! In the end I stuck with scanf, and took its return value (number of variables written) to ensure that the proper stuff was being given in. I then flushed the buffer using a custom function:
    int flushb()
    {
        while(getchar()!='\n'); 
        return 0;
    }
    

    This has the side effect of requesting user input if the buffer is empty, but I ended up using that fact to easily put some "Press enter to continue..." pauses in the output.

    The next time I'll go down the sscanf() route, if only for the learning process!
    ressem wrote: »
    health warning. flushall is not part of the stdio.h spec. May cause issues with your code on some compilers.

    I'm writing and testing the code on Linux, but then finally compiling it and submitting it on Windows XP, so portability is important!
    Naikon wrote: »
    BTW, the Open Group online specs for library/syscalls are probably your best friend on a POSIX box.

    I/O redirection in the shell is extremely handy for these kind of programs!! The final program asks for 7 values though 5 different prompts which, frankly, is an absolute pain in the ass when debugging stuff near the end. So I just created a file with all the necessary input and directed it in; easy peasy lemon squeezy! :D

    (I could have just commented out the intermediate code, of course..!)


Advertisement