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}
Related
#include <stdio.h>
main()
{
int a[2][5], i,j; //2d array declaration
for(i=0;i<=1;i++) //first loop for 1st dimension
{
for(j=0;j<=4;j++) //nested loop for 2nd dimention
{
printf("Value for a[%d][%d] is : ", i,j);
scanf("%d", &a[i][j]); //asks for value
}
}
}
In this program, when the loop is executing, in the first run, i=0, and inside that j=0,1,2,3,4.
When this is done and it comes to the 2nd dimension where i=1, why does it run the nested loop again when the condition is already false (j<=4)?
Where are all these constant values saved? Does it restart the value of j when the nested loop is run again?
A for loop has three components (expressions) in the form for (A;B;C):
A - Pre-Iteration, run once at the start
B - Loop Condition, tested before each iteration, including the first
C - Post-Iteration, executed after each iteration
You're asking to initialize j=0 each time the loop starts, then testing j <= 4 which will be true. When the loop repeats it does j++, then tests again.
It's worth noting that these are all optional and for (;;) is valid, but is an infinite loop unless you break it.
With minor improvements:
int main(void) //added int and void to main
{
int a[2][5], i,j; //2d array declaration
for(i=0;i<2;i++) //first loop for 1st dimension
{
for(j=0;j<5;j++) //nested loop for 2nd dimention
{
scanf("%d", &a[i][j]); //asks for value [note, before printf]
printf("Value for a[%d][%d] is %d\n: ", i,j, a[i][j]);
}
}
return 0;//int main(void) requires a return statement
//Note also, 'main()' is really not a proper signature for
//the main function
}
This code intends to assign values to each member of the 2D array by using prompted input values using scanf, but because of some syntax and logic errors, the original would not work as intended. To help, the order of the two lines in the nested for loops has been switched to prevent the array from being accessed before being initialized.
The nested for loop indexes have been modified in this version to use the same values for limit, as those used to size the array in its declaration:
int a[2][5];
for(i=0;i<2;i++)
for(i=0;j<5;i++)
scanf() is the method used for user input. Each call prompts for a value, which is placed into the corresponding row-column index indicated by i and j, and written to stdout. Note the actual value in the original code is not printed out, but it is in this slightly modified version.
The value of j is initialized to 0 each time you run the nested loop because you set the initialize expression of the for statement to "j=0"
That expression will be run for each execution of the outer loop
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.
Please read the code below.
#include <stdio.h>
int main(void)
{
char* a[4];
int i=0;
while(i<3)
{
char b[50];
scanf(" %s",b);//Assume user enters one two three
a[i++]=b;
}
i=0;
while(i<3)
printf(" %s ",a[i++]);//Why does it always print three three three
return 0;
}
Clarify the following:
Is it that b gets allocated same 50 bytes in memory each time so that all the elements of array a point to same 50 bytes and thus we get only three printed three times(i.e. what's entered last)
Since after the completion of while, array b can be removed very well but no it remains there every single time printing only three's. Why?
Is it not at all a coincidence that this code prints only three's when it could print one two three, one three three as well. What's wrong?
I know the question is very wrongly put. Forgive me for that. I am new here.
QUESTION #1:
The variable b is a variable that is strictly local to the
while loop.
Therefore, do not reference via a pointer any memory formerly used by b outside (after) the while loop.
Storage for b will be reallocated 3 times.
At the end of the while loop, b will go out of scope.
QUESTION #2:
After the while loop, a is not a valid pointer anymore
because a was assigned to point to b,
and b has gone out of scope after the while loop.
NEVERTHELESS, the memory allocated to b may still
not have been modified. You cannot predict what the value of dereferencing a will be after the while loop - since a is only assigned based on b.
QUESTION #3:
(Please see #2) The code that is dereferencing a after the while loop is using a stale pointer - I would not rely on the output.
The code in the question exhibits undefined behaviour because the second loop attempts to access the data that was only valid in the first loop. Therefore, there is very little that can usefully be said.
The question title is "does a variable declared in a loop get the same address each time the loop executes". Here's a proof by counter-example that the address of the variables in a loop need not always be the same, even in a single invocation of a non-recursive function.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(0));
for (int i = 0; i < 3; i++)
{
int n = rand() % 30 + 5;
char a[n];
for (int j = 0; j < n - 1; j++)
a[j] = rand() % 26 + 'a';
a[n-1] = '\0';
printf("a: %p %2d [%s]\n", (void *)a, n, a);
char b[50+n];
scanf("%s", b);
printf("b: %p %2d [%s]\n", (void *)b, n+50, b);
}
return 0;
}
On a Mac running macOS Sierra 10.12.4 (using GCC 7.1.0), one run of the program (lv83) produced:
$ ./lv83 <<< 'androgynous hermaphrodite pink-floyds-greatest-hits-dark-side-of-the-moon'
a: 0x7fff507e53b0 23 [sngrhgjganmgxvwahshvzt]
b: 0x7fff507e5360 73 [androgynous]
a: 0x7fff507e53c0 9 [wblbvifc]
b: 0x7fff507e5380 59 [hermaphrodite]
a: 0x7fff507e53b0 26 [pqsbfnnuxuldaactiwvjzvifb]
b: 0x7fff507e5360 76 [pink-floyds-greatest-hits-dark-side-of-the-moon]
$
The address at which the two arrays are allocated varies depending on how big they are. By using different formulae for the sizes of the two arrays, the base addresses could be tweaked. It looks as though the compiler rounds the base address of the arrays to a multiple of 16.
I'm trying to write code for the gas station problem, where you have a fixed number of cities(linear) and you want to get from one end to the other with as few stops as possible, stopping wherever necessary to refill your gas tank. This is my main function; the function for calculation I've left out for now.
I keep segfaulting saying unable to access tank and arr during the call to solver(the function I'm using to solve).
int main(void)
{
int tank;
int cities;
int ans;
scanf("%d %d",&cities, &tank);
int *arr;
arr=(int *)calloc(cities,sizeof(int));
int *arr2;
arr2=(int *)calloc(cities,sizeof(int));
int i;
for(i=0;i<cities;++i)
scanf("%d",&arr[i]);
arr2[i]=0;
for(i=1;i<cities;++i)
arr2[i]=arr[i]-arr[i-1];
for(i=0;i<cities;++i)
printf(" %d ",arr2[i]);
ans=solver(tank, arr2,cities);
printf("\n ans is %d",ans);
return 0;
}
Can I get some pointers here(terrible pun)?
I'm using the input as:
6 3
0
1
3
4
7
10
Arr holds [0,1,3,4,7,10]
Arr2 holds the differences.
Your loop statement is the problem because of missing encolsing {}:
for(i=0;i<cities;++i) // loop
scanf("%d",&arr[i]); // but there is no enclosing braces. so this is the only statement that loops
arr2[i]=0; //<<<<<< this is executed when loop is finished, i.e i==cities
In other words, you assign arr2[cities], which is out of bouds as it's indexed from 0 to cities-1. This causes the segfault.
Looking at the rest of the code, I guess you inteded to to:
...
for(i=0;i<cities;++i) { // loop, but for the block
scanf("%d",&arr[i]);
arr2[i]=0;
}
...
Apropos the question "Why does using the same count variable name in nested FOR loops work?" already posted in this forum,a count variable "i" defined in each nested loop should be considered a new variable whose scope is limited to that loop only.And we should expect that variable's value to be erased and overridden by the value of "i" which was in the outer loop (before control passed to inner loop).But in my following code, when the control comes out of the inner loop,instead of the variable "i" having the value 0 (which was it's value in the first iteration of outer loop,before control passed to inner loop),it continues to have the value 10 instead (which it got in last iteration of inner loop).Then this 10 is incremented to 11 and hence the condition of the outer loop in not satisfied and the outer loop exits.
I had expected my program to print the numbers 0 to 9 horizontally 10 times, in 10 different lines.But it prints just for one line and exits.
And here's another thing to it--If I use any number greater than 10 in the outer loop condition (i<=10),then it creates an infinite loop.According to my reasoning, it happens because i gets a value of 11 after the first iteration of outer loop and hence if condition is <=11 or more then the outer loop comes to another iteration.Whereupon i is again initialized to 0 in inner loop and the cycle continues.
Sorry if I couldn't put my question very clearly.All I want to ask is, isn't the inner i supposed to be a different variable if we are to assume the linked question on this forum is correct?Why then the value of i continues to hold on after we exit inner loop,instead of reverting to the value of i that was there when we entered the inner loop?
#include <stdio.h>
int main()
{
int i;
//for (i = 0; i <= 11; i++) Creates infinite loop if this condition is used instead
for (i = 0; i <= 9; i++)
{
for (i = 0; i <= 9; i++)
{
printf("%d ", i);
}
printf("\n");
}
}
OUTPUT : 0 1 2 3 4 5 6 7 8 9
PS: As a secondary question, is it impossible to print the number 0 to 9 horizontally, in 10 different lines, using nested for loop if we use the same count variable in each loop,as I have done here? (Ignore this secondary question if it's not relevant to main question)
The answer you linked to is using different variables with the same name, you're simply using the same variable.
Compare:
for(int i = 0; ...
to:
for(i = 0; ...
The former declares a new variable called i, which is how you nest loops like the linked-to answer. Not that I would ever (ever!) recommend doing so.
As you've noticed, support for the former syntax wasn't added to C until C99.
If i were defined in each loop then the behaviour would be as your linked question. In your example you only define i once, outside any loop, then reuse it
int i;
for(i=0; i<=9; i++)
{
for(i=0; i<=9; i++)
{
is not the same as
for(int i=0; i<=9; i++)
{
for(int i=0; i<=9; i++)
{
If you want each for loop to have its own i, you need to create i individually for each. As-is, you have exactly one i that's defined outside both loops, so the modifications done by one loop affect the value seen by the other.
int i;
for (i=0; i<10; i++) {
int i; /* define another i for the inner loop */
for (i=0; i<10; i++)
printf("%d\t", i);
printf("\n");
}
Note that I'd generally recommend against this -- while the compiler has no problem at all with having two variables with the same name at different scopes, code like this where it's not immediately obvious what i is being referred to when may well confuse people reading the code.
All I want to ask is, isn't the inner i supposed to be a different
variable
no, there is only one declaration, so only one variable
Sorry - late response, but couldn't help but notice:
The reason it "works" is that the inner loop resets i to zero, prints & increments i, and returns to the outer loop - at which point i>9 so the outer loop exits.
There is only one iteration of the outer loop and the values printed are entirely determined by the inner loop. It's not a question of scope, it's the fact you reassign new values to i in the inner loop.
PS: As a secondary question, is it impossible to print the number 0 to 9 horizontally, in 10 different lines, using nested for loop if we use the same count variable in each loop, as I have done here? (Ignore this secondary question if it's not relevant to main question)
Of course you can, but you need a more complex format string for your printf.
printf("%d ",i);
The above statement works by printing I, immediately followed by a space, and leaving the carriage where the print stops.
The effect that I think you have in mind is something like the following.
0
1
2
3
4
5
6
7
8
9
To make that happen, you need a couple of changes to your printf statement, as illustrated in the following complete program.
// MarchingDigits.cpp : Defines the entry point for the console application.
//
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
for ( int i = 0 ; i < 10 ; i++ )
{
printf ( "%*d\n", ( i > 0 ? i + 1 : i ) , i ) ;
} // for ( int i = 0 ; i < 10 ; i++ )
return 0;
} // int main
The output generated by this program is as follows.
0
1
2
3
4
5
6
7
8
9
There are three fundamental differences between your printf statement and the one that generated this output.
Between the opening % and the closing d, I inserted an asterisk where the width goes.
I replaced the trailing space with a newline.
Between the format string and your integer argument i, I inserted another argument, in the form of a ternary expression, i > 0 ? i + 1 : i, which says, in effect, if I is greater than zero, set the width to i + 1, otherwise set the width to i. Although the else block sets the width to i, which happens to be zero, this works because printf guarantees never to truncate the output.