Home > Software design >  Pointer Swapping Rules
Pointer Swapping Rules

Time:09-30

I have a few questions regarding the rules of using pointers and arrays, as I am little confused about the rules regarding passing arrays around.

void f1(int* x, int* y) {
  int * ptr = x;
  x = y;
  y = ptr;
}

void f2(int* x, int* y) {
  int val = *x;
  *x = *y;
  *y = val;
}
void f3(int* x, int* y) {
  int val = *x;
  x = y;
  y = &val;
}

So let's say I have two arrays, a[3] = {0,2,4} and b[3] = {1,3,5}.

If I run the lines f1(arr_a, arr_b); & printf("%d\n", *arr_a); it will print out 0. I am assuming this is because since you are only passing a pointer of the array to the function, it is only a copy of the array, so nothing is actually modified. Would this assumption be correct?

Now, if I run f2(arr_a 1, arr_b 1) and printf("%d\n", *(arr_a 1));, it would result in a value of 3, and this is because since I am not using a pointer this time, I am directly using an integer (val), which is being set equal to the value of the array at an index of 1, and swapping those values. I am assuming because this manually changes the address, unlike the first function, which uses a pointer, which is a copy of the array?

And finally, for the third one, if I run f3(arr_a 1, arr_b 1) and printf("%d\n", *(arr_a 1)); the value should be 2 for x and 3 for y, since x is not swapped with y because the * operator is not used (so addresses are not swapped), and y is being set to the address of val, which is some random address, which also regardless does not get swapped? Thank you

CodePudding user response:

First, when passing an array type as a function argument, the array isn't actually passed, but instead the address of the first element is passed. So for an array a, the following two calls are equivalent:

f(a);
f(&a[0]);

Regarding your specific examples:

  1. The call f1(arr_a, arr_b); passes the address of the first element of arr_a and the address of the first element of arr_b. It's equivalent to f1(&arr_a[0], &arr_b[0]);. Nothing is copied, other than the addresses that are passed to the function. The function itself is given its own local copies of the two address. Even though it modifies them, those changes are confined to the function, and have no effect on the caller. All it's doing is making some local variable assignments. In fact, a good optimizer would completely eliminate the function body, since it doesn't do anything.

  2. The call f2(arr_a 1, arr_b 1); passes the addresses of the second elements of arr_a and arr_b. It is equivalent to f2(&arr_a[1], &arr_b[1]); Again, nothing is copied. However, function f2 dereferences those pointers, swapping their targets. So the values at index 1 in arr_a and arr_b are swapped.

  3. The call f3(arr_a 1, arr_b 1); passes the addresses of the second elements of arr_a and arr_b. It is equivalent to f3(&arr_a[1], &arr_b[1]); Again, nothing is copied. The function f3 loads the value of arr_a[1], then does a few local assignments. Like f1, this function has no effect, and a good optimizer would completely eliminate the function body.

To summarize, functions f1 and f3 do nothing and their bodies will likely be optimized away. Function f2 is the only one that does something useful, which is to swap the targets of its two pointer arguments.

CodePudding user response:

it is only a copy of the array, so nothing is actually modified. Would this assumption be correct?

In this call

f1(arr_a, arr_b);

that would be more correctly to write like

f1(a, b);

because you declared arrays a and b there is nothing copied. The array designators a and b are implicitly converted to pointers to their first elements. The call above is equivalent to

f1( &a[0], &b[0]);

These pointers are passed to the function f1 by value. That is the functipon deals with copies of teh values of the pointers.

Within the function

void f1(int* x, int* y) {
  int * ptr = x;
  x = y;
  y = ptr;
}

these copies are swapped. Changing the copies does not influence on the original arrays used as arguments. After exiting the function the local variables x and y will not be alive.

To make it clear consider the following code snippet. Let's assume that there are two variables a and b of the type int.

int a = 0;
int b = 1;

and then there is the following code

int x = a;
int y = b;

int tmp = x;
x = y;
y = tmp;

As you can see it is copies of the values of the variables a and b assigned to the variables x and y were swapped. The variables a and b stay unchanged.

Now, if I run f2(arr_a 1, arr_b 1) and printf("%d\n", *(arr_a 1));, it would result in a value of 3, and this is because since I am not using a pointer this time, I am directly using an integer (val), which is being set equal to the value of the array at an index of 1, and swapping those values. I am assuming because this manually changes the address, unlike the first function, which uses a pointer, which is a copy of the array?

In thus call

f2(a   1, b   1);

you are again using pointers but now they are pointers to second elements of the arrays. Within the function f2

void f2(int* x, int* y) {
  int val = *x;
  *x = *y;
  *y = val;
}

there are swapped the second elements of the arrays pointed to by the pointers. That is for example dereferencing the pointer x like

*x = *y;

you get a direct access to the object pointed to by the pointer x and can change the object.

The third function f3

void f3(int* x, int* y) {
  int val = *x;
  x = y;
  y = &val;
}

just does not make a sense. It swaps nothing. In the first declaration of the function the local variable val gets the value of the object pointed to by the pointer x.

  int val = *x;

Then the local variable x gest the value of another local variable y.

  x = y;

And at last the local variable y gets the address of the local variable val.

  y = &val;

After exiting the function all its local variables val, x, and y will not be alive. Neither object in the arrays a and b passed to the function through pointers were not changed.

CodePudding user response:

it is only a copy of the array, so nothing is actually modified. Would this assumption be correct?

There is no copy of array is created. When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule). So, it is just the pointer to first element of array arr_a and array arr_b assigned to function f1() parameters (integer pointers) x and y respectively. In f1() function, the pointers x and y get swapped i.e. y will point to first element of array arr_a and x will point to first element of array arr_b. Function f1() result in no change in any element of array arr_a and arr_b. After calling this function, the print statement

printf("%d\n", *arr_a);

is printing 0 because *arr_a is equivalent to arr_a[0]1) which is nothing but first element of array arr_a whose value is 0.

*arr_a -> *(arr_a   0) -> *((arr_a)   (0)) -> arr_a[0]

I am assuming because this manually changes the address, unlike the first function, which uses a pointer, which is a copy of the array?

No, it does not change the address, it changes value at the address, pointed by pointer x and y, which you have passed to function f2() as arguments. Pointer x is holding the address of second element of array arr_a and at that address, an integer value exist. When you dereference x (i.e. *x), that means, you are accessing value at that address. When you assign any value to *x, that means, you are modifying the value at that address. Same is with pointer y. When the function f2() returns the change persist because you have modified the value at the address passed to this function (using the pointer x and y).

Now the arr_a elements are {0, 3, 4} and arr_b elements are {1, 2, 5}.

The print statement

printf("%d\n", *(arr_a   1));

will result in printing the second element of array arr_a whose value is 3.

the value should be 2 for x and 3 for y, since x is not swapped with y because the * operator is not used (so addresses are not swapped), and y is being set to the address of val, which is some random address, which also regardless does not get swapped?

In function f3(), you are passing the address of second element of array arr_a and arr_b. They get assigned to parameter x and y respectively. Lets look, what is happening after execution of each statement of function f3() body:

Statement I of f3()

int val = *x;

Pointer x is pointing to second element of array arr_a. Dereferencing x (i.e. *x) will give the value at that address which is 3 and this value assigned to a local variable val of function f3().

Statement II of f3()

x = y;

Pointer y is pointing to second element of array arr_b. After this statement, both x and y will point to second element of array arr_b.

Statement III of f3()

y = &val;

Pointer y is assigned the address of local variable val which hold the copy of value of second element of array arr_a.

So, before exiting the function f3(), x is pointing to second element of arr_b and y is pointing to a local variable val.

No changes made to any value at address passed to f3(), hence the array arr_a and arr_b state will be same after returning from function f3().

The arr_a elements are {0, 3, 4} and arr_b elements are {1, 2, 5} and printing the second element of arr_a will result in output 3.


  1. From C Standards#6.5.2.1

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1) (E2)))..

  • Related