Programmers rarely use the goto operator in modern programming, so you may skip this section if your instructor didn't explicitly assign it. Previously, the unrestrained use of goto statements caused many incomprehensible and unmaintainable programs. However, there remain at least two legitimate uses in contemporary programs: interrupting nested loops and implementing state machines.
Labels And The goto Operator
A goto statement consists of the goto keyword, followed by a programmer-created identifier, and terminated with a semicolon. A label is any unique, legal identifier followed by a colon. Programmers may label any statement in a program and "jump" to it with a goto statement. Early versions of FORTRAN and the Basic programming language had few control statements (such as the ones introduced in this chapter). So, complex program control was implemented with labels and a tangled web of goto statements, resulting in what is now derisively called "spaghetti code" because the chaotic logic reminds programmers of a bowl of spaghetti.
some_statements;
goto label;
...
for (int i = 0; i < 100; i++)
{
...
label: statement;
...
}
(a)
(b)
(c)
Basic goto statements. It's easy to understand a basic goto statement: when executed, it causes program control to jump to a different location in the program. Problems arise when a program has many goto statements whose targets (the labeled statements) are scattered indiscriminately throughout a program. We began the chapter by describing a flow of control as an inked path through a program. Programs with many goto statements produce many broken, disjoint paths. These paths resemble a tangled bowl of spaghetti, where it isn't easy to see the ends or how the strands relate.
goto statements can shift program control forward and backward.
Jumping out of loops, forward or backward, is allowed.
It is illegal to jump into a loop.
Understanding and maintaining spaghetti code is often challenging because goto statements can transfer control to arbitrary places inside statement sequences, making it difficult to know the conditions when individual statements in the sequence run and when they don't.
Exiting Nested Loops
Interrupting a loop early (i.e., before the loop-control condition ends the loop "normally") allows programmers to write efficient code (see case analysis). break and continue are sufficient to interrupt a single, unnested loop. For example:
for (int i = 0; i < counter; i++)
{
. . .
if (condition)
break;
. . .
}
for (int i = 0; i < counter; i++)
{
. . .
if (condition)
continue;
. . .
}
(a)
(b)
Interrupting loops with break and continue.
break and continue statements are typically placed inside an if-statement, but a switch will also work. Whenever a break or continue executes (i.e., whenever the condition is true), all of the statements between the break or continue are skipped.
When the break statement operates, execution resumes with the first statement following the end of the loop.
When the continue statement operates, execution resumes at the top of the loop. If the loop is a for-loop, the program executes the increment expression, then (for all loops) it reevaluates the test expression, and if it is true, the next iteration of the loop runs.
However, the break and continue statements only work for a single, unnested loop. If two or more loops are nested, break and continue only apply to the loop in which they are called (i.e., if called from a nested loop, they cannot affect an outer loop). Programmers typically use a goto statement when they need to break or continue out of nested or inner loops. The goto label merely provides a target for the goto operation: when the goto executes, the program transfers control to the statement following the label.
for (int i = 0; i < counter; i++)
{
for (int j = 0; j < c2; j++)
{
. . .
if (condition)
goto done;
. . .
}
}
done:
int i = 0;
next:
for (; i < counter; i++)
{
for (int j = 0; j < c2; j++)
{
. . .
if (condition)
goto next;
. . .
}
}
(a)
(b)
Interrupting nested loops with goto.
Programmers can interrupt nested loops with a goto and label. They can effect either a break or continue by choosing where to place the label.
With the label placed below the outer loop, the goto performs as a multi-level break
With the label placed above the outer loop, the goto performs as a multi-level continue (note that the loop control variable must be defined and initialized above the loop; otherwise the goto would reinitialize the outer loop
Implementing State Machines
State machines are abstractions practitioners in many disciplines use to describe a system's dynamic behavior. They are most beneficial when an entity's response to an event depends on its response to previous events. Numerous state machine notations are in use, but all consist of finite sets of states and transitions. A state represents an entity's current condition or activity. A transition is a legal way the machine can change from one state to another. While the basic state machine notation is consistent across domains, variations exist. The following figure describes UML state diagrams.
Example State Machine Problem
Write a program that reads a C++ program file and separates the comments from the program code. The program should write the comments to one file and the program code to another file.