Unable to dereference double pointer in c - c

The output of this code is 20 20 10. The first 20 is easy to understand. But I am unable to understand how function change1 and change2 are accessing the variable b.
#include<stdio.h>
int a = 5, b = 10;
void change1(int *p);
void change2(int **pp);
main( )
{
int x=20, *ptr=&x;
printf("%d ",*ptr);
change1(ptr);
printf("%d ",*ptr);
change2(&ptr);
printf("%d\n",*ptr);
}
void change1(int *p)
{
p = &a;
}
void change2(int **pp)
{
*pp = &b;
}

But I am unable to understand how function change1 and change2 are accessing the variable b.
There is a misunderstanding of what change1 does.
It changes where p points to but that change is local to the function. It does not change where ptr points to in main since the pointer is passed by value. change1 does not have any code that accesses the variable b. It's not clear to me whey you think it does.
In change2, you are changing where the pointer points to, to b. The change affects where ptr points to in main since you are passing the address of ptr to change2 and you are changing where that dereferenced pointer points to.

In change1, p is a pointer to int that is passed by value. Assigning a value to p in change1 therefore has no effect because p is local to change1. This is the reason for the 2nd 20.
In change2, pp is a pointer to a pointer to int. It too is passed by value, but this time dereferencing pp (*pp) gives access to the location of the pointer (ptr), and it is into this location that the address of b (&b) is stored.

void change1(int *p)
{
p = &a;
}
The variable p is assigned with the address of a, but this is only valid within the function. p acts as a local variable within the function change1. After this function terminates, the pointer ptr would still be pointing at x(=20). This is the reason behind the second 20.
void change2(int **pp)
{
*pp = &b;
}
But this, is one of the correct ways to make changes to a pointer variable within the function so that it would still be valid outside. pp acts as a pointer pointing to the original ptr variable. As a result, ptr will end up pointing at b(=10) after change 2 terminates. This is the reason behind your third 10.

When you invoke change1() function, you're passing the pointer ptr as an argument. Let's suppose ptr = 0xcafebabe, and obviously *ptr = 20. Under the hood, you're writing the value 0xcafebabe on the stack, and the change1() function will only overwrite this value with &a on the stack frame corresponding to this function.
In the second case, you're passing a pointer to ptr as an argument. Let's suppose this pointer new_ptr has a value of 0xdeadbeef. In this case, *new_ptr = 0xcafebabe and you overwrite 0xcafebabe with &b (hence you are changing where the pointer is pointing.

Related

Passing pointer to function is'nt passing by reference in C?

#include<stdio.h>
int func(int*);
int main(void)
{
int a = 3;
int *p = NULL;
p = &a;
printf("p = %p\n", p);
func(p);
printf("p inc: %p\n", p);
return 0;
}
int func(int *p)
{
p++;
return 0;
}
Output: p=0x7fff6f87e89c
p inc:0x7fff6f87e89c
Pointer p is passed to function func and pointer p is incremented in func, but in main function its address is still the same!! Passing pointer to function is'nt passing by reference?
Pointers are passed by value.
If you want to pass a pointer by reference, you just pass a pointer of a pointer!
Like so:
#include<stdio.h>
int func(int**);
int main(void)
{
int a = 3;
int *p = NULL;
p = &a;
printf("p = %p\n", p);
func(&p);
printf("p inc: %p\n", p);
return 0;
}
int func(int **p)
{
(*p)++;
return 0;
}
There's no passing by reference in C. When you pass a pointer to a function, you are passing a memory address by value.
When, inside the function, you do this:
int func(int *p)
{
p++;
return 0;
}
...you are only incrementing the memory address indicated by the parameter p by sizeof *p bytes.
In order to "simulate" passage by reference in C, you need to explicitly dereference the pointer to access the actual object. If p is a properly assigned and valid pointer, then *p is the object it points to. If a non-pointer expression were this:
a = a + 1;
...then with p == &a it would become this:
*p = *p + 1;
...or simply (*p)++. Notice that the parenthesis are necessary because, otherwise, C will read this as *(p++). You can also get used to writing ++*p instead.
You increment the pointer, not the value.
Try like this
(*p)++;
And
printf("p inc: %d\n", *p);
You need to understand pointers. A pointer is simply a variable that stores the memory address where the data actually is. You can access the data by using the dereference operator *, so if you want to change the data, you simply dereference the pointer, and then modify the data.
Likewise, for printing you want to see the value of the data.
In your code, you only modify the pointer. In c you always pass by value, a copy of the pointer itself is created inside the func() function, initially it holds the same address as your original pointer, but since it's a copy, increment it will only affect the address in the local copy.
Further more, since it's pointing to a variable on the stack. The increment operation on it will result in a pointer that you can't dereference because it would be undefined behavior.
If you want to increment the address of the pointer, you need to pass a pointer to the pointer, like this
void func(int **p)
{
(*p)++;
}
and in main
func(&p);
note that the body of func() is the same, because you once again need to get access to the memory pointed to by p in order to modify it.

Why can't I pass a pointer as an argument?

I am attempting to retrieve a pointer via a function in c. If the pointer is a return value from the function then it works. But if I pass the address of the pointer to the function, I can't update the dereferenced pointer value (which should be the address stored in the pointer) from within the function.
Please see the code and the output. Why don't I get the same results with both GetPointer1() and GetPointer2()? What am I missing?
#include <stdio.h>
#include <stdint.h>
uint8_t SrcArray[2][3] = {{11,12,13},{21,22,23}};
uint8_t *p1;
uint8_t *p2;
void GetPointer1(uint8_t *p);
uint8_t* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", &SrcArray[0][0]);
GetPointer1(p1);
p2 = GetPointer2();
printf ("p1: %d\n",p1);
printf ("p2: %d\n",p2);
return 0;
}
void GetPointer1(uint8_t *p)
{
p = &SrcArray[0][0];
}
uint8_t* GetPointer2(void)
{
return &SrcArray[0][0];
}
Output:
&SrcArray[0][0]: 6295604
p1: 0
p2: 6295604
That is because the pointer you have in the function signature of GetPointer1(uint8_t *p) is passed by value. If you want to modify the pointer itself, you have to pass a pointer to a pointer:
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
Otherwise, you may modify the piece memory to which the pointer points, but not the pointer itself.
Its is local to function GetPointer1 because it is a local variable which is passed as an value not as an address.
Here is the output details of your code for better understanding
inside main: &SrcArray[0][0]: 6295616
value of pointer p1: 0
address of pointer p1: 6295640
inside GetPointer1: 0
value of pointer p: 0 //which ur taking to a pointer p and modifying p whihc is local to that function.
address of pointer p: 64030024
inside GetPointer1 after assignment:value of pointer p: 6295616
address of pointer p: 64030024
If you want to pass address you need to use & before the variable say &p1.
Also as mentioned in one of the answer by IGarFieldI you can use pointer to a pointer.
void GetPointer1(uint8_t **p) {
*p = &SrcArray[0][0];
}
One more point since P1 is global variable, its accessible to all the functions you can directly use P1=SrcArray; which is allowed and does the same task.
ScrArray is equivalent &ScrArray[][] both gives the address of the array.
You have a variable p1 that is pointing to something. Then you pass it to a function GetPointer1. What happens there is that the value of the variable p1 (this is the address of the value it is pointing to!!!) is copied (!) to the function stack. This means that you can modify the pointed value (*p1), but not the original pointer (p1) itself, as you only have a copy of it. If you want to be able to modify the original pointer, then you have to retrieve the address of the pointer and pass this one to the function, i. e. you need a pointer to the pointer. You get this via the address-of operator &. So you need this:
getPointer1(uint8_t** p) { *p = /*...*/; }
and call it via
getPointer1(&p1);
#include <stdio.h>
#include <stdint.h>
int SrcArray[2][3] = {{11,12,13},{21,22,23}};
int *p1;
int *p2;
void GetPointer1(int **p);
int* GetPointer2(void);
int main()
{
printf ("&SrcArray[0][0]: %d\n", SrcArray[0][0]);
GetPointer1(&p1); /*<-- passing the reference of pointer p1 */
p2 = GetPointer2();
printf ("p1: %d\n",*p1);
printf ("p2: %d\n",*p2);
return 0;
}
void GetPointer1(int **p) /*<-- using double pointer */
{
*p = &SrcArray[0][0];
}
int* GetPointer2(void)
{
return &SrcArray[0][0];
}
o/p
rabi#rabi-VirtualBox:~/rabi/c$ gcc -g stack3.c
rabi#rabi-VirtualBox:~/rabi/c$ ./a.out
&SrcArray[0][0]: 11
p1: 11
p2: 11
rabi#rabi-VirtualBox:~/rabi/c$
" But if I pass the address of the pointer to the function." But you're not passing the address of the pointer, you're passing a copy of the pointer; changing the copy (as you noticed), doesn't change the original. If you actually pass in the &p (address of p) like you intended, you will be able to modify it - I'm unsure of syntax. edit: void GetPointer1(uint8_t **p) maybe?

Passing address, but it is working like call by value in C?

Hello I am a beginner in C programming language. Recently I read about call by value and call by address. I have learned that in call by address changes in the called functions reflects the callee. However the following code does not work like that.
int x = 10,y = 20;
void change_by_add(int *ptr) {
ptr = &y;
printf("\n Inside change_by_add\t %d",*ptr);
// here *ptr is printing 20
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d", *p);
// here *p is still pointing to address of x and printing 10
}
When I am passing address then why the changes made by called function does not reflect caller?
The function is assigning a new address to the pointer but the pointer itself is being passed by value, as all arguments are in C. To change the value of a pointer variable the address of the pointer itself must be passed:
void change_by_add(int **ptr)
{
*ptr = &y;
}
change_by_add(&p);
See C FAQ Question 4.8.
Passing by reference does not exist in C but can be achieved by passing the address of the variable who's value is to be changed to a function. For example:
void add_to_int(int* a_value, int a_increment)
{
*a_value += a_increment;
}
You are simply setting the value of the pointer in the function, not the value of the pointed to variable. The function should use the following code:
*ptr = y;
This derefences the pointer (exposing the value pointed to), and therefore when you use the equals operator, the memory pointed at is modified, not the pointer itself. I hope this helps to clarify things.
Changes made by called function does not get reflected by the caller because you are overriding the pointer address in the called function i.e ptr = &y;.
Initially, you passed the address of x but you are changing it with the address of y.
If you really want to implement the concept of call by address then change value instead of address.
Example:
void change_by_add(int *ptr) {
*ptr = y; //changing value
printf("\nInside change_by_add\t %d",*ptr);
}
void main(){
int *p;
p = &x;
change_by_add(p);
printf("\nInside main\t %d \n", *p);
return 0;
}
Output
Inside change_by_add 20
Inside main 20
There is no such thing as call by address in C. There is only call by value. What one does when a function needs to modify an argument in a way that is visible to the caller is to have the caller pass a pointer to something, and have the called function write the update though that pointer. Note that the pointer itself is still sent as call-by-value - that is: the called function gets its own copy of the pointer and could change it to point to anything else if it wants to.

C - modify the address of a pointer passed to a function

I don't understand why the modification of pointer address passed as parameter to a function isn't persisted outside of this function (the address of ptr doesn't change after this function is called):
void advance(int *ptr) {
ptr = ptr + 1
}
When I can inside this same function modify the value pointed by ptr: *ptr = *ptr + 1.
PS: I know that I can achieve what I want using a pointer to a pointer: **ptr.
This behaviour is because parameters to functions in C are always passed by value. What you are passing by value here is an address. When you modify ptr you are modifying a copy of the caller's value.
To modify the caller's value you need an extra level of indirection:
void advance(int **ptr) {
*ptr = *ptr + 1;
}
When you define the function void advance(int *ptr) it means that a pointer in the stack will be created, which pointer points to the same addres as the original pointer. To see the proof try printing the address of orig pointer (&orig) and the address of the parameter pointer (&param), and the "pointed to" addresses (orig,param). The pointer addresses will differ, but the pointed to addresses will be the same.
So we have two pointers that points to the same area, if you modify the param, it will point to the new area, but the orig value will not be changed, it points to the same area as before.
That's why you need a pointer to a pointer. If you use a pointer to a pointer (int **ppointer = &orig), you will have a pointer that directly points to the area where orig stores the "pointed to" address (to where the orig points currently). By changing the value of the *ppointer, you will directly change the value of the orig as well.
Because C is not call by reference, it is always call-by-value, even with references/pointers as arguments.
It is not like other languages, where it can differentiate between argument types.
You actually answered you own question ;)
the modification of pointer address passed as parameter to a function isnt persisted outside of this function
Inside the function you are managing a copy of your parameter.
You can modify the value pointed because you are explicitly asking for change at a specific address.
****** /---\
* 20 * ----> | 2 |
****** \---/
i 20-24
Here i is a pointer pointing to the memory location 20 which has a value 2 i.e. when the binary data in 20 + sizeof(int) - 1 is interpreted as a decimal number. Now, when you pass i to advance, which has an argument ptr, what really happens is
****** /---\ ******
* 20 * ----> | 2 | &lt---- * 20 *
****** \---/ ******
i 20-24 ptr
ptr = i; i.e. the value of i is set to the value of ptr, which are really addresses here, since i and ptr are pointers.
When you increment ptr it'll just make the pointer point to a different address and not change anything with respect to i since ptr is a copy and not i itself. However, if you change the value at ptr using the operator * i.e. as *ptr = 10; then the 2 above will change to 10 thereby change *i as well, which is also pointing to 20. Again notice that i's address or value is untouched, only the location to which it is pointing to underwent a change. Had there been 10 pointers pointing to the address 20, even then none of them get changed, but all their pointed-to value gets changed.
See the function:
void demonstrate(int num) {
num = num + 1; // type of num is int
} // destroys "num", because num's scope is only "demonstrate" function
In your function:
void advance(int *ptr) {
ptr = ptr + 1; // type of ptr is int* and ptr is incremented
} // destroys "ptr" for the similar reason
But you want a function that modifies an address (IN pointer). So the complete solution should be:
#include <stdio.h>
void advance(int **ptr) { //ptr is a pointer to a pointer
// so *ptr is the pointer that is pointed by ptr
*ptr = *ptr + 1; // incrementing the address IN the pointer pointed by ptr
} // destroys "ptr" for the reason above
int main() {
int x = 5;
// initially assign "ptrToChange"
int *ptrToChange = &x;
// "ptrToChange" now points to x
// passing address OF "ptrToChange" to "advance" function
advance(&ptrToChange);
// now "ptrToChange" does NOT point to x
return 0;
}

double pointer vs single pointer

Can someone explain / give a reasoning to me on why the value of variable i in main function in below code snippet does not change via function test1 while it does change via test2? I think a single pointer should be sufficient to change the value of i. Why are we supposed to use double pointer?
#include <stdio.h>
void test1(int* pp)
{
int myVar = 9999;
pp = &myVar;
}
void test2(int** pp)
{
int myVar = 9999;
*pp = &myVar;
}
int main()
{
printf("Hej\n");
int i=1234;
int* p1;
p1 = &i;
test1(p1);
printf("does not change..., p1=%d\n",*p1);
test2(&p1);
printf("changes..., p1=%d\n",*p1);
return 0;
}
In C parameters are passed by value. This means that in test1 when you pass pp a copy is made of the pointer and when you change it the change is made to the copy not the pointer itself. With test2 the copy is of a double pointer but when you dereference and assign here
*pp = &myVar;
you are changing what is being pointed to, not changing pp itself. Take note that this behaviour in test2 is undefined as is documented in some of the other answers here
But you're not changing the value of i, you're changing the address that pp points to, if you only want to change the value of i then it's enough to change your test to:
void test3(int* pp)
{
int myVar = 9999;
*pp = myVar;
}
If you want to change the value of a variable of type T you have to use a pointer on that type (T*). Since you want to change a pointer (T = int*), you have to provide a pointer to a pointer (T* = int**), otherwise you're only going to change the copy.
Note that
int myVar = 9999;
*pp = &myVar;
will result in undefined behavior, since pp will now contain the address of a local variable which isn't valid after you exit the function.
Because f(x) can't change the value of x, no matter whether x is an int, a float, or a pointer.
void test1(int* pp)
{
int myVar = 9999;
pp = &myVar;
}
This function is passed a pointer pp. The function modifies that pointer. But since parameters are passed by value, that modification is not seen by the caller.
You need to write the function like this:
void test1(int* pp)
{
*pp = 9999;
}
The caller of this function is expected to pass the address of an int variable. The function then writes an int value, 9999 in this case, to that address. This is the key. You are passed an address, and you then write a value to that address. Your broken version simply modified the address. You were missing the indirection.
When the function returns, the caller can observe the modification to the int variable whose address was passed to the function. The calling code can look like this:
int i = 0;
test1(&i); // pass address of int variable
printf("%d\n", i); // prints the new value, 9999
void test2(int** pp)
{
int myVar = 9999;
*pp = &myVar;
}
Now, this is broken in a very serious way. This function does indeed return a pointer to the caller. But it returns a pointer to an object that goes out of scope as soon as the function returns. That is known as undefined behaviour. Don't do this. Never pass out of a function, a pointer to a local variable defined in that function.
pp = &myVar; assigns the address of myVar to the pointer pp. If you want to change the value that pp points to, use
*pp = myVar;
instead.
In answer to your second question, pass a pointer to a pointer when you want to change the object pointed to rather than changing the value of your existing object.
int* p1;
p1 = &i;
test1(p1); //1st
test2(&p1); //2nd
In simple way , 1st is pass by value and 2nd is pass by address.
Description :
In first case it passing pointer is actually the copy of that p inside test1 so the pp inside test1 is the local to that function and it's created in test1. You assigned the address and when comes out of function it's destroyed.
But in second case you are passing the address of the pointer to test2 function. So the pointer pp in test2 will point to the pointer p in main so assigning a new address to pp using *pp = &myVar will automatically set the value of p(since you are dereferencing the pointer). Hence when test2 terminates still p will point to modified location.

Resources