I\'m currently trying to figure out a way to break out of a for
loop from within a function called in that loop. I\'m aware of the possibility to just have the
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 from main()
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()
and longjmp()
, 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 a jmpbuf
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.
This is another idea that may or may not be feasible: keep a variable around that can turn foo into a no-op:
int broken = 0;
void foo (int a) {
if (broken) return;
printf("a: %d", a);
broken = 1; // "break"
}
int main(void) {
for (int i = 0; i <= 100; i++) {
foo(i);
}
return 0;
}
This is functionally the same except for some loss of clock cycles (the function will be called, but perform only the if
statement), and there is no need to change the loop. It's not threadsafe and only works the first time (but foo
could reset the broken
variable to 0 if called with a
equal to 0, if needed).
So not great, but an idea that wasn't mentioned yet.
Following your updated question clearly setting out the limitations, I would suggest you move the entire loop inside your function and then call a second function with a return value inside that function, e.g.
#include <stdbool.h>
bool foo (int x)
{
return (x==14);
}
void loopFoo(int passV, int aVal, long bVal)
{
for (int i = 0; i <= 100; ++i)
{
if (foo(x))
break;
}
}
This avoids any extreme and fragile gymnastics to get around the limitation.
You can throw an error in your function inside the loop and catch that error outside the loop.
#include <stdio.h>
void foo (int a) {
printf("a: %d", a);
if (a == 50)
{
throw a;
}
}
int main(void) {
try {
for (int i = 0; i <= 100; i++) {
foo(i);
}
catch(int e) {
}
return 0;
}
If you cannot use the break
instruction you could define a local variable in your module and add a second run condition to the for
loop. For example like the following code:
#include <stdio.h>
#include <stdbool.h>
static bool continueLoop = true;
void foo (int a)
{
bool doBreak = true;
printf("a: %d",a);
if(doBreak == true){
continueLoop = false;
}
else {
continueLoop = true;
}
}
int main(void) {
continueLoop = true; // Has to be true before entering the loop
for (int i = 0; (i <= 100) && continueLoop; i++)
{
foo(i);
}
return 0;
}
Note that in this example this is not exactly a break
-instruction, but the for
loop will not do another iteration. If you want to do a break
you have to insert an if
-condition with the variable continueLoop
which leads to break
:
int main(void) {
continueLoop = true; // Has to be true before entering the loop
for (int i = 0; i <= 100; i++)
{
foo(i);
if(!continueLoop){
break;
}
}
return 0;
}
In a case like this consider using a while() loop with several conditional statements chained with && instead of a for loop. Although you can alter the normal control flow using functions like setjmp and longjmp, it's pretty much considered bad practice everywhere. You shouldn't have to search too hard on this site to find out why. ( In short it's because of it's capacity to create convoluted control flow that doesn't lend itself to either debugging or human comprehension )
Also consider doing something like this:
int foo (int a) {
if(a == someCondition) return 0;
else {
printf("a: %d", a);
return 1;
}
}
int main(void) {
for (int i = 0; i <= 100; i++) {
if(!foo(i)) break;
}
return 0;
}
In this case, the loop depends on a true value being returned from 'foo', which will break the loop if the condition inside 'foo' is not met.
Edit: I'm not explicitly against the use of goto, setjmp, longjmp etc. But I think in this case there is a much simpler and more concise solution available without resorting to these measures!