2

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.

timrau
  • 22,578
  • 4
  • 51
  • 64
Hakim
  • 3,225
  • 5
  • 37
  • 75

6 Answers6

2

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;
} 
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

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.

Fekete Ferenc
  • 119
  • 2
  • 11
1

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.

Binarian
  • 12,296
  • 8
  • 53
  • 84
  • 2
    Java only has pass-by-value also (http://stackoverflow.com/questions/40480/is-java-pass-by-reference) so actually C is just like Java in this regard – David Heffernan Feb 03 '14 at 10:26
  • Yeah you are right, it was another language. Python or some sort of less strict language. Thanks for remembering it :). – Binarian Feb 03 '14 at 10:28
  • 1
    Probably is Java. Classes in Java are reference types. Which means that variables refer to instances, that is they are just pointers to the instance. And the `.` operator includes an implicit dereference of the pointer. Unlike in C. That's the issue you allude to I think. By because Java does not have pass-by-value it is actually impossible to write a swap function in Java! – David Heffernan Feb 03 '14 at 10:31
  • 1
    other "less strict" languages like python pass by reference but have the concept of immutability for some types, that's why people believe that some types pass by value and others by reference but it's wrong. – Jean-François Fabre Dec 19 '19 at 20:59
0

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.

n0p
  • 3,399
  • 2
  • 29
  • 50
0
******            /---\
* 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.

legends2k
  • 31,634
  • 25
  • 118
  • 222
0

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;
}
arnobpl
  • 1,126
  • 4
  • 16
  • 32