Reputation: 61
#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
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
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
:
To break out of a nested loop
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
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