Pointers assignment in C - c

int y=1;
int k=2;
int *p1;
int *p2;
p1=&y;
p2=&k;
p1=p2;
*p1=3;
*p2=4;
printf("%d",y);
I am getting the output as 1, can somebody explain me why !! I was expecting it to be 4.

The below comments explain how this works:
int y=1;
int k=2;
int *p1;
int *p2;
p1=&y; //pointer p1 holds the address of y
p2=&k; //pointer p2 holds the address of k
p1=p2; //pointer p1 now holds the address which p2 holds, which is the address of k
*p1=3; //the value which p1 points to is now 3 (so k equals 3 as well)
*p2=4; //the value which p2 points to is now 4 (so k equals 4 as well)
printf("%d",y); //y is still 1
However if you did printf("%d",k); the value 4 would be printed

To keep this simple let's say &y=3 and &k=4.
int y=1;
int k=2;
int *p1;
int *p2;
p1=&y; // p1=3
p2=&k; // p2=4
p1=p2; // p1=4
*p1=3; // p1=4 so k becomes 3
*p2=4; // p2=4 so k becomes 4
printf("%d",y); // we get 1 because y was never changed

When you do:
p1=p2;
you are basically copying the address of variable k from p2 into p1. So after that step both pointers are pointing to variable k, so if you dereference either p1 or p2 you will actually be changing the value of variable k and not y.
When you do:
*p1 = 3;
You are assiging 3 to variable k. Then when you do:
*p2 = 4;
You are assigning 4 to the variable k again. That's why y remains unaltered and when you print it gives you 1.

The statement p1=p2; sets p1 to point to variable k. So both of the following assignments:
*p1=3;
*p2=4;
only affect variable k, so y remains 1.

Sure, although I'd love to hear how you arrived at 4. p1 gets assigned the address (i.e. pointer to) y, but 2 lines later that gets replaced by the address for k. Thus, neither p1 nor p2 point to y, so y doesn't change.

Related

Understanding pointers in C using example code

I am learning pointers in C, so I am looking at one example. I tried to add comments to understand what is going on. Is the following code correct? In other words, do my comments describe the operation correctly?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main(){
int x, y;
int *p1, *p2;
x=-42;
y=163;
p1=&x; //pointer 1 points to the address of x
p2=&y; //pointer 2 points to the address of y
*p1=17; //this just made x=17 because it says that the value at the address where p1 points should be 17
p1=p2; //this just made pointer 1 point at the same place as pointer 2, which means that p1 now points at y
p2=&x; //this just made pointer 2 point at the address of x
//NOW WE HAVE: p1 points at y, p2 points at x, y=17 because of p1
*p1=*p2; //now x=17 as well as y (because the value at the place p2 points, which is x, just became 17)
printf("x=%d, \ny=%d\n", x, y);
return 0;
}
"Check the debugger", for sure. You can also just copy your printf statement after each time you set a value to check, since you're just learning, but this isn't good long-term practice.
I'm not sure if you've quite got the concept and just made a typo mixing up x and y, or if you're making an incorrect assumption, but yes, in your comments:
//NOW WE HAVE: p1 points at y, p2 points at x, y=17 because of p1
you have the location of p1 and p2 correct at this point, but y has not received an assignment since you gave it the value of 163 initially. Assignments to *p1 will affect y, but only after the p1=p2 line.
At the point of this comment, x=17, because of the *p1=17 line a few line up. y is unchanged from the initial assignment.
*p1=*p2; //now x=17 as well as y (because the value at the place p2 points, which is x, just became 17)
y becomes 17 here, as *p1 (which is now y) is assigned the value in *p2, which, as you state, is x.

Scope of variables mechanism in c

How the mechanisms of variable's scope work (local, static and global)?
I don't understand this output:
void foo1(int *z)
{
z = (int *)malloc(sizeof(int));
*z = 3;
}
void foo2(int *t)
{
*t = 3;
}
void main()
{
int y = 1;
int x = 2;
foo1(&y);
foo2(&x);
printf("%d %d", y, x);
}
output: 1 3
void foo1(int *z)
{
z = (int *)malloc(sizeof(int));
*z = 3;
}
I am not sure why you are using malloc, but *z ends up pointing to the memory address of the memory you just assigned with the malloc. So overriding the original pointer means the change isn't reflected in the original main() method.
A bit more clear:
You have a pointer * z that is pointing to the y from main(). When you use malloc it returns a pointer, so when you assign that to z, it is now pointing to a different block of memory that has nothing to do with the y from main(). You then assign this new block of memory the value of 3. Hence the original y is unchanged.
Starting in main, int y = 1; creates a local object named y and initializes it to 1.
Then int x = 2; creates a local object named x and initializes it to 2.
Then foo1(&y); calls foo1 while passing it the address of y.
In foo1(int *z), the parameter z is effectively an object local to the function foo1. As foo1 starts, z contains the address of y.
Then z = (int *)malloc(sizeof(int)); allocates memory and assigns the address of that memory to z. This changes z, so z no longer contains the address of y.
Then *z = 3; puts 3 in the place where z points, which is now the allocated memory. So the contents of the allocated memory change. y does not change because z no longer points to y, since z = (int *)malloc(sizeof(int)); changed z.
Then foo1 returns and main calls foo2(&x);, which calls foo2 while passing it the address of x.
In foo2(int *t), the parameter t is effectively an object local to the function foo2. As foo2 starts, t contains the address of x.
Then *t = 3; puts 3 in the place where t points. Since t points to x, this changes the contents of x, so now x contains 3.
Then foo2 returns.
Back inside main, printf("%d %d", y, x); prints the contents of y and x. Since y did not change, it is still 1. Since x did change, it is now 3.

Understanding of pointers an usage in C

In the code I wrote:
int *p1=&a,**p3=&p1;
after passing p3 as an argument to the function 'change', p1 gets
changed...then the main function has printed p1, p1 takes the value
at double pointer p3(as wrote int **p3=&p1), but it does not take address
of a(int *p1=&a).
This means that value of p1 will be the value at p3, not
the address of variable 'a'? Why the value at double pointer 'p3'
will be considered??
Why not the value of address(&a) which the pointer stored? can anyone clarify
these two lines....
int *p1=&a;
int **p3=&p1;
I understood the concept of double pointers, but need clarification
regarding these two lines...
#include<stdio.h>
void main()
{
int a=2,b=3;
int *p1=&a,*p2=&b,**p3=&p1;
printf("p1=%d, p2=%d, p3=%d\n",p1,p2,p3);
change(p3,p2);
printf("p1=%d, p2=%d, p3=%d\n",p1,p2,p3);
printf("p1=%d\n",p1);
printf("a=%d, b=%d\n",*p1,*p2);
}
void change(int **x,int *z)
{
*x=z;
printf("p1=%d, p2=%d\n",*x,z);
printf("a=%d, b=%d\n",**x,*z);
}
output:
p1=-840577016,p2=-840577012,p3=-840577008
p1=-840577012,p2=-840577012
a=3,b=3
p1=-840577012,p2=-840577012,p3=-840577008
p1=-840577012
a=3,b=3
Because you changed p1 in this line. *x=z;
To explain a bit more you have done this
change(p3,p2)
Now p3 has address of p1. And then you just changed it by assigning to it something else..
That something else is nothing but b's address.
void change(int **x,int *z)
x contains address of p1.
z contains address of b.
Then you said that whatever is the content of x - go there and write there whatever is the content of z. z contained address of b. So now we changed p1-s content to the address of b.
..but in the main will it ignore the line int *p1=&a after p1 gets changed in the function??
Well to the OP - do you think that p1 will get changed here?
int *p1 = &a;
p1 = &b;
We have lastly assigned b's address to p1. The value earlier written os overwritten.
Nothing is ignored - the program did whatever it is said to do.
Another point
Use %p to print a pointer like this
printf("p1=%p, p2=%p, p3=%p\n", (void*)p1, (void*)p2, (void*)p3);

What's the right way to use pointers. And how do they really work? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I've been trying to figure this out for a while.
From what I understand a pointer is declared like this:
int x =1;
int* p;
From what I understand is that p is not currently pointed to anything but whatever p is pointing at should be an int. Makes sense.
then pass the address of x into p, so that it can point to its value
p = &x
Now whatever x is equal to is also equal to *p and vice versa.
Following that train of logic, if you wanted to initialize a pointer you would do so like this:
int x = 1;
int* p = x;
But this is confusing me. Now what I understand is that the value of p (whatever it points to) is the value of x, 1, but doesn't point to x actually. So how does that work? p isn't pointing to anything but whatever it is pointed to is 1? I don't understand.
Another thing I wanted to know was how pointer = pointer works?
Let's see another example along with my train of logic:
int x = 1;
int* p;
int* p2;
p = &x;
*p2 = *p;
This translated to me as: the pointed value at p2 equals to the value pointed at p, but doesn't point to the variable that p is pointing at (which is x), just the value of x.
Can someone clarify this for me? Is my train of logic wrong? And if so how should I look at it?
After
int x = 1;
to get a pointer to x you would say
int * p = &x;
and not
int * p = x;
so you were right to find the latter confusing.
In your second example, when you say
*p2 = *p;
that will take the thing p points to (which is the value 1, contained in the variable x) and try to store it wherever p2 points. Unfortunately p2 has not been initialized, and doesn't point anywhere useful, so the results are unlikely to be anything you want. So, again, if you were confused about what that would do, you were right to be confused.
Important to say in computer memory there are no integers or pointers - only sequence of bytes. It's your program interpreting these bytes as int or int*. Outside of your program it's just bytes
Let's look at your example step by step. Suppose for the demonstration purpose you have memory of 256 bytes and your ints are only 1 byte:
step 1:
where you are declaring and assigning a variable
program:
int x = 1;
...
say your compiler decided to allocate memory cell 12 for the variable x:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |12:1| ... |255:X|
step 2:
where you are declaring the pointer
program:
int x = 1;
int *p;
...
recall step 1 ... and compiler allocated memory cell 5 for variable p (note - p is not initialized yet so the value in the cell 5 is X!):
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:X| .. |12:1| ... |255:X|
step 3:
where you are assigning the pointer
program:
int x = 1;
int *p;
p = &x;
...
recall step 2 ... and now cell p stores pointer to x. we know cell 12 has been allocated for x, hence 12 is stored into p (cell 5):
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12| .. |12:1| ... |255:X|
step 4:
where you are declaring the second pointer
program:
int x = 1;
int *p;
p = &x;
int *p2;
...
recall step 3 ... and your compiler allocated memory cell 6 for the variable p2 (it's unassigned yet so the value is X):
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |255:X|
step 5:
where you are assigning the second (still undefined!) pointee:
program:
int x = 1;
int *p;
p = &x;
int *p2;
*p2 = *p;
...
recall step 4 and then *p makes compiler recall that p is cell 5 so it generates insruction to read from cell 5 (there is value 12) and use that value as an address of an actual result: reading from cell 12 returns 1. Now compiler knows that name p2 has been given to cell #6 p2 is 6, but *p2 means you need to read the value of p2 and use it as address of the actual storage. But in our case this value is X (undefined)! However in the actual memory chips there is no undefined values and something has been store there at boot time (say value 42). Things become more complicated if virtual memory is affected but i do not want to discuss it here. So let's say electrical charges and cosmic rays at boot time initialized this cell to a random value of 42. Let's see what will happen when *p2 = *p will be executed: we've seen how *p returned us 1, now program will try to find where to store it to. it will read value of p2 which yields 42, now program will store 1 to the memory cell 42 and the result will look:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |42:1| ... |255:X|
in real world however using uninitialized value would frequently lead to a crash. When virtual memory involved some areas of address space (our 256 addresses) may have no memory cells allocated for them and writing to such an address would lead to crash.
step 6:
where you are assigning the second pointer and make it defined pointing again to x:
program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = p;
...
recall step 4 and ignore step 5 which caused your program crash ... now compiler knows which cells are used for both p (cell 5) and p2 (cell 6). hence assignment p2=p works this way: take value from p (which is 12), do not interpret it as pointer but just copy it to p2 instead. Now p2 becomes initialized with the pointer to x (cell 12).
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:12| .. |12:1| ... |42:X| ... |255:X|
step 7:
where you are assigning pointer to unnamed location:
program:
int x = 1;
int *p;
p = &x;
int *p2;
p2 = (int*)100;
...
... let's focus on this line: p2 = (int*)100; this shows how to assign pointer to point to an unnamed memory cell. Recall that compiler didn't assign a name yet to cell #100. But what if you know for sure there is something interesting at this memory location, for example a computer device is communicating with us via that cell. What if the keyboard stores the next character to memory cell #100 and we would like to read it? Now you can read it as *p2:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:100| .. |12:1| ... |42:X| ... |100:keyboard| ... |255:X|
step 8:
where you are revealing relation of pointers to arrays:
program:
int x = 1;
int *p;
p = &x;
int a[5];
a[2]=18;
int *p2 = a;
p2[2]=3;
...
... let's focus on this line: int a[5];: this declaration line tells compiler to allocate 5 cells and use name a for them. And compiler allocated cells 7, 8, 9, 10, 11 for a:
memory |address:value| (value of X means unknown):
|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:X|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
note that it didn't allocate a pointer -- a would be used literally like any other variable! This is how a[2]=18 works: first compiler knows that a starts and 7, so it uses that value as a start, then it adds 2 to get 9. So the target storage cell is found - it's the cell number 9, so it store 18 into that cell:
|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
so let's see how int *p2 = a; works: the compiler knows that a starts at 7. Hence 7 is stored into p2 (recall the cell #6 has been allocated to p2 at step 4)
|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
after initializing a pointer you can use it as an array p2[2]=3;: this is short for *(p2 + 2) = 3. value of p2 is 7, adding 2 gives 9, so we are storing 3 to cell #9:
|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:3|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X|
Sorry for such a long explanation i tried to cover relations between values, variables, pointers and arrays and most use cases for these.
I think it helps to remember that pointers are simply integers themselves. So when you create a pointer, it's really just an offset number into memory. The type of a pointer just tells the compiler how to interpret the data when the pointer is dereferenced. So when you do something like this:
int *p = &x;
You are just assigning an integer to p that is the memory address (offset) of x. In a sense, all pointers really have the same "type", they are either 32 or 64 bit integers, depending on the architecture. Dereferencing a pointer like this:
int y = *p;
Just means "offset into memory by p bytes, and give me the value there in the form of an int (which is 4 bytes)". The type of a pointer just tells the compiler how to read the data out of memory after the offset.

Integer pointer as parameter of function

void inc(int *p) {
p += 1;
}
int main() {
int x = 5;
inc(&x);
printf("x = %d\n", x);
return 0;
}
I've figured that this code doesn't increase the value of x.
It works when I change
void inc(int *p) {
p += 1;
}
to
void inc(int *p) {
*p += 1;
}
Kind of got confused with pointers right now.
Can someone help me?
Thank you in advance!
The difference between the two pieces of code is the difference between increasing the address that the pointer contains and changing the actual value.
The first piece of code: p += 1; increases the address that p is pointing to by one. For instance if x is at address 124, then p was first equal to 124 and is now increased to 125 (in a simple scenario, realistically this would increase by more as p is an integer pointer and thus the increase would be more than 1 byte).
The second piece of code: *p +=1; first dereferences the address in p and adds one to the value currently stored in that address. For instance if x is at address 124 and is of the value 42, then p equals 124, but *p is the deferenced pointer and is equal to 42. You can then assign a new value to *p to make the value at address 124 (i.e. the value of x) equal to 43.
EDIT: As mentioned by #Bathsheba, pointers are passed by value to function calls. This means that if we were to do the following, the original pointer y would remain unchanged, whereas the address p is pointing to does change as mentioned above.
void inc(int *p) {
p += 1;
}
int main() {
int x = 5;
int *y = &x;
inc(y);
return 0;
}
As for your second question on structs. Structs pointers still contain the address of the struct in memory, but the 'arrow notation' you refer to will implicitly do the dereferencing of the fields for you.

Resources