Thread: Making a switch error proof

  1. #16
    Registered User
    Join Date
    Mar 2011
    Posts
    27
    I should've said from the beginning that the program would be a continuous loop, but I didn't think the loop would add such complications. My fault...

    Code:
    int main(int argc, char** argv) {
    
    int exercises;
    char str[50];
    
    while (1) {
        printf( "1. Option 1\n"
                "2. Option 2\n"
                "3. Option 3\n"
                "4. Option 4\n"
                "5. Quit\n"
                "Choose a case: ");
    
        while( scanf( "%d", &exercises ) != 1 ) {
        char buf[ BUFSIZ ] = {0};
        fgets( buf, BUFSIZ, stdin );
    }
                
      switch (exercises) {
        case 1: printf("1\n"); break;
        case 2: printf("2\n"); break;
        case 3: printf("3\n"); break;
        case 4: printf("4\n"); break;
        case 5: exit(EXIT_SUCCESS); break;
        default: printf("Invalid command.\n"); break;
         }
      }
    }
    I'm back to quzah's original suggestion. That bit of code does indeed read a number, and ignores everything else.

    Since I'm using it, I should know exactly what it's doing. Can anyone explain it? Also, can I use sscanf() in this particular code to check if it's anything else other than a number?

  2. #17
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    First the char buf[busiz] should be outside your while loop... otherwise you're recreating it constantly. Also you need to define bufsiz 100 (or so) to hold the data. the part after the = sign initializes the buffers to all 0s.

    What the fgets() does is bleed the input buffer dry so that the next scanf() call sees an empty input queue.

    Also, a minor issue, you don't always need all the braces you use. It's mostly harmless to have them in there but there are some infrequent cases where it might matter, so best learn when to and when not to use them.

    Code:
    #include <stdio.h>
    #define BUFSIZ 100
    
    int main(int argc, char** argv) {
    
       int exercises;
       char str[50] = {0};
       char buf[ BUFSIZ ] = {0};
    
    while (1) {
        printf( "1. Option 1\n"
                "2. Option 2\n"
                "3. Option 3\n"
                "4. Option 4\n"
                "5. Quit\n"
                "Choose a case: ");
    
        while( scanf( "%d", &exercises ) != 1 ) 
           fgets( buf, BUFSIZ, stdin );
    
      switch (exercises) {
        case 1: printf("1\n"); break;
        case 2: printf("2\n"); break;
        case 3: printf("3\n"); break;
        case 4: printf("4\n"); break;
        case 5: exit(EXIT_SUCCESS); break;
        default: printf("Invalid command.\n"); break;
         }
      }
    }
    There are, of course, other solutions you can use here instead of scanf()... getchar() and fgetc() come to mind.

    One of the truisms in programming is that input is always harder than output... you never know what some silly operator is going to type into your code. I've even seen cases where operators have deliberately fed in wrong or corrupt data so they could make a service call on their software... and get the afternoon off.

  3. #18
    Registered User
    Join Date
    Mar 2011
    Posts
    27
    Code:
    while( scanf( "%d", &exercises ) != 1 )
    What is this checking?

  4. #19
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    BUFSIZ is actually a standard library macro, so you should just #include <stdlib.h> instead of redefining it.

    I've even seen cases where operators have deliberately fed in wrong or corrupt data so they could make a service call on their software... and get the afternoon off.
    WOW.

    Hard at work, or hardly working?

    ETA:

    >while( scanf( "%d", &exercises ) != 1 )

    >What is this checking?

    scanf returns how many things it converts successfully, so if it returns anything other than 1, you have a problem. That's why it makes sense.
    Last edited by whiteflags; 06-14-2011 at 06:46 PM.

  5. #20
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by CommonTater View Post
    I've even seen cases where operators have deliberately fed in wrong or corrupt data so they could make a service call on their software... and get the afternoon off.
    I can't say I've seen people doing it for time off. I have, however, seen cases where a bored operator doing a routine job does starts playing with different inputs in order to see what happens.

    I visited a conference stand a few years ago, and a salesman quite proudly told me that the GUI was well engineered and unbreakable, so I could do what I liked. I closed my eyes, placed my hand somewhere on the keyboard, and pushed down (hence depressing several keys at once). The screens went black, and then the software crashed leaving the underlying X-windows on screen. I then exited stage left.

    Apparently it was about three hours before they got an engineer in to get the software going again.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  6. #21
    Registered User
    Join Date
    Mar 2011
    Posts
    27
    So what is it returning if I enter, say, 2?

    What does the 1 represent, and why would I have a problem if it's returning something other than 1, if the while loop is testing for everything other than 1?

  7. #22
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by never_lose View Post
    So what is it returning if I enter, say, 2?

    What does the 1 represent, and why would I have a problem if it's returning something other than 1, if the while loop is testing for everything other than 1?
    If you enter 2, the 2 is stored in the pointer you pass in and the function returns 1, because that's the number of things it stored. Since 1 == 1, you skip the loop and move on with your life.

  8. #23
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by CommonTater View Post
    First the char buf[busiz] should be outside your while loop... otherwise you're recreating it constantly.
    No it doesn't. Even if we assume it does, all that means is that it would nicely clear your buffer every time the loop happened.
    Quote Originally Posted by CommonTater View Post
    Also you need to define bufsiz 100 (or so) to hold the data.
    No, it's a standard macro.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #24
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by grumpy View Post
    I can't say I've seen people doing it for time off. I have, however, seen cases where a bored operator doing a routine job does starts playing with different inputs in order to see what happens.

    I visited a conference stand a few years ago, and a salesman quite proudly told me that the GUI was well engineered and unbreakable, so I could do what I liked. I closed my eyes, placed my hand somewhere on the keyboard, and pushed down (hence depressing several keys at once). The screens went black, and then the software crashed leaving the underlying X-windows on screen. I then exited stage left.

    Apparently it was about three hours before they got an engineer in to get the software going again.
    No joke... I have a paint roller (clean and dry of course) that I run across the keyboard when writing console programs... just to test this very thing!

  10. #25
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by quzah View Post
    No it doesn't. Even if we assume it does, all that means is that it would nicely clear your buffer every time the loop happened.No, it's a standard macro.
    Quzah.
    As I have just now discovered ... Hey, I don't have the headers memorized, you know!

  11. #26
    Registered User
    Join Date
    Mar 2011
    Posts
    27
    Hmm, I've got a pretty good solution now, but not completely error proof.

    Look what happens if I enter "1 3".

    Choose a case: 1 3
    1
    1. Option 1
    2. Option 2
    3. Option 3
    4. Option 4
    5. Quit
    Choose a case: 3
    1. Option 1
    2. Option 2
    3. Option 3
    4. Option 4
    5. Quit
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    //#define BUFSIZ 100
    
    int main(int argc, char** argv) {
    
       int exercises;
       char str[50] = {0};
       char buf[BUFSIZ] = {0};
    
    while (1) {
        beg:
        printf( "1. Option 1\n"
                "2. Option 2\n"
                "3. Option 3\n"
                "4. Option 4\n"
                "5. Quit\n"
                "Choose a case: ");
    
        while ( scanf( "%d", &exercises ) != 1 ) {
           fgets( buf, BUFSIZ, stdin );
        printf("Enter a number!\n");
        goto beg;
    }
    
      switch (exercises) {
        case 1: printf("1\n"); break;
        case 2: printf("2\n"); break;
        case 3: printf("3\n"); break;
        case 4: printf("4\n"); break;
        case 5: exit(EXIT_SUCCESS); break;
        default: printf("Invalid command.\n"); break;
         }
    
      }
    }
    I commented off #define BUFSIZ since I don't need it, right?

    For understanding purposes, if I entered a letter, would it return 0, since "scanf( "%d", &exercises )" can't store that letter as a number?

  12. #27
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by never_lose View Post
    Hmm, I've got a pretty good solution now, but not completely error proof.

    Look what happens if I enter "1 3".
    If that's bothersome to you, you can run through the bleed-the-buffer-dry after every input, not just unsuccessful input.

    Quote Originally Posted by never_lose View Post
    For understanding purposes, if I entered a letter, would it return 0, since "scanf( "%d", &exercises )" can't store that letter as a number?
    scanf always returns the number of inputs it was able to process (or EOF if there was error in even trying to read anything at all). In this case, since it processed zero inputs, and your keyboard actually exists, it will return 0.

  13. #28
    Registered User
    Join Date
    Mar 2011
    Posts
    27
    Putting a "fgets( buf, BUFSIZ, stdin );" in every case solved that, but that's a lot of duplicate code. I'm thinking there is a better way to do it?

  14. #29
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Now that you have a pile of code that does one particular thing ("read in a number"), that would be an excellent thing to turn into a function.

  15. #30
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    int s, n;
    do
    {
        n = 0;
        s = scanf( "%d", &exercise );
        scanf( "%*[^\n]%n%*c", &n );
    } while( !s || n );

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. switch case error. Can anyone help?
    By brack in forum C Programming
    Replies: 4
    Last Post: 02-28-2011, 03:30 PM
  2. Error proofing my switch statement.
    By Shamino in forum C++ Programming
    Replies: 10
    Last Post: 01-04-2008, 04:38 PM
  3. Switch error
    By liats80 in forum C Programming
    Replies: 6
    Last Post: 11-26-2007, 05:53 AM
  4. Switch stat error
    By Emperor128 in forum C++ Programming
    Replies: 3
    Last Post: 04-05-2006, 05:07 PM
  5. switch or if else....how to check for error
    By clear in forum C Programming
    Replies: 1
    Last Post: 04-30-2003, 01:24 PM