The next kind of control flow statement we’ll cover is the unconditional jump. An unconditional jump causes execution to jump to another spot in the code. The term “unconditional” means the jump always happens (unlike an if statement
or switch statement
, where the jump only happens conditionally based on the result of an expression).
In C++, unconditional jumps are implemented via a goto statement, and the spot to jump to is identified through use of a statement label. The following is an example of a goto statement
and statement label
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> #include <cmath> // for sqrt() function int main() { double x{}; tryAgain: // this is a statement label std::cout << "Enter a non-negative number: "; std::cin >> x; if (x < 0.0) goto tryAgain; // this is the goto statement std::cout << "The square root of " << x << " is " << sqrt(x) << '\n'; return 0; } |
In this program, the user is asked to enter a non-negative number. However, if a negative number is entered, the program utilizes a goto statement
to jump back to the tryAgain label. The user is then asked again to enter a new number. In this way, we can continually ask the user for input until he or she enters something valid.
Here’s a sample run of this program:
Enter a non-negative number: -4 Enter a non-negative number: 4 The square root of 4 is 2
Statement labels have function scope
In the chapter on object scope (chapter 6), we covered three kinds of scope: local (block) scope, file scope, and global scope. Statement labels utilize a fourth kind of scope: function scope, which means the label is visible throughout the function even before its point of declaration. The goto statement
and its corresponding statement label
must appear in the same function.
While the above example shows a goto statement
that jumps backwards (to a preceding point in the function), goto statements
can also jump forward:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> void printCats(bool skip) { if (skip) goto end; // jump forward; statement label 'end' is visible here due to it having function scope std::cout << "cats"; end: ; // statement labels must be associated with a statement } int main() { printCats(true); // jumps over the print statement and doesn't print anything printCats(false); // prints "cats" return 0; } |
This prints:
cats
Beyond the jumping forward, there are a couple of interesting things worth mentioning in the program above.
First, note that statement labels
must be associated with a statement (hence their name: they label a statement). Because the end of the function had no statement, we had to use a null statement
so we had a statement to label. Second, we were able to jump to the statement labeled by end
even though we hadn’t declared end
yet due to statement labels
having function scope. No forward declaration of statement labels
is necessary. Third, it’s worth explicitly mentioning that the above program is poor form -- it would have been better to use an if statement
to skip the print statement than a goto statement
to jump over it.
There are two primary limitations to jumping: You can only jump forward or backward within a single function (you can’t jump out of one function and into another), and if you jump forwards, you can’t jump forward over the initialization of any variable that is still in scope at the location being jumped to. For example:
1 2 3 4 5 6 7 8 |
int main() { goto skip; // error: this jump is illegal because... int x { 5 }; // this initialized variable is still in scope at statement label 'skip' skip: x += 3; // what would this even evaluate to if x wasn't initialized? return 0; } |
Note that you can jump backwards over a variable initialization, and the variable will be re-initialized when the initialization is executed.
Avoid using goto
Use of goto
is shunned in C++ (and other modern high level languages as well). Edsger W. Dijkstra, a noted computer scientist, laid out the case for avoiding goto
in a famous but difficult to read paper called Go To Statement Considered Harmful. The primary problem with goto
is that it allows a programmer to jump around the code arbitrarily. This creates what is not-so-affectionately known as spaghetti code
. Spaghetti code is code that has a path of execution that resembles a bowl of spaghetti (all tangled and twisted), making it extremely difficult to follow the logic of such code.
As Dijkstra says somewhat humorously, “the quality of programmers is a decreasing function of the density of go to statements in the programs they produce”.
Almost any code written using a goto statement
can be more clearly written using other constructs in C++, such as if statements
and loops. One notable exception is when you need to exit a nested loop but not the entire function -- in such a case, a goto
to just beyond the loops is probably the cleanest solution.
Best practice
Avoid goto statements
(unless the alternatives are significantly worse for code readability).
![]() |
![]() |
![]() |
on the first code of the goto, there should be a
in the main() function.
Hahaha, this reminds me of the basic programming I used to do when I was a teen. Every time I wanted to add something to my program (an addition or even a correction), I'd insert a GOTO statement which went to a new section of linenumbers at the end of the program and deal with the problem there. Spaghetti-coding at it's worst.
lol! Same bro :P its funny now that we think about it :)
hiiiiiiiiii. this tut. helps very much and Thank u for helping me in goto statement. this statement helps me much. as i calculate sqr.
Thanks.
Thanks for the Tut. Could you also give a typical example about how to avoid a goto-label by using a loop?
That's of interest to me, because after inheriting some C++ Code (coded with MS Vis. C++), I started to learn Cpp some 3 months ago (your tutorials could have saved me 2 months!). The code has a goto-label in it, which seems to conflict with Qt-IDE( & g++ compiler) since I must placed the Qt-code in curly brackets to avoid Compile error "crosses initialization of..."
Thanks
#include <iostream>
#include <cmath>
int main()
{
using namespace std;
tryAgain: // this is a statement label
cout << "Enter a non-negative number";
double dX;
cin >> dX;
if (dX < 0.0)
goto tryAgain; // this is the goto statement
cout << "The sqrt of " << dX << " is " << sqrt(dX) << endl;
}
Could be made
#include <iostream>
#include <cmath>
int main()
{
using namespace std;
double dX;
while (true)
{
cout << "Enter a non-negative number";
cin >> dX;
if (dX > 0.0)
break;
}
cout << "The sqrt of " << dX << " is " << sqrt(dX) << endl;
cin >> dX;
}
Sure, it's not the best example in the world, but hey.
I've found just a few instances where I found goto helpful. But it is indeed helpful. On the ASM level when the program is compiled, there's a WHOLE lot of goto-ish jumping going on. The idea of not using goto in higher level programming is just giving you less rope to hang yourself with.
@spock
I have a similar first memory. Virtually the same code, apart from I printed "Stephen" and I did it on my Amstrad CPC in 1987 :)
@spock, @Steve
How interesting. I also wrote a similar program as a kid, but in the 90s. My second program was a text menu of options which allowed the user to choose which one of four different ways they wanted to get lost in an endless loop :)
I'm not sure if all new programmers go through a stage of doing pointless things for amusement, but I do know that when I showed the program to my mum she looked at me like she was questioning my mental health.
I prefer to think that my fascination with endless loops was simply a young fascination with the concept of infinity or, er, something intelligent like that...
I think I probably did the same thing on an Apple II+.
It always seems like a good idea before you do it.
aaaah.... I remember my first ever code as a 7 year old written in Basic was a goto loop.
I wrote it using a ZX spectrum 48k computer my parents bought me in '84. My code was:
10 Print "Hello Richard"
20 Goto 10
Run
I thought I was brilliant...
;)
In The second line... I think you mean "through" instead of "though".
"This spot is identified though use of a statement label."
[ Indeed! Thanks. -Alex ]
i entered the code which you gave for finding the sqrt.
it obviously worked fine
however when i typed in "-9-" it kept on printing "Enter a non-negative number" continuously (i know i shouldnt have done this!!)
can you pliz tell me what is actually happening!
Sure. The first time through, it asks you to enter a #, so you type in "-9-". It extracts "-9" into the dX variable, leaving the trailing "-" sign still in the input buffer.
Because (dX < 0.0) is true, it loops back to the tryAgain label. This time, it tries to extract the "-" into dX, which fails, so dX keeps it's previous value of -9. This causes it to loop again (and again, and again). Ideally we should check to make sure the extraction operator (>>) succeeded, but that's beyond the scope of this tutorial. I believe I cover how to do this in chapter 13, which is when the tutorial delves into I/O issues.
Alex -
I am really enjoying this tutorial. May I suggest that this section be renamed " 5.4 — Goto statements (and why they are evil)"?
;)
Also, you might want to make your reference to "spaghetti code" (in bold) into a link: http://en.wikipedia.org/wiki/Spaghetti_code