Home > Back-end >  A better way to exit nested for loops in C ?
A better way to exit nested for loops in C ?

Time:06-25

Here are the only two ways I know that roughly makes sense:

for (){
    for (){
        if (found the target) goto cont;
    }
}
cont:;

I've seen people strongly recommending against using goto, but I feel like this is a pretty proper way of using it.

bool exit=false;
for (){
    for (){
        if (found the target){
            exit=true;
            break;
        }
    }
    if (exit) break;
}

I write a bit more code this way.

What would you say to be the proper way to do this?

CodePudding user response:

You can add a layer of abstraction. If this is a loop that will be used in multiple places, then wrap it in a function like

auto do_stuff(params_t params)
{
    for (...){
        for (...){
            if (found_the_target) return something;
        }
    }
}

If this is a one off, then you can create a lambda on the fly like

auto thing_i_wanted_to_know = [&]{ for(...){ 
                                       for(...){ 
                                           if (found_the_target) return something; 
                                       }
                                   } 
                                 }();

CodePudding user response:

Just change your nested loops the following way

bool exit=false;
for ( ; !exit; ){
    for ( ; !exit; ){
        if (found the target){
            exit=true;
        }
    }
}

Usually the inner for loop can be rewritten either like while or do-while loop avoiding using the break statement that makes the code more clear.

CodePudding user response:

I consider this to be a valid use of goto, but I myself use flags for this.


As an experiment, I've also ported Java's named loops to C , using macros.

Usage:

for (int i = 0; i < 10; i  ) LOOP_NAME(foo)
{
    for (int j = 0; j < 10; j  )
    {
        if (i == 5 && j == 5)
            break(foo);
    }
}

Implementation:

#define LOOP_NAME(name) \
    /* The variable in the conditions prevents `BREAK/CONTINUE` from */\
    /* being used outside of the loop with the matching name. */\
    if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
    { \
        [[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_break_,name): break; \
        [[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_continue_,name): continue; \
    } \
    else

#define LOOP_NAME_impl_cat(x, y) LOOP_NAME_impl_cat_(x, y)
#define LOOP_NAME_impl_cat_(x, y) x##y

#define BREAK(name) goto LOOP_NAME_impl_cat(_namedloop_break_,name)
#define CONTINUE(name) goto LOOP_NAME_impl_cat(_namedloop_continue_,name)

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define break(x) BREAK(x)
#define continue(x) CONTINUE(x)
#ifdef __clang__
#pragma clang diagnostic pop
#endif
  •  Tags:  
  • c
  • Related