Reputation:
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
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
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