Reputation: 1215
When I do something like:
struct my_struct {
uint32_t n;
double d;
uint64_t *ptr;
size_t val;
};
struct my_struct a;
and in a function:
void a_func(struct my_struct *a) {
a = (struct my_struct *) [a memory location];
}
I do not get correct values in a;
but when I do something like:
void a_func(struct my_struct *a) {
*a = *(struct my_struct *) [same memory location];
}
I get correct values in the struct;
Any reasonable explanation for this?
Upvotes: 2
Views: 3410
Reputation: 22981
Lets look at three different cases:
Change pointer locally
void foo(S *a) {
a = p;
}
S* b;
foo(b);
a
is a pointer and this function changes the pointer a
. It does not change the object a
is pointing to. It also does not change b
or the object b
is pointing to.
Change object pointed to
void foo(S *a) {
*a = *p;
}
S* b = ...;
foo(b);
*a = *p
performs a deep copy. It copies the object pointed to by p
over the object pointed to by a
. As b
points to the same object as a
, b
will also see these changes.
Get pointer for usage outside the function
void foo(S **a) {
*a = p;
}
S* b;
foo(&b);
Now the function foo
accepts a pointer to a pointer. By writing *a = p
we change the pointer pointed to by a
to p
. This can be used to retrieve the pointer p
as b
will be the same as p
after the call to foo
.
Upvotes: 2
Reputation: 3069
It's the same as trying to change an integer from 3 to 5 inside a function and then failing. Check the following example:
#include <stdio.h>
void func( int a ) {
a = 5;
}
int main ( ) {
int x = 3;
func( x );
printf( "%d", x );
// prints 3 not 5
return 0;
}
This is because, when you pass x
variable into func
here, you pass its value, that is 3
; func
creates a variable named a
, assigns it with the passed value 3
, assigns it again with the value 5
. No change has been made to x
there, so x
still is just 3
.
If you were to pass the address of x
as a value to some other function that takes an address as an argument, then access the contents of that address and change it, then you'd be able to remotely change the x
, as in the following example:
#include <stdio.h>
void anotherfunc( int * a ) { // a is an address-holding variable
*a = 5; // *a is the content of that address and we are changing it to 5
}
int main ( ) {
int x = 3;
func( &x ); // passing the address of the variable x
printf( "%d", x );
// prints 5 now
return 0;
}
Same story for your case, only with one further step of referencing/dereferencing. If you want to make the first version work out, make changes similar to the following:
void a_func(struct my_struct ** a) { // added an asterisk
*a = (struct my_struct *) [a memory location];
}
// ...
int main( ) {
// ...
struct my_struct * x;
a_func( &x );
// ...
return 0;
}
Here, the a_func
takes the address of an address-holding variable (pointer) as an argument, and stores that inside a newly created variable called a
, which is a variable that holds address to an address to a struct my_struct
. Then it accesses the contents of the address a
holds, assigns that with a memory location, and so on...
Upvotes: 0
Reputation: 7227
I assume you call that function and then try to use the a
parameter after the function returned, e.g.
a_func(a);
printf("a->n: %u", a->n);
In both cases, you pass the pointer a
by value. Changing the pointer itself in a_func()
will not be reflected outside of a_func()
. Put another way, a
inside of a_func()
is a copy of a
outside, so changes to the pointer will not reflected outside after returning.
Changing the memory a points to will be visible outside, though.
In the first case (without *
), you assign a
itself in a_func()
. As just explained, the new value of a
will be lost as soon as a_func()
returns.
In the second case (with *
), you copy the memory from [a memory location]
the memory pointed to by a
. This means, that the memory a
points to has to be valid: either it has to be on the stack, or dynamically allocated on the heap. Passing an uninitialized struct my_struct *
pointer will lead to crashes sooner or later.
Once you return, you can access the data copied via the a
pointer you passed to a_func()
.
Example for correctly using the copy version (with *
) with a local variable a
:
struct my_struct a; // Allocate a my_struct object on the stack.
a_func(&a); // Copy data from [some memory location] into a.
printf("a.n: %u", a.n); // Access and use the newly copied data in a.
Another correct version with a
allocated on the heap:
// Allocate a my_struct object on the heap and make a point to that memory.
struct my_struct *a = malloc(sizeof(my_struct));
a_func(a); // Copy data from [some memory location] into a.
printf("a->n: %u", a->n); // Access and use the newly copied data in a.
free(a); // Take care to free the allocated memory when finished!
A broken example:
struct my_struct *a; // An uninitialized pointer!
a_func(a); // The memory location a points to is overwritten - BUG!
printf("a->n: %u", a->n); // May still work but you corrupted your memory with
// the previous function call. This will lead to crashes!
Upvotes: 1