break a loop then not run next code if loop breaks

Viewed 162
#include <stdio.h>

int main() {
    while (height > 0) {
        if (throttle >= 0 && throttle <= 100) {
            printf("%d    %.1f  %.1f   %.1f  ", time, height, velocity, fuel);
            scanf("%d", &throttle);
            height = heightTemp + velocityTemp - (throttle * K-G) / 2;
            velocity = velocityTemp + (throttle * K-G);
            fuel = fuelTemp - throttle;
            time = time + 1;
            heightTemp = height;
            velocityTemp = velocity;
            fuelTemp = fuel;   
        }
        else {
            printf("Please choose a number between 0 and 100! \n");
            break;
        }
    }
   
    if (velocity >= -2.0) {
        printf("You landed successfully: ");
    } 
    else {
        printf("Failed! You crashed");
    }

    return 0;
}

I want to only run the if velocity part if the loop does not break, if I keep the code this way it'll run that code no matter what since the break obviously only quits the loop. My full code is not written.

5 Answers

There are basically two solutions to this:

  1. use a idBreak variable that you set to 1 upon breaking, like in the mikyll98's answer
  2. use a goto pastTheIfElse; instead of break;.

If the pastTheIfElse label marks a return (like it does in your code), then you can directly return instead of the goto.

#include <stdio.h>

int main() {
    while (height > 0) {
        if (throttle >= 0 && throttle <= 100) {
            printf("%d    %.1f  %.1f   %.1f  ", time, height, velocity, fuel);
            scanf("%d", &throttle);
            height = heightTemp + velocityTemp - (throttle * K-G) / 2;
            velocity = velocityTemp + (throttle * K-G);
            fuel = fuelTemp - throttle;
            time = time + 1;
            heightTemp = height;
            velocityTemp = velocity;
            fuelTemp = fuel;   
        }
        else {
            printf("Please choose a number between 0 and 100! \n");
            goto pastTheIfElse; //instead of break;
            //OR in this case: `return 0;`
        }
    }

    if (velocity >= -2.0) {
        printf("You landed successfully: ");
    } else {
        printf("Failed! You crashed");
    }
    pastTheIfElse:

    return 0;
}

The goto solution is what an optimizing compiler should optimize the didBreak version into, so some prefer it, while others are really really strongly against it because "goto considered harmful".

Replace the break; with return 0; or if you consider invalid input an error of value to the host environment return -1; (or other non-zero value - it is implementation defined).

If you want to be ultra-formal #include <stdlib.h> and return EXIT_SUCCESS or return EXIT_FAILURE as you see applicable. Though use of those provided macro constants are rarely seen in either examples of real code.

Some C Standards hold functions should have only one exit point but obeying that sometimes leads to code that is just as contorted and unreadable as an early return where relevant.

Just assign a certain value to a variable if the loop breaks, and add an if condition that checks that value.

#include <stdio.h>

int main() {
    int didBreak = 0;

    while (height > 0)
    {
        if (throttle >= 0 && throttle <= 100)
        {
            printf("%d    %.1f  %.1f   %.1f  ", time, height, velocity, fuel);
            scanf("%d", &throttle);
            height = heightTemp + velocityTemp - (throttle * K - G) / 2;
            velocity = velocityTemp + (throttle * K - G);
            fuel = fuelTemp - throttle;
            time = time + 1;
            heightTemp = height;
            velocityTemp = velocity;
            fuelTemp = fuel;

        }
        else
        {
            printf("Please choose a number between 0 and 100! \n");
            didBreak = 1;
            break;
        }
    }

    if (didBreak == 0)
    {
        if (velocity >= -2.0)
        {
            printf("You landed successfully: ");
        }
        else
        {
            printf("Failed! You crashed");
        }
    }

    return 0;
}

In my opinion, the best solution to your stated problem would be to replace break with return 1;, so that it exits the function. If you #include <stdlib.h>, then you can also use return EXIT_FAILURE; instead, which is easier to read.

However, in cases in which you do not want to exit the function (for example because you want the rest of the function to be executed), then I would recommend that you restructure your loop to an infinite loop with explicit break statements for all possible cases in which the loop should end. That way, you can move the if...else inside the loop:

for (;;) //infinite loop, equivalent to while(true)
{
    if ( height <= 0 )
    {
        if ( velocity >= -2.0 )
        {
            printf( "You landed successfully.\n" );
        }
        else
        {
            printf( "Failed! You crashed!\n" );
        }

        break;
    }

    if ( throttle >= 0 && throttle <= 100 )
    {
        [...]
    }
    else
    {
        printf( "Please choose a number between 0 and 100!\n" );
        break;
    }
}

However, I do not think that your stated problem is your actual problem. When the user enters invalid input, you probably do not want to exit the function (or even the entire program). Instead, it would make more sense to reprompt the user for valid input, when the input is invalid. In order to determine whether the input is invalid or not, you should not only check whether throttle is in the desired range, but also whether the user entered an integer in the first place (i.e. make sure that the user didn't enter something that could not be converted to an integer).

For the reasons stated in this answer of mine to another question, I do not recommend that you use scanf for line-based user input. For determining whether the user entered a valid integer, it is usually better to use the function fgets to read exactly one line of user input as a string, and then to attempt to convert the string to an integer using the function strtol. These two function calls can be combined into a single function, which automatically reprompts the user if he did not enter a valid integer. In my linked answer, I created such a function called get_int_from_user.

After making the changes mentioned above, your code would look like this:

for (;;) //infinite loop, equivalent to while(true)
{
    printf( "T: %d   H: %.1f   V: %.1f   F: %.1f\n", time, height, velocity, fuel );

    if ( height <= 0 )
    {
        if ( velocity >= -2.0 )
        {
            printf( "You landed successfully.\n" );
        }
        else
        {
            printf( "Failed! You crashed!\n" );
        }

        break;
    }

    //repeat until user entered a valid integer in the
    //range 0 - 100
    for (;;)
    {
        throttle = get_int_from_user( "Enter throttle (0-100): " );
        if ( throttle < 0 || throttle > 100 )
        {
            printf( "Please choose a number between 0 and 100!\n" );
            continue;
        }

        //input is ok
        break;
    }

    //do physics calculations (copied from the question)
    height = heightTemp + velocityTemp - (throttle * K-G) / 2;
    velocity = velocityTemp + (throttle * K-G);
    fuel = fuelTemp - throttle;
    time = time + 1;
    heightTemp = height;
    velocityTemp = velocity;
    fuelTemp = fuel;  
}

Here is the full code of a test program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>

int get_int_from_user( const char *prompt );

int main( void )
{
    int time = 0, throttle;
    double height = 100.0, velocity = -5.0;

    for (;;) //infinite loop, equivalent to while(true)
    {
        printf( "T: %d   H: %.1f   V: %.1f\n", time, height, velocity );

        if ( height <= 0 )
        {
            if ( velocity >= -2.0 )
            {
                printf( "You landed successfully.\n" );
            }
            else
            {
                printf( "Failed! You crashed!\n" );
            }

            break;
        }

        //repeat until user entered a valid integer in the
        //range 0 - 100
        for (;;)
        {
            throttle = get_int_from_user( "Enter throttle (0-100): " );
            if ( throttle < 0 || throttle > 100 )
            {
                printf( "Please choose a number between 0 and 100!\n" );
                continue;
            }

            //input is ok
            break;
        }

        //do physics calculations
        velocity += throttle / 100.0;
        velocity -= 0.5; //gravity
        height += velocity;
        time++;
    }
}

int get_int_from_user( const char *prompt )
{
    //loop forever until user enters a valid number
    for (;;)
    {
        char buffer[1024], *p;
        long l;

        //prompt user for input
        fputs( prompt, stdout );

        //get one line of input from input stream
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            fprintf( stderr, "Unrecoverable input error!\n" );
            exit( EXIT_FAILURE );
        }

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small)
        if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
        {
            int c;

            printf( "Line input was too long!\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    fprintf( stderr, "Unrecoverable error reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //attempt to convert string to number
        errno = 0;
        l = strtol( buffer, &p, 10 );
        if ( p == buffer )
        {
            printf( "Error converting string to number!\n" );
            continue;
        }

        //make sure that number is representable as an "int"
        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "Number out of range error!\n" );
            continue;
        }

        //make sure that remainder of line contains only whitespace,
        //so that input such as "6sdfj23jlj" gets rejected
        for ( ; *p != '\0'; p++ )
        {
            if ( !isspace( (unsigned char)*p ) )
            {
                printf( "Unexpected input encountered!\n" );

                //cannot use `continue` here, because that would go to
                //the next iteration of the innermost loop, but we
                //want to go to the next iteration of the outer loop
                goto continue_outer_loop;
            }
        }

        return l;

    continue_outer_loop:
        continue;
    }
}

Since the physics calculations that you posted do not compile, I have added my own (simple) physics calculations.

This program has the following output:

T: 0   H: 100.0   V: -5.0
Enter throttle (0-100): hh7
Error converting string to number!
Enter throttle (0-100): test
Error converting string to number!
Enter throttle (0-100): 6abc
Unexpected input encountered!
Enter throttle (0-100): 200
Please choose a number between 0 and 100!
Enter throttle (0-100): -30
Please choose a number between 0 and 100!
Enter throttle (0-100): 5 
T: 1   H: 94.5   V: -5.5
Enter throttle (0-100): 10
T: 2   H: 88.7   V: -5.9
Enter throttle (0-100): 15
T: 3   H: 82.5   V: -6.2
Enter throttle (0-100): 20
T: 4   H: 76.0   V: -6.5
Enter throttle (0-100): 25
T: 5   H: 69.2   V: -6.8
Enter throttle (0-100): 35
T: 6   H: 62.4   V: -6.9
Enter throttle (0-100): 45
T: 7   H: 55.4   V: -7.0
Enter throttle (0-100): 55
T: 8   H: 48.5   V: -6.9
Enter throttle (0-100): 65
T: 9   H: 41.8   V: -6.8
Enter throttle (0-100): 80
T: 10   H: 35.3   V: -6.5
Enter throttle (0-100): 100
T: 11   H: 29.3   V: -6.0
Enter throttle (0-100): 100
T: 12   H: 23.9   V: -5.5
Enter throttle (0-100): 100
T: 13   H: 18.9   V: -5.0
Enter throttle (0-100): 100
T: 14   H: 14.5   V: -4.5
Enter throttle (0-100): 100
T: 15   H: 10.6   V: -4.0
Enter throttle (0-100): 100
T: 16   H: 7.1   V: -3.5
Enter throttle (0-100): 100
T: 17   H: 4.2   V: -3.0
Enter throttle (0-100): 100
T: 18   H: 1.7   V: -2.5
Enter throttle (0-100): 100
T: 19   H: -0.2   V: -2.0
You landed successfully.

It doesn't make sense to prompt for re-entry of data, then exit the processing and go off somewhere else...

Revamp your while loop and test user input when it is input.

Perhaps a "sentinel value" (eg: 999) could be available to abort the loop...

while( height > 0 ) {
    printf("%d    %.1f  %.1f   %.1f  ", time, height, velocity, fuel);
    scanf("%d", &throttle);
    if( throttle < 0 || throttle > 100 ) {
        if( throttle == 999 ) return -1; // Maybe???
        printf("Please choose a number between 0 and 100! (999 to abort) \n");
        continue;
    }

    /* Calculations omitted */
}
Related