Valentin Bichok
Valentin Bichok

Reputation: 61

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).

Upvotes: -2

Views: 192

Answers (3)

anastaciu
anastaciu

Reputation: 23792

The problem, as mentioned in the comments, is that goto is always executed because it does not depend on the condition, it's out of its scope.

In C the only statement dependant on the condition is the one in the next line, to have more than one you'll need to increase the codition scope using {} to envelop the statements that should depend on it, i.e.:

if(...){ 
   statement; 
   statement;
}

if you have other solution that restarts the main program after an execution please tell me

There are many possiblities to achieve the same result. I would choose a simple and elegant solution using a do-while loop:

int main()
{
    int x = 0; //initialize the control variable to avoid problems in case of bad input

    do {
        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");
    } while (scanf("%d", &x) && x > 6 && printf("Wrong option!\n"));
    //including scanf in the condition has the advantage of also checking its return value

    if (x == 1)
        printf("Drawing");
    if (x == 0)
        printf("we are out!\n");

    return 0;
}

Upvotes: 2

klutt
klutt

Reputation: 31296

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 {}

Upvotes: 6

Vlad from Moscow
Vlad from Moscow

Reputation: 310940

This formatting of the statements

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

does not mean that the statement with goto is a sub-statement of the if statement. Actually you have

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

Thus the goto statement gets the control in any case.

It is a bad idea to use the goto statement. It would be much better to use for example the do-while statement along with a switch statement the following way

#include <stdio.h>

int main()
{
    int x = 0;

    do
    {
        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"); 
        scanf("%d", &x);

        switch( x )
        { 
        case 0:
           printf("we are out!\n");
           break;
        case 1: 
           printf("Drawing");
           break;
        default:
            printf("Wrong option!\n");
            break;
        }
    } while ( x != 0 );

    return 0;
}

Also you could introduce an enumeration the enumerator constants of which will be used in the case labels.

For example

#include <stdio.h>

int main()
{
    enum { Exit = 0, Draw = 1, EvenOrOdd = 2, Text = 3, /* other constants */ };  
    int x = 0;

    do
    {
        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"); 
        scanf("%d", &x);

        switch( x )
        { 
        case Exit:
           printf("we are out!\n");
           break;
        case Draw: 
           printf("Drawing");
           break;
        default:
            printf("Wrong option!\n");
            break;
        }
    } while ( x != Exit );

    return 0;
}

Upvotes: 1

Related Questions