My opinion is that the first example you gave is the "right" way to do it. Why do I feel this way? Let's go over a few reasons.
Variable Scope
In this snippet that you have provided, it looks like it is all contained within a single function. As a result, none of the variables declared within the function are accessible outside of the function. Now, if sum were declared as a member variable (or field, in Java) to a containing class, your concern about accessibility may be more justified. But who else are you worried about having this value? No other object can touch it. It's even more private than a private
member variable. Once the function returns, it dies...
Compilation
Eventually, the code written above gets compiled into machine code that the processor can run. You may be surprised to know that when this happens, both variables i
and sum
will live side by side in memory. Now scope-wise, the compiler will treat i
and sum
differently, but when they are finally compiled and running on the processor, i
and sum
will be neighbors.
Efficiency
In the second example, your iterator i
is a float
instead of an int
. This means, your comparison, i<students.length
and your increment, i++
are going to be less efficient for float
s than they are for int
s, because floating point arithmetic takes more processor cycles than integer arithmetic.
Maintainability
Software engineering ends up being an interesting problem to solve, because it all depends on what you are trying to optimize for. The code I work with often requires being optimized for readability so that when another software developer comes down a year from now, he can read what my code is doing with minimal confusion. The second example is much more confusing than the first – perhaps, if for no other reason, than it is significantly out of the norm, for very little benefit.