A Loop By Any Other Name

The questions below are due on Sunday September 20, 2026; 11:59:00 PM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
Back to Exercises

Big Idea

C, being a language that is "closer to the metal", means it has some constructs and features that may not appear in some higher level languages like Python. Pointers are one of those for sure, but there are others, including some control flow statements including the goto statement which really has no native Python equivalent.

A goto statement is basically a command to "jump" to another spot in the code base unconditionally. You specify these spots using labels that are distinctive names you give your code regions followed by a colon like code_spot_1:. Then if you say goto code_spot_1; in your code, no matter where you are, your code will "go to" that line and continue executing. (one caveat to keep in mind is that gotos do not work between function scopes...so you can't jump between functions using this.). It really is as simple as that.

A simple example of a goto functionality is shown below:

    // x starts at some value specified earlier
    if (x>11){
        printf("x is greater than 11!\n");
        goto finish_up;
    }
    printf("x is not greater than 11!\n");
    finish_up:
        //indent here purely for style/readability (not needed)
        printf("Thanks for evaluating x!\n");

If this code were to be run with a value of like x=13, the following transcript would come out:

x is greater than 11!
Thanks for evaluating x!

What happened during the run is the if statement evaluated in the affirmative as we expect, the inner print happened as we expect, and then the code jumped to right after the finish_up label and continued from there. In doing this, the line about x not being greater than 11 was bypassed/skipped over, which would not have happened if that goto statement had not been encountered.

If the above code were run with a value like x=8, the following transcript would come out:

x is not greater than 11!
Thanks for evaluating x!

What happened during that run is the if statement evaluates in the negative, so the code inside that portion doesn't execute. Instead, it hits the print about not being greater than 11, and then moves right into the next line which is labeled as finish_up and continues on.

So big take-away from this is that you can get to code labels either by using a goto command or just naturally encountering them and rolling right into them as the code executes one line after the other. The labels are effectively "invisible" when you encounter them naturally as the next line.

So What?

You may say that the previous example could have just used an else statement mated with the if, and that's absolutely correct. The reason we're bringing up goto statements in this class is that they are much closer in operation to how computers will actually run "under the hood" so it can be helpful for learning. In a few weeks, we'll begin learning about assembly, which is the actual set of operations that all computer programs are expressed in (compilers turn higher level code into these simpler, lower level options we call assembly language), but as a mini-preview, when we get there, we'll quickly see that there is no "if/else" instruction. There's really only a mixture of "branch" and "jump" instructions which basically are operations that move your the "cursor" of your operating code to different points in the program denoted by labels. Jump instructions are effectively just the goto statement. There will be assembly (pseudo)instructions like j spot_0 which is the same as a C goto spot_0; line. Branch instructions are a form of conditional jumping where you either jump or continue onto the next line.

if (x>5){
    goto spot1;
}
spot1:
    //code here gets executed if x>5!
//continue on

Loops?

Just like there's not if/else in assembly, it turns out there's no loop constructs (for, while, etc...) either. Those also end up getting made out of simpler pieces, including conditional checks (if) and jumps. This means it is possible to write loop constructs using just if and goto statements in C. There's nothing that says the label you're "going to" needs to be later on in the code; you can always jump backwards if needed.

To get a little practice with this, without using for, while or do while else statements, write a function dot_product that takes in two C integer arrays as well as an argument specifying their length (you can assume the two arrays are equal in length) and returns the dot product of the two arrays which is defined for two arrays \mathbf{a} and \mathbf{b} as \mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i.

Also as a bit of guidance, the checker below is looking for any instance of the words for, while, do while, or else so even if you shove them in your comments or program labels, it'll get flagged, so avoid using those things anywhere. Normally it is perfectly fine to have a label like for_start, but I ran out of time to write a good parser so just make it fr_start or whatever you need. Sorry.

Actual Use for goto?

You may be asking, "if higher level constructs like if/else and for and while loops exist in C, why even keep the goto statement around in C?" This is a reasonable question. In fact, usage of goto is often discouraged since it can lead to lots of spaghetti code that is hard to follow, so you don't see it too much. The one spot you'll maybe sometimes still see it is when you're deep inside some nested logic check and you just need to get to the end of all of it, a goto can be a clean way to achieve that. A slightly related pattern that is very common is when doing something like processing data and you encounter an error mode and you just want to get to the bottom and exit out. This is is shown below

int check_scores(int *scores, int count, int *average_out){
    int sum = 0;
    int valid_count = 0;
    int result = -1; //return this as indicator of 'success or failure'

    // Check for NULL pointer (does
    if (!scores || !average_out){
        goto error;
    }

    // Check for valid count
    if (count <= 0 || count > 1000){
        goto error;
    }

    // processs each score
    for (int i = 0; i < count; i++){
        // Check for impossible scores (must be within 0-100)
        if (scores[i] < 0 || scores[i] > 100){
            goto error;
        }
        // Check for overflow (INT_MAX is specified by the system as max int val)
        //in case of 32 bit system it would be 2**31 - 1
        //we'll go over that number in week 2's lecture!!! :)
        if (sum > INT_MAX - scores[i]){
            goto error;
        }
        sum += scores[i];
        valid_count++;
    }

    // Success!!! - calculate average
    *average_out = sum / valid_count;
    result = 0; //0 means good!!!
error:
    // Maybe print or log error details here!
    // Nicer to do in one location at the end than...
    // repeating in multiple locations
    return result;
}

Anyways, be aware. As you are writing code and using loops, think about how that loop could be done with just goto/jumps and conditional checks!!

Back to Exercises