user12027492
user12027492

Reputation:

Why can't I declare more than one variable in a for loop's initial statement?

When using a with one variable, we declare it to 0 as i=0 like here

but when we use two variables as if I add n = strlen to make the code more efficient then i=0 is not declared but a comma is used and n=strlen(s) is declared. Why can't we use 'i=0;' here as done in the previous code?

Edit: The cs50.h is part of the sandbox cs50 which is made by harvard.

#include <stdio.h>
#include <string.h>

int main(void)
{
    string s = get_string("Input:  ");
    printf("Output: ");
    for (int i = 0; i < strlen(s); i++)
    {
        printf("%c\n", s[i]);
    }
}
#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    string s = get_string("Input: ");
    printf("Output:\n");
    for (int i = 0, n = strlen(s); i < n; i++)
    {
        printf("%c\n", s[i]);
    }
}

Upvotes: 3

Views: 223

Answers (2)

Frankie_C
Frankie_C

Reputation: 4877

From C standard ISO/IEC 9899:TC3 / ISO/IEC 9899/C11, the grammar description of the for statement, §(6.8.5) iteration-statement, have 2 different forms:

for ( expression_opt ; expression_opt ; expression_opt ) statement

for (declaration expression_opt ; expression_opt ) statement

Note that in the first form we have an expression in the first position, although it is optional as all 3 fields, and all the 3 parts of the statement form are separated by a ; semicolon used as a delimiter.

In the second form we can see that the first element in parenthesis is a declaration instead of an expression, and we can note also that there is no semicolon delimiting it. This is because the declaration itself is always terminated by a semicolon.

Paragraph (6.7) declaration describe grammar for a declaration:

declaration-specifiers init-declarator-list_opt ;

As you can see a declaration is always terminated by a semicolon.

A declaration can assume of course the form of multiple declarations initialized as in your:

for (int i = 0, n = strlen(s); i < n; i++)
{
    printf("%c\n", s[i]);
}

So you are using the second form where the semicolon delimits the declaration (not the first part of the for).

Using multiple semicolon is simply a grammar error.

Upvotes: 3

Emil Vatai
Emil Vatai

Reputation: 2531

Not sure if I understand the question (although I like it). Both your code snippets work, don't they? Note that we don't know what is in cs50.h, but I tried compiling this, and it worked (both compiling and running).

#include <stdio.h>
#include <string.h>

int main(void) {
  char *s = "Hello world!";
  printf("Output:\n");
  for (int i = 0, n = strlen(s); i < n; i++) {
    printf("%c\n", s[i]);
  }
}

Two things might be relevant here; - how for works and - how variable declaration/initialization works.

You can think about for like this: for(AAA; BBB; CCC) DDD; is the same as

{ // Important!
  AAA;
  while(BBB) {
    {
      DDD;
    }
    CCC;
  }
} // Important!

The // Important! braces are important because the for introduces a new scope, i.e. i and n won't accessible outside/after the for loop.

The other thing is declaration/initialization. So the

int i = 0, n = strlen(s);

is an initialization of two variables: i, n. I'm not 100% sure about the proper vocabulary and rules (you can consult the standard), but the idea is that a declaration looks like: TYPE VAR1, VAR2, ..., VARn where the VARx is a variable name declared, or an "assignment" in which case it is an initialization.

UPDATE/PART2: Usually how I would do this is something like:

const int len = strlen(s);
// Good practice to declare const what every you know wont change
for(int i = 0; i < len; i++) {
  // whatever
}

But, what if the confusing coma/semicolon could be made consistent and since the semicolon is a must let's try to make everything a semicolon, I've tried this:

for ({int i = 0; int n = strlen(s); }; i < n; i++) {
  // what ever
}

This did not compile, but it also didn't make sense, since if this would have "worked" (in the sense I thought I could but actually couldn't), i and n would be declared in the small block and it wouldn't be accessible anywhere else, i.e. in i < n would not be accessible. So to make them accessible we could try this:

int i, n;
for ({i = 0; n = strlen(s); }; i < n; i++) {
  printf("%c\n", s[i]);
}

Now this should have worked if the for-while equivalency stated above would be 100% true, but it's not since apparently the the AAA has to be a single statement (usually a declaration) and it can't be a block i.e. {...}. Exact compiler error:

cc     hola.c   -o hola
hola.c: In function ‘main’:
hola.c:8:8: error: expected expression before ‘{’ token
    8 |   for ({
      |        ^
make: *** [<builtin>: hola] Error 1

but as you can see it is already very ugly and all... so yes, you need to use , to separate the declarations/initializations and a ; to terminate it.

Upvotes: 3

Related Questions