3

During my c++ courses at my university I got use to the practice of (and was taught to) declaring an int in a for loop like so:

for(int i = 0; i < 5; i++)
{
    // code
 }

But now that I’m in a mechatronics class where we write in c and Arduino the teacher told me it is bad practice to do this and suggested doing it this way:

int i = 0;
for(i; i < 5; i++)
    //code

Why would one be preferred over the other?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • No iterators are involved here. These are just indices. The first version is better because it scopes `i` to the place where it's used. The second version makes little sense, even if it's an old C standard that prohibits loop initialization (`i` does nothing in the initializer; it'd normally be `i = 0` here). Only do it this way if the compiler won't let you initialize in the loop or in the uncommon case you need to use `i` in the outer block after the loop ends. It's pretty seldom you need these sort of loops in C++ anyway. Prefer range loops or actual iterators. – ggorlen Feb 19 '21 at 19:14
  • 15
    It is not a bad practice. It is just the "old-school" way back in the days defining variables was restricted to the beginning of a function only. This restriction is obsolete now, unless you are forced to use some old C revision. – Eugene Sh. Feb 19 '21 at 19:16
  • It was not allowed in old versions – Bernd Feb 19 '21 at 19:16
  • 11
    The second approach is required in very old versions of C and is mostly just around for legacy support and as a habit from dinosaurs. Modern practices usually encourages limiting the scope of objects to the minimum you need, and to keep variable definitions near their first use. Both of these practices suggest using the `for(int i; i<5; ++i)` variant. – François Andrieux Feb 19 '21 at 19:17
  • 5
    Prefer the first, unless it doesn't compile, in which case prefer to second. – john Feb 19 '21 at 19:20
  • 3
    Does this answer your question? [Declaring variables inside loops, good practice or bad practice?](https://stackoverflow.com/questions/7959573/declaring-variables-inside-loops-good-practice-or-bad-practice) – Shivendra Agarwal Feb 19 '21 at 19:23
  • 7
    Declaring a legitimate style to be "bad practice" without explanation is bad teaching. Ask. your instructor *why* it's bad practice, and listen with an open mind. They may have a legitimate point, or they may be stuck in 1987, or perhaps you misunderstood what they were saying in the first place. Whatever happens, you'll learn something. – Caleb Feb 19 '21 at 19:31
  • Can you ask your teacher to visit this question and read all the comments? Maybe he/she will learn something new today. – Tanveer Badar Feb 19 '21 at 19:46
  • 1
    I would say that `int i = 0; for(i; i < 5; i++)` is poor style no matter what. If you're using an old compiler or just prefer doing things the old way, I recommend `int i; for(i = 0; i < 5; i++)`. It's the intent of the `for` loop, and good style, to collect all the information right there in one place: initial value, final value, and increment. – Steve Summit Feb 19 '21 at 20:17

4 Answers4

6

"mechatronics class"

I'm going to employ a reasonable guess.

The compiler you have is probably dumb and compiles this

for(int i = 0; i < 5; i++) {
    //code
}
for(int i = 0; i < 5; i++) {
    //code
}

to use two independent stack variables. Modern compilers are better than that but embedded systems have old dumb compilers, and old instructors remember the problems long after they're fixed. Given this is Arduino, if you've got an up-to-date compiler it's just plain old wrong now.

I remember using a compiler that would explode on this code with i has already been declared but I digress.

Joshua
  • 40,822
  • 8
  • 72
  • 132
  • Sounds like the OP is using Arduino, which is C++ compiler under the hood. So this restriction does not make sense at all. – Eugene Sh. Feb 19 '21 at 19:24
  • @EugeneSh.: Compilers with this fault I encountered were C++ compilers. – Joshua Feb 19 '21 at 19:25
  • Oh, I see what your answer is about. Misinterpreted it at first. – Eugene Sh. Feb 19 '21 at 19:26
  • "a compiler that would explode on this code with `i` has already been declared" - indeed, Microsoft Visual C++ used to have this bug! Ridiculous. As a result it was necessary to wrap `for` loops in extra braces. – Bungo Feb 19 '21 at 20:51
5

Why would one be preferred over the other?

In cases where you for example break out of the loop early, you might want to know the last value of i which is of course only accessible if it was declared outside the loop. So, in this case that is the only option (unless you use a separate variable for that, but this adds unnecessary complexity).

But generally when both are valid options, declaring all variables in smallest possible scope is potentially marginally more efficient, and easier to read - although latter may be subjective, so this is mostly a matter of taste. The former is objectively not "bad practice" in general.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

To be honest, it's not bad practice, the only difference is the iterator will be accessible after the loop is finished running in the second scenario

  • Also, the second version is one line longer. If you can write shorter code, do it! – M-Chen-3 Feb 19 '21 at 19:19
  • @M-Chen-3 Sure, also it deallocates the memory earlier –  Feb 19 '21 at 19:20
  • 6
    @M-Chen-3 That is a pretty naive rule of thumb that can easily back-fire. It sounds good at first glance. But brief code is not necessarily better code. Often, writing code that is a bit longer but clearer is going to be better. – François Andrieux Feb 19 '21 at 19:20
  • @FrançoisAndrieux That's why I said "if you can". Obviously, if there are some requirements for it to be clear then you shouldn't. – M-Chen-3 Feb 19 '21 at 19:21
  • 2
    @user15244951: No it doesn't. The memory is freed when the function is returned in either case. The compiler will not bother to emit the stack-frame-sizechanger for something not a variable-length array. – Joshua Feb 19 '21 at 19:30
  • @Joshua So all my work using local scopes to free memory early is wasted? –  Feb 19 '21 at 19:30
  • 1
    @user15244951: If your compiler is newer than 2010, yes. If older, we'd both be guessing. (Does not apply to objects managing heap allocations.) – Joshua Feb 19 '21 at 19:31
  • When an automatic variable is destroyed and no longer visible is well defined, when it goes out of scope, but when the memory used by the variable is reclaimed... Now that's a fuzzy one. Many modern compilers do what Joshua suggests, They allocate for the worst-case automatic storage consumption at the beginning of the function and release it at the end. This is easier and often a wee bit faster although it can chew up more memory. – user4581301 Feb 19 '21 at 19:44
  • @user4581301 But the whole point of the time I spent adding `{}` was to manually free up stack memory :( –  Feb 20 '21 at 01:24
  • There may be a compiler option to change behaviours, but if you're worried about aa few bytes, ferget it. Not worth the time. If you have a big-ass array, Might be worth it. Note that if you decide to put the big-ass array and its users into a function, the compiler may still pull a fast one and optimize for speed. – user4581301 Feb 22 '21 at 18:14
1

The C89/ANSI standard requires all variables be declared at the top of a scope block. This was required because old C compilers were single pass compilers meaning they parsed, type checked, and emitted machine code during their one and only pass over the program. Since machine code is emitted as it's parsed, the amount of stack space to reserve for a given scope block needs to be known when it's encountered which is why old standards mandated that variables be declared at the top.

Newer C compilers are multi-pass compilers meaning they make multiple passes over the program. Because of this, it's no longer necessary to know how much stack space to reserve on the initial pass.

Embedded systems often use a C compiler adhering to the older C89/ANSI standard. Your teacher is likely encouraging you to declare variables at the top so you never have to think twice about it. They may give a more thorough explanation, as I have done, as the class progresses.

hgs3
  • 525
  • 3
  • 6
  • If the compiler can handle a variable declaration inside an `if` block it's back-propagating the stack frame size. – Joshua Feb 19 '21 at 19:33