Breaking out of a loop from within a function called in that loop
You cannot use break;
this way, it must appear inside the body of the for
loop.
There are several ways to do this, but neither is recommended:
you can exit the program with the
exit()
function. Since the loop is run frommain()
and you do not do anything after it, it is possible to achieve what you want this way, but it as a special case.You can set a global variable in the function and test that in the
for
loop after the function call. Using global variables is generally not recommended practice.you can use
setjmp()
andlongjmp()
, but it is like trying to squash a fly with a hammer, you may break other things and miss the fly altogether. I would not recommend this approach. Furthermore, it requires ajmpbuf
that you will have to pass to the function or access as a global variable.
An acceptable alternative is to pass the address of a status
variable as an extra argument: the function can set it to indicate the need to break from the loop.
But by far the best approach in C is returning a value to test for continuation, it is the most readable.
From your explanations, you don't have the source code for foo()
but can detect some conditions in a function that you can modify called directly or indirectly by foo()
: longjmp()
will jump from its location, deep inside the internals of foo()
, possibly many levels down the call stack, to the setjmp()
location, bypassing regular function exit code for all intermediary calls. If that's precisely what you need to do to avoid a crash, setjmp()
/ longjmp()
is a solution, but it may cause other problems such as resource leakage, missing initialization, inconsistent state and other sources of undefined behavior.
Note that your for
loop will iterate 101
times because you use the <=
operator. The idiomatic for
loop uses for (int i = 0; i < 100; i++)
to iterate exactly the number of times that appears as the upper (excluded) bound.
(Note: the question has been edited since I originally wrote this)
Because of the way C is compiled it must know where to break to when the function is called. Since you can call it from anywhere, or even somewhere a break makes no sense, you cannot have a break;
statement in your function and have it work like this.
Other answers have suggested terrible solutions such as setting a global variable, using a #define
or longjumping(!) out of the function. These are extremely poor solutions. Instead, you should use the solution you wrongly dismiss in your opening paragraph and return a value from your function that indicates the state that you want to trigger a break
in this case and do something like this:
#include <stdbool.h>
bool checkAndDisplay(int n)
{
printf("%d\n", n);
return (n == 14);
}
int main(void) {
for (int i = 0; i <= 100; i++) {
if (checkAndDisplay(i))
break;
}
return 0;
}
Trying to find obscure ways to achieve things like this instead of using the correct way to achieve the same end result is a surefire way to generate dire quality code that is a nightmare to maintain and debug.
You mention, hidden in a comment, that you must use a void return, this is not a problem, just pass the break parameter in as a pointer:
#include <stdbool.h>
void checkAndDisplay(int n, bool* wantBreak)
{
printf("%d\n", n);
if (n == 14)
wantBreak = true;
}
int main(void) {
bool wantBreak = false;
for (int i = 0; i <= 100; i++) {
checkAndDisplay(i, &wantBreak);
if (wantBreak)
break;
}
return 0;
}
Since your parameters are fixed type I suggest you use a cast to pass in the pointer to one of the parameters, e.g. foo(a, b, (long)&out);
break
, like goto
, can only jump locally within the same function, but if you absolutely have to, you can use setjmp
and longjmp
:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jump_target;
void foo(void)
{
printf("Inside foo!\n");
longjmp(jump_target, 1);
printf("Still inside foo!\n");
}
int main(void) {
if (setjmp(jump_target) == 0)
foo();
else
printf("Jumped out!\n");
return 0;
}
The call to longjmp
will cause a jump back to the setjmp
call. The return value from setjmp
shows if it is returning after setting the jump target, or if it is returning from a jump.
Output:
Inside foo!
Jumped out!
Nonlocal jumps are safe when used correctly, but there are a number of things to think carefully about:
- Since
longjmp
jumps "through" all the function activations between thesetjmp
call and thelongjmp
call, if any of those functions expect to be able to do additional work after the current place in execution, that work will simply not be done. - If the function activation that called
setjmp
has terminated, the behaviour is undefined. Anything can happen. - If
setjmp
hasn't yet been called, thenjump_target
is not set, and the behaviour is undefined. - Local variables in the function that called
setjmp
can under certain conditions have undefined values. - One word: threads.
- Other things, such as that floating-point status flags might not be retained, and that there are restrictions on where you can put the
setjmp
call.
Most of these follow naturally if you have a good understanding of what a nonlocal jump does on the level of machine instructions and CPU registers, but unless you have that, and have read what the C standard does and does not guarantee, I would advise some caution.