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
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 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.
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.
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.
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)))..
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 function deals with copies of the 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 this 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 gets 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.
Related
I understand that it's bad practice to do like that, it's just interesting for me to discover language's fratures.
I have already asked this question, where I need to increment value of variable. But now I don't want to change x variable value.
Here is the code
#include <stdio.h>
int foo(int *px) {
*px = *px - 1;
return *px * 2;
}
int main() {
int res;
int x = 4;
res = foo((x--, &x));
printf("%d\n", res);
return 0;
}
I want to pass pointer to x - 1 value as argument, but not to change x value. Also if it's possible, it's interesting for me to know if I can do this in one function call.
If I've understood you correctly, you want to do something like this I guess :
res = foo(&(x - 1));
But you can't :
When you try to access the address of x - 1 you will get an error because you are trying to access the address of a temporary variable x - 1 (variable which is not actually stored).
I want to pass a pointer to x - 1 value as an argument, but not to change x value.
If you want to do this, you need to store x - 1 in another variable and send the address of that:
int var = x - 1;
res = foo(&var);
Note:
I think I have mentioned some points about lvalue and rvalue in that answer. So technically x - 1 is a rvalue here. So you &(rvalue) is not possible.
So, the argument to foo needs to be a pointer to some int object which contains the value x-1. If you don't want that object to be x itself, then necessarily you have to create another one somehow.
The simplest approach is to just define it as a temporary variable, as in
Sai Sreenivas's answer: int var = x - 1; foo(&var);. If you want to avoid polluting your namespace with the variable var, you can enclose everything in a set of braces so that it is a separate compound statement:
int x = 4;
int res;
{
int var = x - 1;
res = foo(&var);
}
int var = 17; // unrelated to the previous var
Another approach, less readable but more compact, is to use a compound literal:
res = foo(&(int){x-1});
This creates a temporary object of type int that has no name, initializes it with the value x-1, and passes its address to foo.
Note that if foo modifies the value of *px, those modifications will be made to this temporary object. But you will have no way of retrieving its new value after foo returns, so it is effectively lost.
Compound literals are a somewhat more obscure feature of the language, so some readers of your code may have trouble recognizing what's going on. Thus I'd suggest avoiding this approach unless there is a compelling reason to use it, beyond just brevity.
All you can do is to keep the x value the same after the function finishes. Since you can not track what happens to x before it is pushed as parameter, you can not revert the changes made. What i mean by this is, if in the function you do *px = *px - 123 you can revert it back, but you can not see how the calling statement looks like (it can be foo((x = x-1, &x)); or foo((x = x+1, &x));) and you will have no information inside the foo function about how the operation changed x.
But i might have a solution for it. A macro (well experimenting means experimenting please never use something like this xD )
int foo (int* px)
{
// what you do in the function, you undo in the function.
*px = *px - 1;
int nReturnValue = *px;
*px = *px + 1;
return nReturnValue;
}
#define bar(x, number) \
printf("%d\n", foo((x = x + number, &x))); \
x = x - number;
int main()
{
int x = 5;
bar(x, 10);
printf("Now the value is the same: %d", x);
return 0;
}
NOTE: THIS CODE SHOULD ONLY HAVE EXPERIMENTAL PURPOSES, DO NOT USE!
I want to pass pointer to x - 1 value as argument
There are actual two options, which you could mean with that statement.
Method A:
If you mean you want to use &(x - 1), this would attempt to gain a pointer to rvalue 3 as (x - 1) gains 3, which isn't possible. An rvalue does not have an address because it is not stored in an lvalue object in memory, which you could reassign with any other int value. & can only be used at lvalue objects.
Method B:
If you want to get a pointer which points one size of the object before a scalar object, doing so invokes undefined behavior. It is even undefined behavior for the first element of an array.
It would only be valid if x would be something like x[1] and denote an array element after the first one, which isn't the case here.
You can't store an int value at this location inside of the function, so I don't understand how that would makes sense either.
How can I create a pointer to a new object (which is decremented value of a variable) as argument in C?
The only way, to achieve this to create a separate variable in the caller, assign x + 1 to this one and pass a pointer to this variable to foo.
int y = x + 1;
res = foo(&y);
Here is an example of what I mean. This example is without using pointers and the variables do not swap.
void swap(int x, int y);
main()
{
int a = 33, b = 55;
swap (a, b);
printf("a = %d, b = %d\n", a, b);
}
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
Now if you use pointers the variables a and b swap. Why is it that it only works with pointers?
C is a pass-by-value language. Always. That means with this:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
you're swapping the values of x and y, obtained from the values passed to the function. When you invoke like this:
int main()
{
int a = 33, b = 55;
swap (a, b); // passing values of a and b
printf("a = %d, b = %d\n", a, b);
}
the values of a and b are passed. So this is your problem. The solution is to make the values passed something that can be used to modify the caller's variables. If you want to modify those variables they need to somehow be addressable from the called code. Hmmm...
The mechanism is called "pass by address", and though it sounds fancy in reality it isn't. It is simply a retooling of pass-by-value, but with a different value type. Whereas before we were passing values of type int we will instead pass addresses of the integer variables and declare the formal parameters to be pointers to int instead. Make no mistake. They're still values, but not of the basic int type. Rather the values passed are addresses of int variables. To access the data at those addresses pointers are used in conjunction with the dereference operator (of which there are several kinds, only one shown here):
void swap(int *ptrToX, int *ptrToY)
{
int temp = *ptrToX; // dereference right, store value in temp
*ptrToX = *ptrToY; // dereference both, assigning value from right to left.
*ptrToY = temp; // dereference left, assign temp value
}
and invoked like this:
int main()
{
int a = 33, b = 55;
swap (&a, &b); // passing addresses of a and b
printf("a = %d, b = %d\n", a, b);
}
Note: Often ill-quoted as the exception to pass-by-value is passing an array. Though the phrase "decays to a pointer" is thrown about like confetti on New Years Eve, I abhor that vernacular. The verb itself implies a functional operation where there is, in fact, none.
The language specifies the value of an array used in an expression is the address of its first element. In other words, its "value" is already an address and as such can simply be passed by-value to a function expecting a pointer to the same base type. Because it is an address, the receiving parameter (a pointer, because thats what holds address values) can then be used to modify the array content from the caller. Second only to multiple levels of indirection (pointers to pointers, etc) it is easily the hardest thing for people new to C to wrap their head around, yet it is important you do so.
When you call swap, the value of the variables a and b are passed to it. These values are passed by copy. When you swap those values in swap, you are only swapping local copies of a and b.
When you pass pointers to variables to a function, you are able to modify the values of the variables in the calling function.
That's called pass by value.
You are just passing values of a & b to the swap function. The swap function copies that value into its variables x & y which are different from a & b. Hence in swap you are working on x & y instead of a & b.
On the other hand, when you pass pointers, you are passing the address where a & b are stored. Your x & y point to the same address and hence you are manipulating the content at that address where a & b are stored. Hence, main gets to see the updated values.
This is the best example to define the advantage/use of function call by reference V/s call by value
In the main() function the two variables has the value
int a = 33, b = 55;
so using these variables in the swap(a,b) function, it just passes the values to the function definition where
void swap(int x, int y)
{
int temp;
temp = x;
x = y;
y = temp;
}
they declare again two variables x,y and the values in this variables are swapped. But the variables x and y are only known to function swap() after execution of the swap() function that variables are no longer valid. So nothing happens to the variables a,b in the main function.
So in order to swap variables using function you've to use
swap(&a,&b);
in main() function , and modify function swap()
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
Which passes the address of variables a and b , and the pointers are used to swap the variables,It gets swapped effectively. Since pointer points to the address of the variables the value of the variables get changed.
For more google "call by referece and call by value in c"
I have a problem, I have a function and I do not understand a specific thing. The function is:
int F( int* x , int n ){
int i , m=0
for (i=0;i<n; i++){
m=x[ i ] + m;
}
return m * m ;
}
I call the function with a pointer and with an integer. Later I do a "for", but I do not understand the line:
m=x[ i ] + m;
Because x is a pointer not an array.
Could you please help me.
Then x points to the memory position then to +1. For example if i call the function with
n=10
x=&n
F(x,n)
the function returns somenthing strange.
X points to the position memory to n, later to the position memory to n+1??
Since x is a pointer, when you pass the array to the function, x points to the first element of the array. Since array is a contigous allocation of memory, The pointer can be made to point to consecutive elements of the array. Thats why
m=x[i]+m
x[i] implies to the ith index from the first element of the array
main()
{
int x[10]={1,2,3,4,5,6,7,8,9,10},sum;
sum=function(x,10);
return 0;
}
This function sends the array to the function, with 10, the size of the array
Arrays are represented as contiguous memory and the array variable gets interpreted as a pointer to the base of that memory (e.g. &(x[0])). Array offset syntax gets translated into pointer arithmetic.
See this post, which clarifies the difference between pointer and arrays:
[] - indexed dereference
a[b] is equivalent to *(a + b). This means a and b must be a pointer to an array element and an integer; not necessarily respectively, because a[b] == *(a + b) == *(b + a) == b[a]. Another important equivalence is p[0] == 0[p] == *p.
The function might be equivalently declared (with more clarity perhaps):
int F(int x[], int n);
and you would call it like so:
int data[3] = {1, 2, 3};
int value = F(data, 3);
I am translating C code to another language. I am confused about pointers.
Say I have this code. The function foo, calls function bob, and they are both pointers.
double
*foo(double *x, double *init, double *a){
double *y = (double*)malloc(5*sizeof(double));
double *z = (double*)malloc(5*sizeof(double));
double *sum, *update;
sum = (double*)bob(y, z) //<---Q1: why y and z don't need stars in front of them?
//I thought they are pointers?
for (i<0; i<5; i++){
z[i]=y[i] //Q2: howcome it's ok to assign y to z?
} //aren't they pointer?(i.e.hold memory address)
}
double
*bob(*arg1, *arg2){
something...
}
So,
1) Why y and z don't need stars in front of them, isn't y and z just address?
2) Why sum doesn't have a star, I thought sum is declared as a pointer.
3) Why it's ok to assign y to z?
I've learned these, but they've soooo long, could someone give me a hint?
double
*foo(double *x, double *init, double *a){
// x is a pointer to a double, init is a pointer to a double, a is a pointer to a double
// foo is a function returning a pointer to a double
// and taking three pointers to doubles as arguments
double *y = (double*)malloc(5*sizeof(double));
// y is a pointer to a double. It is assigned a pointer returned by malloc.
// That pointer returned by malloc points to memory space for 5 doubles.
double *z = (double*)malloc(5*sizeof(double));
// z is a pointer to a double. It is assigned a pointer returned by malloc.
// That pointer returned by malloc points to memory space for 5 doubles.
double *sum, *update;
// sum and update are pointers to doubles
sum = (double*)bob(y, z) //<---Q1: why y and z don't need stars in front of them?
//I thought they are pointers?
// sum (whose type is pointer to double)
// is assigned a pointer to double returned by bob
for (i<0; i<5; i++){
y[i] = z[i] //and are z and y pointers?!?!
// y[i] === *(y+i)
// (y + i) points to the i-th element in the space previously allocated by malloc
// *(y + i) dereferences that pointer
// equivalently, y[i] accesses the i-th element from an array
}
if(sum<0)
z=y //Q2: howcome it's ok to assign y to z?
//aren't they pointer?(i.e.hold memory address)
// after the assignment, z contains the same address as y (points to the same memory)
}
double
*bob(*arg1, *arg2){
something...
}
Values y and z don't need stars because adding a star dereferences them, and you want to pass the pointer not the value.
Again, you want the pointer and not the value. Although from the code it appears you actually DO want the value, so there probably should be a star there.
You can assign a pointer to another pointer, this means change the address that the pointer points to. So when y=z, y now points where z points.
They don't need a star because you do not dereference them, but pass as pointers.
You can compare pointer, but that's probably not what you want.
Assigning pointers is okay, note, though, that it's not the same as copying values.
Ans for Q1: You are passing y and z to another function which take in pointers as arguments, why would you pass the value of the pointer?
Ans2: They are pointers and you are assigning one to another
Basic pointer notions:
double a = 42.0; // a is a double
double b; // b is a double
double *x; // x is a pointer to double
x = &a; // x is the pointer, we store the address of a in pointer x
b = *x; // *x is the pointee (a double), we store the value pointed by x in b
// now b value is 42.0
With regard to 2) and why z[i] = y[i] is acceptable, I think it best to point you to this page which describes arrays and pointers in some detail, especially 2.1 through 2.8. What's happening in that particular expression (not necessarily in order) is start at location y, fetch the pointer, add i to the pointer, then fetch the value pointed to at that location. Start at z, fetch the pointer, add i to the pointer, and assign the value (y[i]) to that location.
The following code is trying to make a point (probably the difference between arrays and local variables) I only have a vague idea on the code. Would someone please elaborate? Thanks
void doit(int x[10], int y) {
y = 30;
x[0] = 50;
}
void main(void) {
int x[10];
int y = 3;
x[0] = 5;
printf("x[0] is %d and y is %d\n", x[0], y);
doit(x, y);
printf("x[0] is %d and y is %d\n", x[0], y);
}
It is showing that arrays are not really passed directly to functions - instead, the address of the first member of the array is passed.
That means that if the called function modifies the array that was "passed", it is modifying the original array in the caller.
On the other hand, when the called function modifies the plain int parameter y, it is modifying a local copy of the variable, and the change is not reflected in the caller.
In C, all arguments are passed by value. However, arrays decay into a pointer to the first element to the array when they get passed; the result is effectively as if the array was passed by reference.
In your code, the doit() function can mutate the array pointed to by x, but it cannot mutate the simple int value in y.
y is passed by value meaning that a temporary copy is created, you have to pass it as a pointer to modify it:
void doit(int x[10], int* y) {
*y = 30;
x[0] = 50;
}
Declaring an array is also not really needed. The compiler anyway understands only that it is a pointer and does (usually) not check the boundaries.
void doit(int* x, int* y) {
*y = 30;
x[0] = 50;
}
Local variables are passed as value where as in arrays the reference is passed not the actual values. so when you change the value in child array the parent array will get changed. Arrays are same as pointers in using the reference