I have noticed that if you pass a local variable, it can change it's value even though you didn't pass it by adress.
I have 2 questions: is for() a function or a macro? I want to see how it was written.
How can it change the value, without an adress?
int main()
{
int i = 0;
for(; i < 5; i++);
/* i is 5 now. How? */
return 0;
}
You are confusing two things, "how for works" (which isn't your actual problem), and variable scope (which is).
Consider:
#include <stdio.h>
int main()
{
int i = 0;
printf( "Address of i outside the loop: %p\n", &i );
for ( int i = 0; i < 5; ++i ) // this "shadows" i
{
printf( "Address of i inside the loop: %p\n", &i );
}
}
You will see that the i inside the loop is at a different address. There are two variables named i here, and inside the for loop, the one declared at the beginning of the program is not visible.
This has nothing to do with how for works; it would be the same here:
#include <stdio.h>
int main()
{
int i = 0;
printf( "Address of i outside the block: %p\n", &i );
{
int i = 0; // this "shadows" i
printf( "Address of i inside the block: %p\n", &i );
}
}
You are looking at a "shadowed" variable: Inside the for loop / code block, i means something other than outside.
If you write this:
#include <stdio.h>
int main()
{
int i = 0;
printf( "Address of i outside the loop: %p\n", &i );
for ( i = 0; i < 5; ++i ) // does NOT "shadow" i
{
printf( "Address of i inside the loop: %p\n", &i );
}
}
...you don't redeclare i -- no int in the for statement, so there is only one declaration, and only one variable named i in the program.
for is not a function or a macro, but a keyword of the language. There is no convenient bit of code that would show you its inner workings, as what it does would be spread out across the various compiling stages (lexing, parsing, code generation). But as I showed above, what confuses you has nothing to do with for in the first place, but with variable scope. I hope the example snippets help you understanding the issue better.
I have noticed that if you pass a local variable, it can change it's value
That is because if we can't change values of local variables, it would be impossible to write functioning programs.
is for() a function or a macro?
It is neither, it is an iteration statement, one of the core building blocks of the language.
I want to see how it was written.
That doesn't make any sense, for the above reason. A for loop can generate all manner of machine code, including the compiler performing a complete loop unrolling and/or removing the loop entirely. For example if I add a printf("%d\n", i) at the bottom of your program, the whole loop when compiled on x86 gets replaced with mov esi, 5 = move the value 5 into a register (then print it). No loop is necessary.
A loop doesn't exist as written code, other than as a lexical element that the compiler treats in a certain way, according to the C standard.
How can it change the value, without an adress?
This has nothing to do with the loop as such but the i++ expression, which is guaranteed to update the variable "as per assignment", similar to i=i+1. No address is needed, the variable is written to directly.
your loop is an equivalen of:
int main(void)
{
int i = 0;
loop:
if(!(i < 5)) goto loop_exit;
i++;
goto loop;
loop_exit:
printf("%d\n", i);
}
Judging by the comment you attached to your question, it seems that the real problem is that you don't understand what variable scope and shadowing are. So here is a short demonstration program:
#include <stdio.h>
int main( void )
{
int i = 1000;
printf( "Test 1: i now has the value: %d\n", i );
for ( int i = 0; i < 5; i++ )
{
printf( "Test 2: i now has the value: %d\n", i );
}
printf( "Test 3: i now has the value: %d\n", i );
}
This program has the following output:
Test 1: i now has the value: 1000
Test 2: i now has the value: 0
Test 2: i now has the value: 1
Test 2: i now has the value: 2
Test 2: i now has the value: 3
Test 2: i now has the value: 4
Test 3: i now has the value: 1000
In this program, I have declared two distinct int variables, both with the same name i. The second variable only exists inside the loop and when I use the identifier i inside the loop, it refers to this second variable. This means that the second variable i shadows the first variable, as long as it exists. As soon as you exit the loop, the second variable ceases to exist, so that it no longer shadows the first variable. That is why "Test 3" prints the value of the first variable again, which is 1000.
is for() a function or a macro?
It is neither a function nor a macro. It is a keyword, which means that it has a special meaning to the compiler. For this reason, it also does not have its own source code.
You have to understand the concept of scope for a variable. Scope associates an identifier with an object. In less fancy words: a name with some memory.
In this code:
int main(void) {
for (int i = 0; i < 5; ++i) {
...
}
return 0;
}
the scope of i is the block of the for block (after the second {). This is a bit unusual in that normally the scope of an identifier starts after its declaration inside a block and ends at the enclosing }.
In this code:
int main(void) {
int i = 0;
for (;i < 5; ++i) {
}
return 0;
}
i has block scope of the main's function block (the first {).
And then there's the case where the same identifier is used in different nested blocks (in C jargon this is called shadowing):
int main(void) {
int i = 0; /* This i is in main's block scope. */
for (int i = 0;i < 5; ++i) { /* This i shadows main's i. */
frob(i); /* Uses i of the inner scope. */
}
/* Here i is from main's scope again. */
return 0;
}
is for() a function or a macro?
Neither - it is a statement. Here's the syntax:
for ( expr1opt ; expr2opt ; expr3opt ) statement
Don't let the parentheses fool you into thinking it's a function or macro, they're just there to separate the control expressions from the body of the loop.
Here's how it works:
expr1, if present, is evaluated once - it usually initializes whatever condition expr2 is testing;
expr2, if present, is evaluated before each loop iteration - if true, statement (the loop body) is executed, otherwise we exit the loop;
expr3, if present, is evaluated after each loop iteration - it usually updates whatever condition expr2 is testing.
Let's walk through an example to see how it works;
int i = 0;
for ( i = 0; i < 10; i++ )
printf( "i = %d\n", i );
Set i to 0
Evaluate i < 10; if false, goto 6
Execute the printf statement
Increment i
goto 2
Exit loop
Now, if you write it as
int i = 0;
for ( int i = 0; i < 10; i++ )
printf( "i = %d\n", i );
this will create a new object named i that "shadows" the variable i declared before the loop. This new object i is local to the loop body, and any changes to it do not affect the variable i declared outside of the loop.
Each of the control expressions is optional - you could write a loop as
for ( ;; )
do_something();
which will loop "forever" - expr2 is assumed to be true in this case.
As John Bode said in his answer, it's a statement, but you can think of it as a macro that does this:
#define for(A;B;C){STUFF} A; while(B){STUFF C;}
Because this:
for(int i = 0; i < 10; i++){puts("howareyou");}
is identical to this:
int i = 0;
while (i < 10){
puts("howareyou");
}
which is identical to this:
int i = 0;
loopstart:
puts("howareyou");
if(i < 10) goto loopstart;
TLDR: for loops are shortcuts for while loops, and while loops are shortcuts for "goto loops". Switch-case statements and functions are also just shortcuts for goto statements in a way.
Consider this:
int main() {
int i = 1; // function scope
int j = 5;
printf( "i = %d j = %d\n", i, j );
{ // Begin local scope
int i = 3; // local scope within "{}"
printf( "i = %d j = %d\n", i, j );
// There is no legitimate way to access the 'other' i in this scope.
// The 'function scope' i stands in the shadows...
} // end local scope
printf( "i = %d j = %d\n", i, j ); // function scope
return 0;
}
i = 1 j = 5
i = 3 j = 5 // j is not being "shadowed"
i = 1 j = 5
Related
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.
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.
I was doing some exercises on codewars, and had to make a digital_root function (recursively add all digits of a number together, up untill there's only one digit left).
I was fairly confident that I did it right, but for some reason my while-loop never broke, even though my prints showed that len was 1.
#include <stdio.h>
#include <string.h>
int digital_root(int n) {
char number[10];
sprintf(number, "%d", n);
int len = strlen(number);
printf("Outer print: %s %d %d\n", number, n, len);
int sum = 0;
while(len > 1)
{
sum = 0;
for(int i = 0; i<len; i++)
{
sum += number[i] - '0';
}
sprintf(number, "%d", sum);
int len = strlen(getal); //!!!
printf("Inner print: %s %d %d\n", number, sum, len);
}
return sum;
}
It took me a long time to figure out what was wrong. I noticed that I copy pasted the 'int' keyword when I recalculated the len in the while loop (line marked with !!!). When I removed that (because it was not needed to redefine it as an int, it already was), everything suddenly worked like it was supposed to.
This kinda confused me. Why would this matter? I understand that redefining it is bad practice, but I don't get how this would result in the while-loop not breaking?
The used compiler is Clan3.6/C11.
(Ps. When I tried the same code in TIO, it worked in both cases...)
You're not redefining an existing variable, you're defining a new variable.
Consider this example:
#include <stdio.h>
int main(void) {
int x = 42;
printf("Outside, start. x (%p) = %d\n", (void *)&x, x);
{
printf("Inner block, start. x (%p) = %d\n", (void *)&x, x);
int x = 123;
printf("Inner block, end. x (%p) = %d\n", (void *)&x, x);
}
printf("Outside, end. x (%p) = %d\n", (void *)&x, x);
return 0;
}
Sample output:
Outside, start. x (0x7ffd6e6b8abc) = 42
Inner block, start. x (0x7ffd6e6b8abc) = 42
Inner block, end. x (0x7ffd6e6b8ab8) = 123
Outside, end. x (0x7ffd6e6b8abc) = 42
[Live demo]
This program outputs the memory address and value of x. Most uses of x refer to the outer variable declared at the beginning of main. But within the inner block, after int x = 123;, all occurrences of x refer to a second, separate variable that happens to also be called x (but is otherwise independent).
When execution leaves the inner block, the outer x variable becomes visible again.
This is also referred to as shadowing.
In your code, the outer len is never modified, so while(len > 1) is always true.
By the way, shadowing is a very common concept in most languages that support block scoping:
Perl
JavaScript
Haskell
Common Lisp
Your second int len creates a second, parallel, variable that goes away at the end of the {} block. The original len then returns to life, completely unchanged. Without the second int the original variable is changed. With it the original len is effectively an unchanged constant and infinite loop.
in learning quick union algorithm, i have met these two statements
for(i=p; i!=id[i]; i=id[i]);
for(j=q; j!=id[j]; j=id[j]);
since I only learned for loop to be something like
for(i=0; i<100; i++)
I don't know the difference between the two statements and the following statements
i=p; i=id[i];
j=q; j=id[j];
i have no idea why the results are different?
thanks
I want to ask why
#include <stdio.h>
#define N 10000
int main()
{
int i, j, p, q, id[N];
for(i=0; i<N; i++) id[i]=i;
while(scanf("%d %d\n", &p, &q)==2)
{
for(i=p; i!=id[i]; i=id[i]);
for(j=q; j!=id[j]; j=id[j]);
if(i==j) continue;
id[i]=j;
printf(" %d %d\n", p, q);
}
}
is different from
#include <stdio.h>
#define N 10000
int main()
{
int i, j, p, q, id[N];
for(i=0; i<N; i++) id[i]=i;
while(scanf("%d %d\n", &p, &q)==2)
{
i=p; i=id[i];
j=q; j=id[j];
if(i==j) continue;
id[i]=j;
printf(" %d %d\n", p, q);
}
}
I have tested the results, that's why I am confused
i=p;
Sets i to the value of a variable p (defined and initialized elsewhere in the program)
i=id[i]
Sets i to the value of the i th element of the array id (defined and initialized elsewhere in the program)
for(i=p; i!=id[i]; i=id[i]);
Loop initializes i to the value of p, executes the statements inside the for loop once if i is not equal to the i'th value of the array id, and then stops.
Further explaination:
assuming some values for the variables:
int p = 4;
int i;
int id[5] = {1,2,3,4,5};
for(i=p; i!=id[i]; i=id[i]) {
printf("Loop executed!\n");
}
Output:
Loop executed!
And then a segmentation fault.
What happens:
i is set to 4, then compared to id[4]. This is unequal, thus the loop is triggered. After that it sets i to 5. Now it tries to compare id[5] to i. This is disallowed because id only has space for 5 elements and indexes start at 0.
When looking at non-standard for "loops" like this, it helps to convert your for loops into while loops. (that is all they really are)
To do that, remember that a for loops consists of three parts separated by semicolons. The initialization part, the conditional part, and the update or increment part:
for(initialize statement; boolean loop conditional; update/increment statement);
The initialize statement is executed before your loop, the loop conditional is evaluated to determine whether the loop continues, and the update/increment statement is executed as the end of the loop.
Your first example:
for(i=p; i!=id[i]; i=id[i]);
As a while loop, looks like..
i = p
while(i!=id[i]) {
i = id[i];
}
Your second example:
for(j=q; j!=id[j]; j=id[j]);
As a while loop, looks like..
j = q
while(j!=id[j]) {
j = id[j];
}
Once they're written like this, it's easier to tell what's going on.
We're initializing the loop variable to one of two values, p or q.
Then, we're looking into the array "id" at the location specified by the loop variable and updating the loop variable with it. This has the effect of looking up in the array the next loop variable. In other words, each slot in the array contains the next value to jump to.
The conditional checks to see whether the destination is the same as the current location. That is to say, if we are "told" to jump to the location we're already in.
The difference between you two loops is only the initialization value. The first one initializes to p where the second initializes to q.
It may be helpful to manually jump through a simple cases such as..
p=0
q=1
id = {1,2,2}
p=2
q=1
id = {0,0,2}
In c, when this block of code is run,it outputs 10 10 10 10 10. I think the loop should exit after 1st execution as i becomes 11 but it is not happening. Why it is so?
#include<stdio.h>
int main()
{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d\t",i);
i++;
}
return;
}
But when program is written as below the output is similar to what i am thinking(i.e.10 ).What is the exact difference between above code and the code shown below? How C is handling these variable? I would be glad if anyone explain about this.
#include<stdio.h>
int main()
{
int i;
for(i=0;i<5;i++)
{
i=10;
printf("%d\t",i);
i++;
}
return;
}
In your first program, for loop is using the i declared outside the for to control the loop. The printf uses the i declared inside the for loop to print the value and this i has block scope.
The new declaration of i in the for loop temporarily hides the old declaration. Now the value of i is 10. At the end of the for loop block the new i is not visible to the program and the variable regains its old meaning and this time i stores the value as per the iteration of loop (either 1, 2, 3 or 4).
In the first code you declare your variable twice: one outside the loop and the second one inside the loop. So inside the loop compiler found another declaration for the variable so it uses the inner declaration (this called block scope).
So that the first program print 10 10 10 10 10 because this is the inner declaration int i=10
But in the second code you declare it once so the compiler use this declaration in the whole program.
In C99 or later, you can write this variation on your code with 3 independent variables called i:
#include <stdio.h>
int main(void)
{
int i = 19;
printf("i0 = %d\n", i);
for (int i = 0; i < 5; i++)
{
printf("i1 = %d\n", i);
int i = 10;
printf("i2 = %d\n", i);
i++;
}
printf("i0 = %d\n", i);
return 0;
}
The output is:
i0 = 19
i1 = 0
i2 = 10
i1 = 1
i2 = 10
i1 = 2
i2 = 10
i1 = 3
i2 = 10
i1 = 4
i2 = 10
i0 = 19
(In C89, you can't have the variable tagged i1 in the output, and you couldn't demonstrate the two variables in the loop because declarations have to precede statements such as printf() calls.)
Because in first example the i inside the loop is not the same as the one which governs/controls the loop, it is a completely different variable though with same name.