Domanda

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?

È stato utile?

Soluzione

Lets look at three different cases:

  1. 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.

  2. 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.

  3. 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.

Altri suggerimenti

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!

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...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top