Scope of variables in "for" loop - c

What I have known so far is, multiple declarations inside a block produce an error message and also uninitialized local variable gives garbage value on printing.
But coming across an example of for loop in C has shaken my concept on the scope of variables.
Below is the code for the same:
#include<stdio.h>
int main()
{
int i;
for(int i = 5; i > 0 ; i--){
int i;
printf("%d ", i);
}
}
The above code produces the output
0 0 0 0 0
I have two questions
A for loop is considered as one block then how two different memories are allocated for two declarations of same variable i? And if the first line of for loop and its body are considered as two blocks, then how to identify different block?
Inside the body of the loop, the variable i is uninitialized, then how is it taking the value as 0, as it should be having garbage value?
Please, explain this.

The scope of a variable declared in the first part of the for loop is all three parts of the for plus the loop body. In your case the body of the loop is a compound statement, and you declare another variable named i in that block, so it masks the i declared in the for.
So in your piece of code there are three relevant scopes:
The body of the main function
The three parts of the for loop.
The body of the for loop.
And each of them is "internal" to the other, so a variable declared at one of these scopes masks a variable of the same name in a higher scope.
To further illustrate this, if we modify your code as follows:
int main()
{
int i = 9;
printf("outer i: %d\n", i);
for(int i = 5;i>0;printf("middle i:%d\n", i),i--){
int i = 7;
printf("inner i: %d\n",i);
}
printf("outer i: %d\n", i);
}
The output is:
outer i: 9
inner i: 7
middle i:5
inner i: 7
middle i:4
inner i: 7
middle i:3
inner i: 7
middle i:2
inner i: 7
middle i:1
outer i: 9
As for why your code is printing 0 inside of the loop, an uninitialized variable may have any value, including 0. So just because it's printing 0 doesn't mean it's not garbage.

A block is anything in curly braces. A block doesn't have to follow a for do, while, if, etc. Literally any set of statements can be enclosed in their own block scope using curly braces.
The i in the for loop is not in the loop body scope since it is outside the curly braces. The i in the block is indeed uninitialized and contains garbage. Garbage usually just means "whatever was there before". As often as not, that value will be zero. That doesn't make it any less garbage.

Related

error: use of undeclared identifier 'finalTotal'

When I compile this simple code the output is the above error.
So how to declare finalTotal outside while loop?
while (total<endn)
{
int finalTotal = (total + total/3 - total/4);
}
printf("no of years is %i\n", finalTotal)
NOTE:total and endn are part of the total code but not necessary for the question.
You can simply move the declaration of finalTotal as an int to before the loop.
int finalTotal = 0; // declare and initialize to 0 in case while loop does not run
while (total<endn)
{
finalTotal = (total + total/3 - total/4);
}
printf("no of years is %i\n", finalTotal)
This does look like an infinite loop though, as neither total nor endn seems to change.
You need to read up on scope. Variables can only be accessed within their scope. Since you declare int finalTotal inside of the while loop, only other statements inside of the while loop can access it.
Instead you need to declare your variable in the outer scope, so that the following printf can access it.
For example:
int finalTotal; // Declared outside of the while loop.
// You may want to consider initializing it
// with some value in case the while-loop
// never executes. (Such as -1 or something
// to signal an invalid number of years).
while (total<endn) // NOTE: This may infinite loop. Perhaps a typo?
{
// This scope has access to `finalTotal` since it was declared
// by an outer scope.
finalTotal = (total + total/3 - total/4);
}
// Now `finalTotal` can be accessed here, since it's within the same
// level of scope and not stuck inside the scope of the while-loop
// curly braces.
printf("no of years is %i\n", finalTotal)
As mentioned by others, another problem is that the while loop may never terminate since total and endn are not changing inside of the while loop. So it will potentially iterate forever.
Perhaps this was intended to be while (finalTotal < endn).

For loop with ; in C [duplicate]

This question already has answers here:
For Loops and stopping conditions
(4 answers)
Closed 2 years ago.
While studying for my exam I saw a question which is as shown below can someone please explain to me that does the ';' means at the end of the for loop and can I also put it in a while loop? And what is the difference between the Compile-time error and the Compilation error?
#include <stdio.h>
int main(){
int value;
for ( value = 1; value <= 15; value+=3);{
printf("%d", value);
}
return 0;
}
This is probably a mistake; it is syntactically correct, but actually would be read by the compiler like this:
for (value = 1; value <= 15; value+=3);
// Unrelated block!
{
printf("%d", value);
}
This means that the loop will execute, then run four more times, but not actually do anything, then the block will execute once.
Where the loop and the block following it are completely separate and unrelated.
The semicolon ; terminates the definition of the loop body. In this case there are no statements in the body of the loop, hence the only affect of the loop is to modify the value of the counter variable, value.
The statement following the semicolon has it's own scope thanks to the curly braces, but it has no real affect in this case.
The printed result will be the value of value after the (empty) loop has executed, i.e. 16.
You could not do the same with a while loop because the variable would need to be incremented within the body of the loop and the value tested at each iteration to decide whether to continue looping.
Of course, you could avoid any loop by initialising value to 16.

I have trouble understanding about blocks of for loop and if statement

In C Primer Plus, the author says that
A C99 feature, mentioned earlier, is that statements that are part of
a loop or if statement qualify as a block even if braces (that is, { }
) aren’t used. More completely, an entire loop is a sub-block to the
block containing it, and the loop body is a sub-block to the entire
loop block.
I guess the loop body means the printf(...) statement in the example below. But what do these these two bold words mean? : ".. an entire loop is a sub-block to the block containing it,..." It would be nice if you could explain it using the example below!
for(int n =1;n<3;n++)
printf("%d \n",n);
It is phrased a bit badly, but it's quite simple:
for(int n =1;n<3;n++) // <-- loop
printf("%d \n",n); // <-- block
The loop body is as you said the printf() in this case, and in general, trying to keep my answer as minimum as possible, this is the format:
for(...; ....;)
body_of_loop
The sub comes into play when you have nested loops, or if statements. For example, a double for loop:
1. for(int i = 0; i < 10; ++i)
2. for(int j = 0; j < 10; ++j)
3. printf("hi\n");
More completely, an entire loop is a sub-block to the block containing it, and the loop body is a sub-block to the entire loop block.
So, line 2 is an entire loop and it's a sub-block to the block that it is part of. The block of the exterior for loop is lines 2 and 3.
If you have a code block, for example:
while(1) <-- code block (contains if [that contains printf])
if(2) <-- sub block (contains printf)
printf("3"); <--- part of if block
the printf is considered to be a part of the if block, and the if block itself (now containing the printf as well) is considered a part of the bigger while block. This could go on and on...
while(1)
while(2)
if(3)
for(;;)
i++;
Each of the 3 mid-lines here is a sub block that contains following lines
The C11 standard says, in §6.8.5 Iteration statements
¶5 An iteration statement is a block whose scope is a strict subset of the scope of its
enclosing block. The loop body is also a block whose scope is a strict subset of the scope
of the iteration statement.
I think this is what the statement you quote is attempting to paraphrase.
What this is driving at, somewhat opaquely (welcome to the world of reading standards), is that an iteration statement (while loop, do … while loop or for loop) is treated as a block. This primarily affects the for loop with variable declarations.
Consider:
for (int i = 0; i < max; i++)
printf(" %d", i);
putchar('\n');
The wording means that the code functions as if you had:
{
for (int i = 0; i < max; i++)
{
printf(" %d", i);
}
}
putchar('\n');
This particularly limits the scope of i to the for loop; it is not accessible outside the loop. The loop body being a block whose scope is a strict subset of the iteration statement isn't a big surprise. The surrounding block is less obvious and could be a surprise.

using statement bodies in printf in C

I am taking a course where we were doing a lot with systems level programming, and now we are getting to the point where we are starting the introduction to C. We are given some code and told to state the values printed out by each 'printf' statement. I know how to do regular printing statements in languages like Java and Python. But the code given has bodies to the print sections which I have not seen before. The statements are executed in the order A, B, C, D. Here is the code:
int t; /* This variable is global */
{
int t = 2;
printf("%d\n", t); /* A */
{
printf("%d\n", t); /* B */
t = 3;
}
printf("%d\n", t); /* C */
}
{
printf("%d\n", t); /* D */
}
The part that confuses me is that some of the print statements have bodies. A print statement inside a print statement?
So here is what I am thinking: t = 2 so when we get to A, it executes the body within A first. So the first statement in that body is to print t which at this point is 2. Then after we print 2, we change the value in t to 3. After that we go to C which just prints t which is 3 (I guess? I'm not sure here). After that we go to the body that contains D. Int t is a global variable declared above, but it is never initialized (except in the first portion of code). So in the second portion that contains D, would there be an error since t is not initialized in that block of code?
2
3
3
Error
I feel like I am wrong.
First, you have a global variable t, which is initialized to 0 (AFAIK, all global variables in C are initialized to 0 if not explicity initialized)
Then, a block is opened and a local variable t is declared and initialized to 2, which shadows the global variable with the same name (in java this is an error, the compiler will complain and refuse to use the same name), for the whole block.
The first printf, which is inside the block, prints 2.
Then a nested block opens, with a printf in it. This printf will also use the local variable t, printing 2 again.
Then t is assigned 3. This "t" cannot be other than the local variable.
Then, the nested block closes and we are back into the first still opened block in which local t was declared. The printf here prints 3.
Then the first block finishes and so the local variable t is gone. A new block opens and the last printf prints the value of global variable t, which is the only one known in this block. It prints 0.
The curly braces begin and end new scopes, just like they do with functions.
There are two "main blocks" in your program. One contains a definition of variable t, thus shadowing the global t. Therefore 2, 2, and 3 is printed out. The second block can access the global t, so the printf in the second block prints out the value of the global t.
Global variables are initialized to 0 by default, so the last printf call prints 0 to the screen.
Local variables are not initialized with any value, so the last printf call would yield undefined behavior.
The output is
2
2
3
and after that
0
if the "global" t really is global or (probably1) some random value if it is local.
1 Undefined behavior occurs. Anything may happen. In this case, it's probably a random value getting printed out.

Explain the output of the given code

In the below code, variable i has been declared globally as well as locally in the for loop . Due to high precedence of local variable, i will be initialized with the value 10 . But in the first occurrence of the loop, due to i++in the for loop, value of i will become 11, so should it not exit the loop after the first instance only?
#include<stdio.h>
int main(){
int i;
for(i=0;i<5;i++){
int i=10;
printf(" %d",i);
i++;
}
return 0;
}
P.S: The answer is 10 10 10 10 10
Precedence is not just about initialization. The variable i inside the loop body is a different variable from the one outside. It "shadows" the outer i, making it inaccessible in the loop body.
The loop control statement is outside the loop body. Its i is the outer i, and nothing done to the inner i has any effect on it, so it starts at 0 and counts up to 5. At each loop iteration, the inner i is re-initialized to 10, and that's the one that gets printed.
The reason it always prints is because the inner i shadows the outer i. For the same reason the i++; inside the loop increments the inner i, not the i that's used as the for loop counter.
But the i that controls the loop gets incremented after the scope of the inner i is over and has no relation to i++; done inside the loop. It's completely independent of the inner i and thus the loop runs 5 times.
GCC provides an option to warn about such shadowing: -Wshadow.
Yet another answer because there is one aspect missing so far. If you change your code slightly:
#include<stdio.h>
int main(){
int i;
for(i=0;i<5;i++){
static int i=10;
printf(" %d",i);
i++;
}
return 0;
}
You will get a more "expected" result:
10 11 12 13 14
A variable inside a block stops to exist after the block (read: pair of curly braces) is left (and it is left here after every step to execute the control statements of for) ... so with your original code, you get a new inner i each time. Declaring the inner i static still doesn't change the scope (it is only visible inside the loop body), but makes the variable survive and still be available when the same block is entered again.
Yes the answer is correct.
As loop iterates 5 times and for every iteration i inside loop is set to 10 and outer one is overshadowed by inner one. After i=10 its value is printed therefore 5 times 10 is output.

Resources