3

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]);
    }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • `Why can't we use 'i=0;' here as done in the previous code? ` - there is `int i = 0` in both code snippets you attached. How would you want to use `i = 0`? `i=0 is not declared` - No, it's still declared. – KamilCuk Dec 29 '19 at 11:32
  • 1
    You can declare more than one variable. Both code samples here are fine. – interjay Dec 29 '19 at 11:36
  • @KamilCuk In the first code, we used i=0; but in the second one we used i=0, as here we used a comma and didn't declare it. When I try to use "i=0;" in the second code, a error pops up saying --use of undeclared identifier 'n'-- even though I used "n=strlen(s);" –  Dec 29 '19 at 11:41
  • @interjay Yes both are fine but my question is why can't we use "i=0;" in the second one. –  Dec 29 '19 at 11:42
  • 2
    No, with a comma it's still a declaration. `int i = 0, n = strlen(s);` and `int i = 0;` both declare a variable `i` and initialize it to `0`. – KamilCuk Dec 29 '19 at 11:42
  • 1
    @animesh There really isn't any reason to think that your preferred version is 'more efficient'. To you, it looks like a more efficient use of space, but it is very difficult to guess, especially without a lot of experience, what the compiler will turn that into. And it is best to avoid making a habit of such thinking because code should be readable to humans first and foremost. – dandan78 Dec 29 '19 at 11:42
  • 1
    @KamilCuk so I can put multiple variables seperated by a comma but the last one has to be with a semicolon ? –  Dec 29 '19 at 11:44
  • 1
    Because `;` separates the 3 clauses of the `for` loop, so you can't use it between declarations. – interjay Dec 29 '19 at 11:44
  • The `;` separates like "sentences". You can do use a comma to separate multiple variable declaration. The `int a = 1, b, c, d, e = a, f = 1 + 5;` is "equivalent" to `int a = 1; int b; int c; int d; int e = a; int f = 1 + 5;` – KamilCuk Dec 29 '19 at 11:45
  • @dandan78 it's less efficient as the compiler has to check the string after printing each letter but when I used n=strlen. It makes the compiler more efficient as it rather than checking again and again, the value is stored in n. –  Dec 29 '19 at 11:47
  • Actually, I've just noticed that I *can* do this! For years, my MSVC compiler complained - maybe they finally updated the base `C` standard? OP- What compiler are you using? – Adrian Mole Dec 29 '19 at 11:47
  • 1
    @AdrianMole Using the sandbox cs50 compiler. It displays a error message-- use of undeclared identifier 'n'--. It uses the C99 version, maybe the newer version is better. –  Dec 29 '19 at 11:51
  • @AnimeshSingh The compiler isn't dumb. It is perfectly capable of figuring out that the value you are checking against is a constant, especially if the cstring isn't changing in the loop itself... like I said, don't make assumptions based on inadequate knowledge. And even if your assumption were valid, there is nothing preventing you from making the assignment on the line right before your `for` loop. – dandan78 Dec 29 '19 at 11:54
  • @dandan78 They told it was a good practice in the course. I don't really know anything beyond it –  Dec 29 '19 at 11:57
  • 1
    OT: It should be `size_t i = 0, n = strlen(s);` as `strlen()` returns `size_t` not `int`. – alk Dec 29 '19 at 12:13
  • 1
    "They told it was a good practice in the course" --> All courses consider what they suggest is _good practice_ - even when it is not. – chux - Reinstate Monica Dec 29 '19 at 12:52

2 Answers2

3

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.

Emil Vatai
  • 2,298
  • 1
  • 18
  • 16
  • So a comma is used when declaring multiple variables and the last one has the be end with a semicolon. The cs50.h is a header file of a sandbox cs50 made by harvard. It does not really affect anything in for loop. Anyways I got my answer. Thanks –  Dec 29 '19 at 11:53
  • Adrian Mole where? in the `for` or in the `while`? I think this sort of works! I've tried something else (I will update the answer in a sec), since you might not need it if it is a single statement. – Emil Vatai Dec 29 '19 at 11:54
  • Animesh Singh basically yes. So your smallest "unit" in your program is a statement, which has to be separated by putting a semicolon at the end. But one declaration statement can have multiple variables declared, and they are separated by commas (and one statement separation semicolon at the end). – Emil Vatai Dec 29 '19 at 11:56
  • 1
    @Emil I would suggest adding `{ DDD; }` in your `while` example. Because user could declare an `int d` in the loop's body, but this will *not* be accessible in the `for` loop's `CCC` clause. – Adrian Mole Dec 29 '19 at 12:00
  • Was concentrating on the whole answer... but you are right I guess. Will update accordingly. – Emil Vatai Dec 29 '19 at 12:11
  • @chux-ReinstateMonica You mean a `continue` instead of a break? Or am I missing something? – Emil Vatai Dec 29 '19 at 12:50
  • @EmilVatai For future reference, the proper response to a question you don't understand correctly is either to vote to close as unclear, or to leave a comment to that effect or both. An answer that includes a disclaimer is not a good choice. – dandan78 Dec 29 '19 at 12:51
  • EmilVatai : removing my previous comment. Yes a `continue` is not quite the same. – chux - Reinstate Monica Dec 29 '19 at 12:56
  • @dandan78 I disagree. I can remove the disclaimer (as you call it) about _my uncertainty_ since I agree that it is irrelevant to the answer. I think I can never or very rarely understand 100% what another soul thinks, I never considered the question to be unclear (OP certainly put effort into it), hence not voting to close it. And the answer I gave would not have fit into a comment and I think/hope OP benefited from the answer since OP stated to be a novice. But thank you for the reminder. – Emil Vatai Dec 29 '19 at 14:14
  • @EmilVatai Helping the OP is secondary to creating resources for future visitors. I didn't mean posting your answer as a comment, but requesting clarification. Whether or not OP is a novice is also irrelevant, as _all_ posters should be held to the same standards. – dandan78 Dec 29 '19 at 17:02
3

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.

Frankie_C
  • 4,764
  • 1
  • 13
  • 30