1

Say you have a double-nested for, like when you are trying to see if an item in one unsorted array is inside another unsorted array. So for example say you have 2 lists candidates and corruptPeople, you're going through the candidates and skipping those that are listed in corruptPeople.

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
             break_this_loop_and_then_continue_outer_loop ;

    // initiate the eligible candidates
    initiate( candidates[i] ) ;
}
bobobobo
  • 64,917
  • 62
  • 258
  • 363

4 Answers4

3

One way to do this (which I'm open to peer review for!) is using goto:

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
             goto END_FOR ;

    // initiate the eligible candidates
    initiate( candidates[i] ) ;

    END_FOR:
    ; // seem to need an empty statement to make it compile
}

I'm curious what others have to say of the use of goto in this context. A dogmatic disagreeal with goto means you're going to have a dogmatic application of structured programming.. which looked pretty bad when I tried it.

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 2
    I don't think using a goto could ever be considered a clean solution -- even if in the end it was necessary. – goji Dec 07 '12 at 04:11
  • 1
    Personally, this is one of the few cases where I _prefer_ `goto`. As maligned as it is, and as much as it can be abused, I find it simpler in cases like this than other solutions. – Joshua Green Dec 07 '12 at 04:38
  • It may not be clean, but unfortunately C doesn't have anything quite as nice as, say, Python's `for ... else` construct. – Joshua Green Dec 07 '12 at 04:42
  • 1
    The reason you need an empty statement to make it compile is that `;` is a statement but an empty sequence of tokens isn't. Therefore `END_FOR:;` is a labelled statement but `END_FOR:` isn't. – Steve Jessop Dec 07 '12 at 04:51
  • Some info regarding the need for `;`... http://stackoverflow.com/questions/8384388/variable-declaration-after-goto-label-c – Krishnabhadra Dec 07 '12 at 04:53
2

Much better to use an additional variable than to resort to a goto:

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    int corrupt = 0;
    for( int j = 0 ; j < lenCorruptPeople ; j++ )
        if( candidates[i] == corruptPeople[j] )
        {
            corrupt = 1;
            break;
        }

    // initiate the eligible candidates
    if (!corrupt) initiate( candidates[i] ) ;
}
goji
  • 6,911
  • 3
  • 42
  • 59
0

How about the below code? Am I missing something?

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    int j;
    for( j = 0 ; j < lenCorruptPeople ; j++ )
    {
        if( candidates[i] == corruptPeople[j] )
          break;
    }

    //j will be equal to lenCorruptPeople only when candidate is not in corrupt list   
    if(j==lenCorruptPeople)
    {
        initiate( candidates[i] ) ;
    }

}
Jay
  • 24,173
  • 25
  • 93
  • 141
0

Moving the inner loop to another function often helps:

typedef int Person; // or whatever it is.

Person *findPerson(Person *first, Person *last, Person val)
{
    while (first != last)
    {
        if (val == *first) return first;
        ++first;
    }
    return 0;
}

...

for( int i = 0 ; i < lenCandidates ; i++ )
{
    // veto candidates[i] if candidates[i] is in corruptPeople at all
    if (!findPerson(corruptPeople, corruptPeople+lenCorruptPeople, candidates[i]))
    {
        // initiate the eligible candidates
        initiate( candidates[i] ) ;
    }
}
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    I think I would go crazy if I had to define a new function every time I had a situation like this. – Joshua Green Dec 07 '12 at 04:49
  • @JoshuaGreen: Fortunately you don't have to do it every time, but it often helps. In this case "find" is a simple abstraction that might even be re-usable, so I think it's a fairly good candidate. If you don't like short functions that do one thing then of course `findPerson` is a nightmare ;-p – Steve Jessop Dec 07 '12 at 04:54