-5

If I have code that looks like this:

int i;
void functionA (){
    for (i=0; i<10; i++){
        functionB();
    }
}
void functionB (){
    for (i=0; i<20; i++){
        doSomething();
    }
}

It seems like using the same variable i to iterate through the two for-loops would overlap and cause errors.

I've always just used a second variable instead of i to iterate through functionB(), but that gets hard to manage.
Is there an easier way to do this, like maybe making a variable private to one for-loop? How do I do that?

1
  • 1
    "maybe making a variable private to one for-loop?" - yes, it's called a local loop variable, just declare it in the loop itself for (int i = 0; i < length; i++). It's local to the loop block, and it goes out of scope when the loop ends; you can reuse the name all you like. Commented Dec 29, 2020 at 7:19

1 Answer 1

4

It seems like using the same variable 'i' to iterate through the two for-loops would overlap and cause errors.

Indeed, it would. Well, not "errors", so much as unexpected behavior. The code you have is syntactically fine; no C or C++ compiler that I know of would raise any warnings, much less errors. However, if you run it, you'll see that it merely loops through 20 times (i = 0 to 19).

Why? Because the i variable is a global variable, shared across both functionA and functionB. functionA initializes i to 0, then immediately (first iteration of the loop) calls functionB. functionB resets i back to 0 and then loops through 20 times before returning. Upon return to functionA, i has the value 19. That is not less than 10, so the check in the for loop's ending condition inside of functionA fails and the loop exits.

The behavior is correct and predicable, but unexpected, assuming that you were intending the loop in functionA to run through 10 times.

This is why shared state should be avoided whenever possible: it makes the behavior of a program more difficult to reason about.

Is there an easier way to do this, like maybe making a variable private to one for-loop?

Yes, that is precisely what you should do. In fact, always prefer to reduce the scope of a variable whenever possible. What you have now is a global variable. Making a local variable (one that is local to each function) would be preferable, e.g.:

void functionA (){
    int i;
    for (i=0; i<10; i++){
        functionB();
    }
}
void functionB (){
    int i;
    for (i=0; i<20; i++){
        doSomething();
    }
}

But even better is to actually scope the index variable to the for loop itself. That can be done by declaring the variable within the loop statements:

void functionA (){
    for (int i=0; i<10; i++){
        functionB();
    }
}
void functionB (){
    for (int i=0; i<20; i++){
        doSomething();
    }
}

Personally, I like to write the increment statement as ++i, since that's a better reflection of what is actually happening. As a bonus, it may, with certain types of objects, in certain languages, be more efficient. But in C and/or with an int, both forms result in identical object code. I just prefer the pre-increment.

1
  • 1
    In C, ++i and i++ do have different behavior, though it may not be observable in this code, and most optimizing compilers may output the same machine code (for this situation). But in general, ++i returns the incremented value and i++ returns the value from before the increment. int a=0; int b=0; printf("%d, %d; ", ++a, b++); printf("%d, %d\n", a, b); will print 1, 0; 1, 1.
    – 8bittree
    Commented Dec 29, 2020 at 17:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.