Why does this program produce odd output when the variable is uninitialized? - c

int main() {
int j = 0;
int i = 0;
for (j = 0; j < 5; j++) {
printf("Iteration %d : %d ", j + 1, i);
int i;
printf("%d", i);
i = 5;
printf("\n");
}
}
The above code generates the following output:
Iteration 1 : 0 0
Iteration 2 : 0 5
Iteration 3 : 0 5
Iteration 4 : 0 5
Iteration 5 : 0 5
I'm not able to understand why the second printf value in iterations 2,3,4,5
is 5.
My understanding of why the first value is 0 in each iteration is that the scope of i in the for loop is local and it is destroyed as soon as we go into a new iteration as i was declared in the for loop.
But I'm not able to figure out why this value becomes 5 at the second printf.

The behaviour of your program is undefined.
The inner scope i is not initialised at the point it's read.
(What might be happening is that the reintroduced i on subsequent iterations occupies the same memory as the previous incarnation of the inner i, and the uninitialised memory on the first iteration corresponds to 0. But don't rely on that. On other occasions, the compiler might eat your cat.)

The second printf in your program is printing garbage value from uninitialized local variable i. In general case the behavior is undefined.
By accident, storage location that represents your i (memory cell or CPU register) is the same on each iteration of the cycle. By another accident, the body of your cycle is executed as a single compound statement for each iteration (as opposed to unrolling the cycle and executing all iterations at the same time in interleaved fashion). By yet another accident, the storage location of i keeps its old value from the previous iteration. So, the garbage that you are printing matches the last stored value from that location on the previous iteration of the cycle.
That's why you see 5 in local i on each iteration besides the first. On the first iteration that garbage value happened to be 0.

I think this is what is happening:
Breakpoint 1, main () at abc.c:4
4 int j = 0;
(gdb) s
5 int i = 0;
(gdb)
6 for(j=0;j<5;j++){
(gdb) p &i
$23 = (int *) 0x7fff5fbffc04 //(1) (addr = 0x7fff5fbffc04) i = 0
(gdb) p i
$24 = 0 // (2) i == 0
(gdb) s
7 printf("Iteration %d : %d ",j+1,i);
(gdb) p &i
$25 = (int *) 0x7fff5fbffc00 //(3) here compiler finds there is contention in variable 'i' and assigns the inner one which is in present scope. Now, when subroutines are called, the stack frame is populated with (arguments, return address and local variables) and this is when the inner 'i' was also got allocated in this inner loop block but not initialized yet and this is the reason i get garbage value in the first integration output.
(gdb) p i
$26 = 1606417440 // (4) Here i == 1606417440 (Garbage)
(gdb) s
9 printf("%d",i);
(gdb) s
10 i = 5;
(gdb) p &i
$27 = (int *) 0x7fff5fbffc00
(gdb) p i
$28 = 1606417440
(gdb) s
11 printf("\n");
(gdb) p &i
$29 = (int *) 0x7fff5fbffc00
(gdb) p i //(5) after executing previous statement, now i == 5
$30 = 5
(gdb)

C compilers have some latitude in how they implement things and it would not be at all unusual for the local "i" to not actually be recreated each pass of the loop. It is likely actually only being created once, and re-used on each pass. In this case, your first print is outside the scope of the local variable so uses the i from outside the loop. The second print uses the local i as it is in scope, and after the first iteration has been set to 5. On the first iteration, the correct value is undefined, not 0, but the behavior of undefined is implementation specific, in your implementation it appears to automatically be initialized to 0.

If you declare a local variable and don't give it a value before using it, if you get is undefined behavior.
C standard say,
Variables with automatic storage duration are initialized each
time their declaration-statement is executed. Variables with automatic
storage duration declared in the block are destroyed on exit from the
block.

Related

Why is the output coming as 8883. How is the code is being executed?

Variable i is becoming 8 at the first entry in loop. Then how the condition i <= 2 satisfied next time?
#include <stdio.h>
int main()
{
int i;
for (i = 0; i <= 2; i++)
{
int i = 8;
printf("%d", i);
}
printf("%d", i);
return 0;
}
It prints 8 three times from the loop with i = 0, i = 1 and i = 2.
for(i=0;i<=2;i++)
{
int i=8;
printf("%d",i);
}
The second variable i (the one declared inside the body of the loop) will not affect the first i (the one declared outside the loop), because it is declared in a different scope i.e., inside the loop.
Final the last 3 comes from because the inner most i will be increment on last time before exit the loop. So for:
printf("%d",i);
the variable i will take the value 3.
The variable i you modify inside the loop body is a different variable from the i defined before the for loop and used in the loop tests.
int i defines a new variable only accessible inside the loop body, which is a block with its own scope.
Hence the code prints 8 3 times, once for each iteration of the loop and 3 which is the value of the variable i of the main body after the loop.
Here is a modified version that will print 89 as expected:
#include <stdio.h>
int main() {
int i;
for (i = 0; i <= 2; i++) {
i = 8;
printf("%d", i);
}
printf("%d", i);
return 0;
}
It sets i to 8 and prints 8 inside the loop body for the first iteration, then i gets incremented, 9 is greater than 2 so the loop exits and 9 is printed by the final printf.
int i=8 is a declaration of a new variable (declares and initializes new variable) which is in a local scope that shadows the existing variable from the more general scope.
In other words:
First int i defines variable;
for uses that variable and initializes it with 0 and starts a cycle;
int i=8 - as it is written with int - defines new local variable that because it has the same name that i from outer scope - shadows it ("shadowing" is a term). And so further code in the loop uses new local i which set to 8.
Internal printf("%d",i); prints 8.
Cycle ends and local scope gets erased, and so that internal i=8 erased also.
for lives outside (in more general scope) of the scope of the loop. for condition uses variable from outside, which was set to i=0 in step #2. So for in a second cycle instructed to increment (i++) it, so i=1, which passes the i <= 2 check. So for indeed starts executing next cycle of internal code.
Inside for loop external i gets shadowed by internal int i=8... (step #3).
In short: It is because code declares a new variable with int i.
The good style is to:
for(int i=0;i<=2;i++) - always declare and initialize the variable in one instruction.

++i and i++ in while loop in C

I am using a program to detect the boundary of each data type, which is like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
/*first while loop using a++ dosesn't give us a right answer*/
int a = 0;
while (a++ > 0);
printf("int max first = %d\n", a-1);
/*second while loop using ++a performs well*/
int b = 0;
while (++b > 0);
printf("int max second = %d\n", b-1);
system("pause");
return 0;
}
After I compile this propram and excute it, it returns:
int max first = 0
int max second = 2147483647
So I try to debug it, and I find out that in the first part, after a++ becomes 1, then it just stop autoincrement and jump the while loop,while in second part it runs well, why is this happening?
The pre-increment operator (e.g. ++b) is done first, and the value of the expression is the incremented value.
That is
int b = 0;
while (++b > 0) ...
will increment b first and then check its value using the larger-than comparison. Since in the very first iteration ++b will make b equal to 1 the condition will be 1 > 0 which is true.
Now the post-increment operator does the increment after the old value is used.
So for example a++ will return the old value of a and then do the increment.
So with
int a = 0;
while (a++ > 0) ...
the very first iteration a++ will return 0 which means you have the condition 0 > 0 which is false and the loop will never even iterate once. But the value of a will still be incremented, so afterwards it will be equal to 1 (when the loop have already ended).
This behavior of the pre- and post-operators should be part of any decent book, tutorial or class.
after a++ becomes 1, then it just stop autoincrement and jump the
while loop
This happens because of the post and pre increment operators and the ; in while loop working together.
a will be incremented by 1 after the condition a++ > 0 is evaluated. Thus, the condition fails. The ; at the end of the while statement results in an empty loop and the next print statement will be executed even if the condition on which the while loop is based returns true.
This is exactly what happens in the second while loop - the pre increment operator will increment b before the condition is checked inside while (++b > 0);. The empty while loop keeps on adding one to the value of b until there is an overflow.
At this point, strictly speaking, you have invoked undefined behaviour because the operation has resulted in overflowing a signed integer.
Let me rewrite the main function you wrote - so that it becomes easier to understand.
int main()
{
/*first while loop*/
int a = 0;
while (a > 0){ a = a + 1; }
printf("int max first = %d\n", a-1);
/*second while loop*/
int b = 0;
b = b + 1;
while (b > 0){ b = b + 1; }
printf("int max second = %d\n", b-1);
system("pause");
return 0;
}
Some observations regarding what happened here:
Because at the beginning of the first while loop - the value of a is 0 - which is not greater than 0; the loop gets skipped at the beginning. As a result, the first printf outputs 0.
At the beginning of the second while loop, before evaluating the loop control condition; the loop control variable b gets incremented by 1, resulting the value of b becoming 1; which is greater than 0. For this reason, the second loop is executed.
While executing the second loop, the value of b keeps incrementing by 1 until the value of b overflows. At this point, the program encounters undefined behaviour - and exits the while loop if the program doesn't crash or keeps executing the loop indefinitely (in which case, at some stage the OS will terminate the program; or ask the user to terminate it - as the program will become non-responsive).
You mentioned that you wanted to measure the limit of int values; I hope this reference and this reference will help you in some way.

Why did the compiler assign different memory address to the same variable, after re-defining the variable?

The code is as follows:
#include <stdio.h>
int main()
{
int i;
printf("%p\n",&i);
for (i = 0; i < 5; i++)
{
int i = 10;
printf("%d %p\n", i,&i);
i++;
}
return 0;
}
First we defined a variable i (just after main). Then at the start of for loop we defined the same variable i again. So, inside for loop, value of i is 10. The for loop must iterate only once, since i>5 after first iteration. But to my surprise the output is as follows:
0x7ffe8b799da0
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
10 0x7ffe8b799da4
My questions are:
1) Why is the compiler considering the initial defined variable i while executing i<5;i++ instruction and, not the re-defined variable i? (after first iteration).
2) Why did compiler assign different memory address to same variable identifier i?
Why is the compiler considering the initial defined variable i while
executing i<5;i++ instruction and, not the re-defined variable i?
(after first iteration).
Because the re-defined (shadowing) variable isn't in scope yet. If you remove the first definition, you get an "identifier undeclared" error. This also doesn't change after the first iteration of the loop as it is determined at compile time.
2) Why did compiler assign different memory address to same variable
identifier i?
Even though you can't access the outer int i inside the loop as the second one shadows it, it still exists and therefore needs its own memory. It's not overwritten by the other int i. You can see that by putting a printf("%d\n", i); after the loop - it will print 5, because that's the value of that i after loop.
On another note, the i++; at the end of the loop has no effect because it affects the i inside the loop, which goes out of scope right after the i++;. This is unlike the i++; in the for (i = 0; i < 5; i++), which increases the outer i.
You've got two different variables both named i, so obviously the situation is going to be confusing! For every i in the program, we have to ask: is this the "outer" i, or the "inner" i?
Here's your program again, with the variables renamed for clarity:
#include <stdio.h>
int main()
{
int i1;
printf("%p\n",&i1);
for (i1 = 0; i1 < 5; i1++)
{
int i2 = 10;
printf("%d %p\n", i2,&i2);
i2++;
}
return 0;
}
To your specific question, the reason the loop runs 5 times is that the loop control for (i = 0; i < 5; i++) is unquestionably using the outer i.

If loop execution

In the code below,
#include<stdio.h>
int main()
{
int k,sum;
for(k=7;k>=0;sum=k--)
printf("%d \n",sum);
return 0;
}
The output is:
0
7
6
5
4
3
2
1
I want to know how this loop executes and why isn't printing 0 in the last?
On first iteration sum is uninitialized. It has indeterminate value.
C11: 6.7.9 Initialization:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.
Section 6.3.2.1 says that the behavior is undefined in this case.
In short, the sum variable is updated to be the same as k. After that update, k is decremented by 1 and then the loop runs
What that means is...
First loop, sum is uninitialised (hence the first 0)
the last time the loop runs, sum is set to k (1), k is decremented to 0. The loop runs. The condition is tested so the loop exits.
It all comes down the this: sum=k--. If you were to do sum=--k, k would be decremented before its value is assigned to sum.
Your program has undefined behaviour, since it is reading from an uninitialized variable in the first round of the loop (cf. C11 6.3.2.1/2).
Following code :
for(k =7; k >= 0; sum = k--)
//your code here printf("%d \n",sum);
can be expanded as:
k=7;
for(; k >= 0; ){
//your code here printf("%d \n",sum);
sum = k--;
}
In first run sum is uninitialized so your program have undefined behavior.
Try this
#include<stdio.h>
int main()
{
int k=7,sum;
for(sum=k=7;k>=0;sum=--k)
printf("%d \n",sum);
return 0;
}
The loop starts by taking the initial value of the sum which in this case is by default equal to zero as a result the first iteration displays 0 however on the second iteration init of sum takes place and it starts from 7 to onward 0
When k=1 then value of k is assigned to sum and it gets decremented to 0 . Thus sum = 1 and k = 0.
Now k=0 and as per the loop condition k>=0 is true. So it enters into loop body and prints value of sum as 1 . Now value of k is get assigned to sum and k decrements . Thus sum = 0 and k = -1 . But -1>=0 is false and loop execution stops .
Hence program is not printing 0 in the last.

Explain about the nature of output of the code?

Code:
#include<stdio.h>
int main(void)
{
int i, j;
for(j = i+1, i=1; i<=5; j++, i++)
printf("%d %d\n", i, j);
return 0;
}
Output:
1 66
2 67
3 68
4 69
5 70
Can Anyone explain about the nature of output of the code?
i is unitialized when you set j=i+1. So j (initially) could be almost anything.
In your code i, j are not initialized at the time of declaration.
In for loop you assign j = i + 1 So j remains garbage value whereas i assigned 1 ,
in for loop you increment i, j and printf values. i increment from 1 to 5, and j from a initial garbage value (that is 66 in your output) to initial garbage + 5.
Edit On the basis of comments:
If you don't assign an initial value upon declaration the variable will be pointing at an address that may contain previously used data from another application(or any last used).
Before allocating memory in runtime system does not clear the memory before allocating (just to keep system performance high) So,default value of the variable is garbage value.
j is assigned the value of i even before i is assigned = 1. So i here can be any arbitrary value provided to it by the OS. In the above case the value assigned to i by the OS was 66. This arbitrary value could be different on varying systems.

Resources