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:
The call
f1(arr_a, arr_b);
passes the address of the first element ofarr_a
and the address of the first element ofarr_b
. It's equivalent tof1(&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.The call
f2(arr_a 1, arr_b 1);
passes the addresses of the second elements ofarr_a
andarr_b
. It is equivalent tof2(&arr_a[1], &arr_b[1]);
Again, nothing is copied. However, functionf2
dereferences those pointers, swapping their targets. So the values at index1
inarr_a
andarr_b
are swapped.The call
f3(arr_a 1, arr_b 1);
passes the addresses of the second elements ofarr_a
andarr_b
. It is equivalent tof3(&arr_a[1], &arr_b[1]);
Again, nothing is copied. The functionf3
loads the value ofarr_a[1]
, then does a few local assignments. Likef1
, 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
.
- From C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1) (E2)))..