(1) Imagine this 3-loop construction occurs half-a-dozen times in the
function
(2) You would only need one 'int' declaration in the first variant, rather
than 18.
(3) The extra clutter in the second, is only telling you what you've already
guessed, that these loop indices are all ints.
No, it's also telling you that each loop index will be used, with it's
particular meaning, within a restricted scope.
(4) But if you *did*, at some point, need to change the loop indices from
int to something else, you've got eighteen times as much editing to do.
No, in general, if you change the type of one of the loop indexes, you
will NOT need to change all of the other seventeen. That's the reason
why separating them is both possible and desirable.
(5) This would be bad practice, but if you ever found it necessary to goto
from one loop body to another, the loop indices would be undefined.
Yes, and a diagnostic is mandatory when that occurs. Making that
diagnostic mandatory is one of the purposes of writing code this way. If
you're changing a variable from having a meaning that's restricted to
one limited scope, into a variable with a wider scope, you should move
the point of declaration to reflect that fact. This is not the kind of
change that should be easy to make without thinking about the consequences.
(6) If you wanted to break out of any of the loops, and needed to refer to
the value of the loop variable outside, it would either not exist, or be
confused with a more global version.
As with point 5, requiring you to move the declaration in order to avoid
the otherwise mandatory diagnostic is precisely the point of writing
code this way. You should have to invest at least a little bit of time
thinking about it whenever you decide to widen the scope of a variable.
When you always declare them with the widest possible scope, it does
make things easier, but in particular it makes it easier to commit
design errors, such as using the same variable name for two unrelated
purposes.
(7) If ever needed to refer to one of the variables, either in a debugger,
or on the phone to somebody, or in a note or email or comment, or even in a
printf caption, then you've got a problem.
No, in general that's not a problem; the context will usually make it
clear which variable you're referring to; if you're referring to it out
of the proper context, that's the problem, not the fact that scope has
been deliberately limited. If the proper context is bigger than the
scope a variable has been given, then the scope is too small, and it's
declaration should be moved to the innermost block that contains all of
the contexts where it is needed; but only the innermost one, not to any
block farther out.
Admittedly for the single bit of code in your example, it's not much of an
issue. But for the more general case of having declarations scattered
everywhere, identically-named variables shadowing each other in nested
scopes,
Shadowing is something to be avoided in general; by giving each variable
the smallest scope consistent with its intended use, you actually reduce
the chance that another variable with the same name will shadow it (or,
more seriously, be accidentally merged with it by using a single
declaration for both uses).
identically-named variables from different scopes getting mixed up
Defining variables with the smallest scope consistent with their
intended use prevents mixing them up; declaring them with a wider scope
than they need creates more opportunities for mixing them up.
(and what *does* happen when you goto from from block to another?),
If the second block is not nested inside the first one, then variables
declared in the first block will no longer be visible. If that's a
problem for some particular variable, then that variable has NOT been
declared with the smallest possible scope consistent with its intended
use; it needs to be moved up to a higher scope that includes both
blocks. The point is, it should be moved up only to the smallest scope
that includes both blocks.