2
  1. The advantage of approach 1 is a slightly smaller file size due to less text characters in the source code:

    int i, j;
    for (i = 0; i < numRows; i++)
        for (j = 0; j < numCols; j++)
        //<some code here>
    
  2. The advantage of approach 2 is the smaller scope of local variables.

    int i;
    for (i = 0; i < numRows; i++)
    {
        int j;
        for (j = 0; j < numCols; j++)
        //<some code here>
    }
    

Even if the differences in optimizations are negligible in today's modern computers, which approach is considered "better" code?


Edit to clarify that this question is not a duplicate:

This question is based on the current C11 standard, which does not allow for syntax like this:

for (int i = 0; i < numRows; i++)

In C++ and C99, this syntax is perfectly acceptable whereas C11 does not allow for variable declarations inside the for statement.


Edit to correct misinformation:

I thought I was using C11 because I had recently downloaded the compiler from CodeBlocks, so that's why I said C11 didn't allow for variable declarations inside the for statement. But it turns out I was actually using C90, which was the root of my problems.

FriskySaga
  • 409
  • 1
  • 8
  • 19
  • I believe the compilations will be equivalent, meaning it's probably better to use the second, since it will prevent you from accidentally using j in the place of i in the outer loop. I'm not going to post this as an answer though, since somebody more experienced with C will have a better answer. – Matt Goodrich Feb 18 '17 at 04:53
  • see this- http://stackoverflow.com/questions/7959573/declaring-variables-inside-loops-good-practice-or-bad-practice-2-parter – danishansari Feb 18 '17 at 05:07
  • 1
    Possible duplicate of [Declaring variables inside loops, good practice or bad practice? (2 parter)](http://stackoverflow.com/questions/7959573/declaring-variables-inside-loops-good-practice-or-bad-practice-2-parter) – tod Feb 18 '17 at 05:29
  • 1
    @tod: Your suggested duplicate is not a bad answer – except that is tagged [tag:c++] and not [tag:c]. That makes it less than 100% desirable as a duplicate for a C question. The information is mostly still valid — though it is surprising that there isn't a discussion of the constructors and destructors being invoked for the `string` defined inside the loop. – Jonathan Leffler Feb 18 '17 at 05:42
  • It depends — it depends on whether you need to access the value of `i` (or, less plausibly, `j`) outside the loop. Suppose you have `int i; for (i = 0; i < 10; i++) { double val; if (read_value(&val) == EOF) break; /* use val */ }` then you can find out how many values were actually read after the loop by inspecting `i`. If you use a 'loop scope' variable, you can't do that — you'd have to create another variable and assign to it, or something. If you don't need the variable outside the loop, use the loop-scoped notation: `for (int i = 0; i < 10; i++) { … }`. – Jonathan Leffler Feb 18 '17 at 05:47
  • @JonathanLeffler The loop-scooped notation will not be accepted by a compiler built on C11. That's also why I don't believe this question is a duplicate question because C++ syntax is different. – FriskySaga Feb 18 '17 at 18:35
  • 1
    @FridaySky: waddya mean? Those have been in C since C99! – Jonathan Leffler Feb 18 '17 at 18:36
  • @JonathanLeffler If I compile code with the loop-scoped notation, an error will show up saying: 'for' loop initial declarations are only allowed in C99 mode. – FriskySaga Feb 18 '17 at 18:43
  • @FridaySky-- check the citation that I added in a comment under my answer. Loop-scoped variables are in the Standard. What compiler and what invocation are you using? – ad absurdum Feb 18 '17 at 18:44
  • @DavidBowling I'm not sure if this answers your question, but I'm using "gcc -o" to compile my programs through the Windows command prompt. – FriskySaga Feb 18 '17 at 18:49
  • I would guess that you are actually compiling in C90 mode. Try compiling with `gcc -std=c99 ...` or `gcc -std=c11 ...` – ad absurdum Feb 18 '17 at 18:51
  • 1
    @FridaySky: if that's a GCC version 4.x, then it defaults to `-std=gnu90` mode, meaning GNU extensions to the C90 standard. If you use version 5.x or later, it defaults to `-std=gnu11`, meaning GNU extensions to the C11 standard. I'd hazard a guess you're using GCC 4.x which might well produce that message. Add `-std=c11` or `-std=gnu11` (or `-std=c99` or `-std=gnu99`) and they'll compile just fine. The C90 standard hasn't been current for 17+ years. – Jonathan Leffler Feb 18 '17 at 18:52
  • @JonathanLeffler-- couldn't remember if that default was C89 or C90! – ad absurdum Feb 18 '17 at 18:53
  • @DavidBowling: they're synonyms (that is, `-std=c89` and `-std=c90` both work and mean the same thing; also `-ansi` means this standard too). C89 was the original ANSI standard. C90 was ratified by ISO, and then accepted by ANSI as a replacement for the ANSI standard. The technical content was unchanged except for the section numbering; there were slight differences in the covers and preamble. – Jonathan Leffler Feb 18 '17 at 18:54
  • @DavidBowling For some reason, I get an error saying: "No such file or directory". To be specific, I'm typing `gcc -std=c99 DummyVariables DummyVariables.c`. I downloaded my GCC compiler through CodeBlocks about a year ago. I assumed I was using C11 since that's the most recent standard, but you could be right. How do I check if I'm using C89? – FriskySaga Feb 18 '17 at 18:58
  • 1
    The argument `DummyVariables` is naming a file that doesn't exist. Did you miss out `-o` before it? You can check the GCC version with `gcc --version`. You can find out what it's really doing by running `gcc -v …` to be verbose. The output should include the version information, IIRC. – Jonathan Leffler Feb 18 '17 at 18:58
  • @JonathanLeffler Yeah, you're right. If I remove `DummyVariables`, it compiles fine. – FriskySaga Feb 18 '17 at 19:01
  • You can type `gcc --version` to find out what version of gcc you have. Then consult the documentation to see what it says about defaults for your version. [Here is a link](http://stackoverflow.com/questions/7458340/how-to-find-out-which-ansi-c-standard-my-gcc-works-with-by-default) to a SO question that discusses this. – ad absurdum Feb 18 '17 at 19:05
  • To wrap it up, you guys were right about the loop-scoped variable declarations all along! I just couldn't get mine to compile because I didn't realize I was using a much older version of C. Actually, I was using gcc 4.7.1. Sorry for the troubles, everyone. – FriskySaga Feb 18 '17 at 19:05

4 Answers4

5

For sheer compactness and limiting of scope, I would use:

for (size_t i = 0; i < numRows; i++) {
    for (size_t j = 0; j < numCols; j++) {
    //<some code here>
    }
}

Note the use of size_t for what appear to be array indices. The size_t type is an unsigned integer type guaranteed to be able to hold any array index. Just a matter of style, but I would also suggest using braces around all loop bodies. This makes it much less likely that you will break your code with inevitable updates and changes.

By making it a habit to declare loop variables with block scope like this, you force yourself to choose to use the values stored in loop variables elsewhere in your code.

ad absurdum
  • 19,498
  • 5
  • 37
  • 60
  • Hi, David. Thank you for your reply. But as I mentioned in another comment to Peter's answer, I am concerned about the variable declarations inside the for statements. While C99 does allow your syntax, from what I've read C11 does not allow for variables to be declared inside the for-loop parentheses. – FriskySaga Feb 18 '17 at 18:32
  • @FridaySky-- C11 does allow it. Where have you read this? [From the C11 Draft Standard](http://port70.net/~nsz/c/c11/n1570.html#6.8.5.3): "If clause-1 is a declaration, the scope of any identifiers it declares is the remainder of the declaration and the entire loop, including the other two expressions...." – ad absurdum Feb 18 '17 at 18:36
  • @FridaySky-- use of loop-scoped variables in C (when it makes sense) is considered a best practice by many, possibly even most, professional programmers. – ad absurdum Feb 18 '17 at 18:41
  • Actually, I didn't read it from anywhere. I read that C99 was an older standard of C, and I also read the comments that were saying that loop-scoped variable declarations worked for C99, so I **assumed** that loop-scoped variable declarations would not work for C11, because it didn't work for me. – FriskySaga Feb 18 '17 at 19:11
1

This seems be a question of taste rather than having any definite answers, but I'll give you my opinion:

Given current computers, saving a couple of characters of source code is too trivial to even think about. In fact, I think I would have said that even when I was learning C on a VAX 11/780 in 1976.

I would favor the second example, because the current preference is to declare variable as close to the first use as possible. In C++ you could even put the declarations of the loop variables inside the for statements:

for (int i = 0; i < numRows; i++) {
   for (int j = 0; j < numCols; j++) {
      ...
   }
}

But that's still just a matter of taste: the belief that the program will be more readable if the declaration of a variable is close to its use.

A. P. Damien
  • 376
  • 2
  • 10
  • 2
    C99 allows `for (int i = ...`. No need for C++ – rici Feb 18 '17 at 05:40
  • THanks. I tried looking for the ANSI C spec, but I got the 1988 version. Anyway, that spec is written for compiler writers, not for users. Hoping to someday find the ANSI C equivalent of the Harbison & Steele book, "C: A Reference Manual". (Also for the C++ version.) – A. P. Damien Feb 18 '17 at 06:01
1

Neither approach is preferred.

Two common coding guidelines are (1) to ensure that no variable exists any longer than it needs to and (2) don't use a variable for more than one thing. Following such guidelines reduces (often, but not always, eliminates) accidental usage of a variable in a way that is not intended, and therefore helps avoid subtle programming errors.

In your first case, both i and j continue to exist until the end of the enclosing scope - which means they exist after the loops are complete. This maximises the chances of subsequent code (in that enclosing scope) accidentally reusing i or j for another purpose (e.g. when the intent is to use another variable). Such bugs are often hard to find.

The second case has the same problem, except with i only. Even one variable with such a problem is bad news though.

I'd probably use a construct like

// unintentionally using i or j here will cause a compilation error

for (int i = 0; i < numRows; i++)
{
    // unintentionally using j here will cause a compilation error

    for (int j = 0; j < numCols; j++)
    {
       //<some code here>
    }

    // unintentionally using j here will cause a compilation error
}

// unintentionally using i or j here will cause a compilation error

(The comments I've inserted to make the point make this more unreadable, but such comments will not normally be needed in practice).

This ensures that neither i not j exist outside the outer loop. It also means that j cannot be accidentally used in the outer loop. Practically, it is easy to type i when j is intended (and vice versa) - for example, they are close together on a QWERTY keyboard. i and j also look quite similar visually, so visual code inspections often miss such errors. However, using an approach like this, the COMPILER will detect such typos. Given a choice, it is better to have a compiler pick up errors rather than for a human to have trouble finding them.

Of course, this doesn't prevent misuse or interchange of i and j in the inner loop - but that's one reason that guidelines often encourage use of more informative names than i and j - misuse of visually different names is easier for a mere mortal to detect.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • Hi, Peter. Thank you for your reply. My concern with your construct is that some C compilers do not allow variable declarations inside the parentheses of the for-loop. However, for other languages like Java, your construct would be very ideal. – FriskySaga Feb 18 '17 at 18:19
  • Don't worry about my previous comment. It turns out I was using a compiler as old as C90 even though I had only installed the compiler only about a year ago. – FriskySaga Feb 18 '17 at 19:08
-1

The second method is the best method as

  1. It can use low memory
  2. Allows usage of same variable again if required in any other loop
ashokrajkp
  • 19
  • 2
  • 1
    Will it really use less memory? My understand is that most compilers move the variable inside the loop automatically. – Matt Goodrich Feb 18 '17 at 04:56