Control Flow: For loops, If statements, and goto

Dr. Lawlor, CS 202, CS, UAF

C++ has a very rich set of "control flow" statements: for loops, while loops, do loops, ifs, and even the ancient and shunned goto statement.

For Loop (Gaddis chapter 5.6)

For loops have three parts: the initializer, the test, and the counting expression.  They're each separated by semicolons:
for (int i=0;i<5;i++) {
cout<<i<<"\n";
}

(Try this in NetRun now!)

Surprisingly, you can actually leave off any of the three parts. 

Here we just have the initializer.  You still need the semicolons so the compiler knows which part of the for loop you mean:
for (int i=0;;) {
cout<<i<<"\n";
i++;
if (i>=5) break; /* exit loop */
}

(Try this in NetRun now!)

Here we just have the test:
int i=0;
for (;i<5;) {
cout<<i<<"\n";
i++;
}

(Try this in NetRun now!)

Here we just have the counting part:
int i=0;
for (;;i++) {
if (i>=5) break; /* exit loop */
cout<<i<<"\n";
}

(Try this in NetRun now!)

You really can put any C++ expression inside the for loop statements.  For example, here we're looping across the letters of a string!
for (string s="a";s!="abbb";s+="b") {
cout<<s<<"\n";
}

(Try this in NetRun now!)

We'll see some pretty complex for loops when we talk about data structures after spring break.

While Loop (Gaddis Chapter 5.2)

A while loop is actually much simpler than a for loop, because it only has one part, the test.  I claim this is actually a bad thing, and I prefer "for" to "while", because "for" provides nice places to remind you to write all three parts of the loop.  For example, in this "while" translation of a "for" loop, what would happen if you forgot the "i++"?
int i=0;
while (i*i<100) {
std::cout<<i*i<<"\n";
i++;
}

(Try this in NetRun now!)

One place a while loop is handy is to keep getting integers from cin until there are no more integers to get:
int i;
while (cin>>i) {
std::cout<<i<<"'s square is "<<i*i<<"\n";
}

(Try this in NetRun now!)

This looks pretty weird, but "cin>>i" returns true if the input worked, so we should keep getting more integers.  "cin>>i" returns false if cin is unhappy (in an error state).  It might be unhappy because there aren't any more integers to get, or because the user typed a non-integer.  To make cin happy again, call "cin.clear();".

Generally speaking, if you know exactly how many iterations you'll be doing, a "for" loop is appropriate.  If you don't know how many iterations you'll use, "while" is more approriate.

A while loop whose condition fails the first time around will not execute even once.  For example, this prints nothing:
int i=13;
while (i<10) {
std::cout<<i<<"'s square is "<<i*i<<"\n";
i++;
}

(Try this in NetRun now!)

This prints nothing, because i=13 does not pass the test i<10.

Do Loop (Gaddis Chapter 5.5)

A do loop is exactly like a while, but it tests the condition only after executing the loop one time.  The same code above written with a do loop prints the square of 13 and exits:
int i=13;
do {
std::cout<<i<<"'s square is "<<i*i<<"\n";
i++;
} while (i<10);

(Try this in NetRun now!)

Break and Continue (Gaddis Chapter 5.12)

"break" leaves the enclosing loop.  "continue" goes back to the start of the loop.  Both are useful for handling various errors.  For a hard error, "break" is one way to just stop looping; while "continue" lets the user try again.
int v;
for (int i=0;i<3;i++) {
std::cout<<"Please enter an integer from 1..10:\n";
cin>>v; /* try to read */
if (!cin) {
cout<<"Input ERROR; exiting...\n";
break; /* hard error; leave the loop */
}
if (v<1 || v>10) {
cout<<"BAD input value "<<v<<"; try again.\n";
continue; /* back to start of loop */
}
std::cout<<"i="<<i<<" and v="<<v<<"\n";
}

(Try this in NetRun now!)

Goto (not in Gaddis)

The syntax of goto is quite simple.  "goto X;" jumps over to the portion of your code labelled X.  You can add labels to any part of your code.  For example, this code skips over the middle cout using a goto:
cout<<"How you doin?\n";
goto X;
cout<<"You talkin to me? Hey, you talkin to ME!?\n";
X:
cout<<"Anyway, gotta go.\n";

(Try this in NetRun now!)

This code simulates a for loop using a goto:
int i=0;
startEmUp:
cout<<"i="<<i<<"\n";
i++;
if (i<5) goto startEmUp;
cout<<"See ya!\n";

(Try this in NetRun now!)

This code simulates a function call using a goto in "printGreeting".  To get back, you need a separate variable, here called "back", that is accessible to both caller and called code.  Adding a new caller means you need to modify the called code.  This is a very poor substitute for real functions!
int back; /* determines where to jump back to */

back=1;
goto printGreeting;
back1:

cout<<"How are you!\n";

back=2;
goto printGreeting;
back2:
goto end;

printGreeting:
cout<<"My most honored and illustrious friend!\n";
if (back==1) goto back1;
else goto back2;

end:

(Try this in NetRun now!)

The basic problem with goto is that it is extremely powerful.  It can simulate branches, loops, functions, and other weirder control statements that have no direct analog.  Looking at one line of code, for example "goto X;", you can't tell whether that's part of a loop, part of a function call, or something even more bizarre.

The goto statement has thus earned a very bad reputation.  Famously, in 1968 Edsger Dijkstra wrote a short but very influential article titled "Go To Statement Considered Harmful", in response to what has come to be called "spaghetti code":
int i;
goto start;
gimme:
cout<<"Gimme a value\n";
goto back1;
start:
goto gimme;
back1:
cin>>i; // try to read
goto errcheck;
back2:
cout<<"Got value "<<i<<"\n";
if (i>=1 && i<=10) goto destination;
goto start;
destination:
cout<<"Valid input "<<i<<"\n";
goto end;
errcheck:
if (!cin) goto destination;
goto back2;
end:

(Try this in NetRun now!)

The absurd overuse of goto statements in this chunk of code makes it extremely hard to read--looking at one line of code at a time, you can't tell where you are in the program, where you came from, or where you're going.  The same code written as a loop is much clearer.

Like alcohol, although fine in moderation it is very easy to abuse goto.  Hence there is a strong taboo against the use of goto, and many modern languages (such as Saudi Arabia; er, Java) prohibit it entirely.