views:

181

answers:

4

When I was first introduced to C I was told to always declare my variables at the top of the function. Now that I have a strong grasp of the language I am focusing my efforts on coding style, particularly limiting the scope of my variables. I have read this SO question on the benefits to limiting the scope and I came across an interesting example. Apparently, C99 allows you to do this...

for (int i = 0; i < 10; i++)
{
   puts("hello");
}

I had thought that a variables scope was limited by the inner-most surrounding curly braces { }, but in the above example int i appears to be limited in scope by the curly braces of the for-loop even though it is declared outside of them.

I tried to extend the above example with fgets() to do what I thought was something similar but both of these gave me a syntax error.

fgets(char fpath[80], 80, stdin); See Note*

fgets(char* fpath = malloc(80), 80, stdin);

So, just where exactly is it legal to declare variables in C99? Was the for-loop example an exception to the rule? Does this apply to while and do while loops as well?

Note*: I'm not even sure this would be syntactically correct even if I could declare the char array there since fgets() is looking for pointer to char not pointer to array 80 of char. This is why I tried the malloc() version.

+11  A: 

In C99, you can declare your variables where you need them, just like C++ allows you to do that.

void somefunc(char *arg)
{
    char *ptr = "xyz";
    if (strcmp(arg, ptr) == 0)
    {
        int abc = 0;    /* Always could declare variables at a block start */

        somefunc(arg, &ptr, &abc);

        int def = another_func(abc, arg);   /* New in C99 */
        ...other code using def, presumably...
    }
}
  • You can declare a variable in the control part of a 'for' loop:

    for (int x = 0; x < 10; x++)    /* New in C99 */
    
  • You cannot declare a variable in the control part of a 'while' loop or an 'if' statement.

  • You cannot declare a variable in a function call.
  • Obviously, you can (and always could) declare variables in the block after any loop or an 'if' statement.

The C99 standard says:

6.8.5.3 The for statement

The statement

for ( clause-1 ; expression-2 ; expression-3 ) statement

behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any variables it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.

Jonathan Leffler
Thank you for the detailed comment and referencing the standard
SiegeX
+5  A: 

The first thing I'd note is that you shouldn't confuse

for (int i = 0; i < 10; i++) {
    puts("hello");
}

and

fgets(char* fpath = malloc(80), 80, stdin);

The first is a control structure while the second is a function call. The control structure evaluates the text inside it's parens() in a very different way from how a function call does.

The second thing is... I don't understand what you're trying to say by:

the compiler will promptly give you an error if you try to use i inside the for-loop body.

The code you listed for the for loop is a very common structure in C and the variable "i" should, indeed, be available inside the for loop body. Ie, the following should work:

int n = 0;
for (int i = 0; i < 10; i++) {
    n += i;
}

Am I misreading what you're saying?

RHSeeger
No, you weren't misreading but apparently I read some incorrect info on the SO link I posted in my question which said it wouldn't compile. Apparently, the more correct statement should have been it would fail to compile without passing -std=c99 to `gcc`. Could you provide a bit more insight on the evaluation of text within a control structure vs a function call as I think this is definitely the root of what my question was trying to get at.
SiegeX
A: 

Opinion is divided, as it usually is...

I work with VB more than anything else, and in good ol' honest VB6, it doesn't really matter if you declare your variable at the top of the function or in the middle of it - just so long as it's declared before you use it, all will be well.

Many places, including the firm I work for, therefore have coding standards requiring all variable declaration in a nice big block at the top of the function - which in VB6 makes as much sense as anything else - we can use the tools (Cntrl I) in the IDE to rapidly determine if a variable is local or not, and it's type.

However, C, C# and VB.Net have scoping at finer granularity than merely the method level - in that now variables actually scope to the block of code in which their declaration is contained. For instance, this compiles:

Sub Main()
        Console.WriteLine("Hello World!")

        ' TODO: Implement Functionality Here
        If True Then
            dim myVariable as String = "Hello"

        End If

        If True Then
            dim myVariable as Integer = 123

        End If
        Console.Write("Press any key to continue . . . ")
        Console.ReadKey(True)

End Sub

That means you can use the same identifier for two totally different variables, which is all fine and dandy but not something I would recommend in practice. However, it also means that if you're just using a local variable within a particular block of code, you can declare it there and know for certain that it's free from interference anywhere else in the code. That's a nice little safety catch - and one my firm have yet to pick up on...

Now, you personally work in C, so since you probably lack a really nice IDE, I would suggest you keep the declarations close to where they are used, as JonH has already said...

Martin Milan
Martin Milan
The question wasn't about people's preferences or best practices, but about language syntax (C, not VB6)
qrdl
You clearly missed "Now that I have a strong grasp of the language I am focusing my efforts on coding style" then...My comments were relevant. The example I gave was in VB.Net, yes... However I qualified this with the statement that C and C# offered the same ability.Now, reading on, fine - don't up vote me - but I think -2 is a bit harsh. Still, I'm not going to lose sleep over it. Peace!
Martin Milan
+1  A: 

The bottom line with respect to your for/fgets confusion is that while "enclosing braces control scope" is the correct rule in C most of the time, there is another rule regarding scope in C99 (borrowed from C++) that says that a variable declared in the prologue of a control structure (i.e. for, while, if) is in scope in the body of the structure (and is not in scope outside the body).

Tyler McHenry
apparently this only works with `for` loops but +1 for the answer.
SiegeX
Oops. It works for `if` and `while` in C++, so I guess I assumed that C99 would have borrowed the whole thing, not just the `for` part.
Tyler McHenry