cloopsif-statementgotolabeled-statements

How to use goto without getting this error?


#include <stdio.h>

int main()
{
    repeat:
    printf("choose an option: \n1:Draw\n2:Even or Odd:\n3:Text type\n4:How to Dec\n5:Base to Dec:\n6:Count to Bits\n0:Exit\n"); 
    int x;
    scanf("%d", &x); 
    if (x > 6)
       printf("Wrong option!\n");
       goto repeat;
    if (x == 1) 
       printf("Drawing");
    if (x == 0)
       printf("we are out!\n");
    return 0;
}

I am using an online complier.

The end result I want to see is a simple menu that asks the user for input number and executes a code according to the number and then goes to the starting point and prints the menu again. (That's why I chose goto. If you have other solution that restarts the main program after an execution please tell me.)

The problem I encountered is that no matter the number I input, it outputs the menu again without the messages or without exiting (when I input 0).


Solution

  • C is not indentation dependent. Just change

    if (x > 6)
           printf("Wrong option!\n");
           goto repeat;
    

    to

    if (x > 6) {
           printf("Wrong option!\n");
           goto repeat;
    }
    

    You can only omit the braces for single statements.

    But I would strongly advice against using goto like this. goto has it's uses, but this is not one of them. You could rewrite your code like this:

    int main()
    {
        while(1) {
            printf("choose an option: \n1:Draw\n2:Even or Odd:\n3:Text type\n4:How to Dec\n5:Base to Dec:\n6:Count to Bits\n0:Exit\n"); 
            int x;
            scanf("%d", &x); 
            if (x > 6) {
               printf("Wrong option!\n");
            }
    
            if (x == 1) {
               printf("Drawing");
               break;
            }
            if (x == 0) {
               printf("we are out!\n");
               break;
            }
        }
    }
    

    It's not how I would have written it. I changed to a while loop with as few changes as possible. I would have done something like this:

    int x = 6;
    while(x == 6) {
        printf("choose an option: \n1:Draw\n2:Even or Odd:\n3:Text type\n4:How to Dec\n5:Base to Dec:\n6:Count to Bits\n0:Exit\n"); 
    
        // Always check scanf for errors
        if(scanf("%d", &x) != 1) { perror("Input error"); exit(1); }
    
        switch(x) {
            case 1: printf("Drawing"); break;
            case 0: printf("we are out!\n"); break;
            default: printf("Wrong option!\n");
        }
    }
    

    There are only two cases where I would ever consider using goto:

    1. To break out of a nested loop

    2. To clean up allocated resources in a function on failure

    Example of breaking out of nested loop:

    while(1) {
        while(1) {
            if(<condition>) goto END;
        }
    }
    END:
    

    Example of cleanup:

    void foo() {
        char *p = malloc(1);
        if(!p) goto END;
        char *q = malloc(1);
        if(!q) goto P;
    
        // Do stuff
    
        free(q);
    P:
        free(p);
    END:
    }
    

    Note that the cleanup example is not very good, since you can safely free a NULL pointer, which malloc returns on failure. An example with fopen would be more appropriate. But it demonstrates the general principle. That you do the cleanup in reverse order and jump to the appropriate place in case of failure.

    And whatever you do, NEVER jump backwards with goto. Only jump forwards. Or at least I have never seen a case where a backwards jump would be motivated.

    In languages that support exceptions, you would typically use exceptions for both of these cases. First example would be something like this pseudo:

    try {
        while(1) {
            while(1) {
                if(<condition>) throw MyException;
            }
        }
    } catch MyException {}