将内存转换为结构指针

时间:2014-04-19 12:19:10

标签: c struct casting

当我做类似的事情时:

struct my_struct {
    uint32_t n;
    double   d;
    uint64_t *ptr;
    size_t   val;
};

struct my_struct a;

并且在一个函数中:

void a_func(struct my_struct *a) {
    a = (struct my_struct *) [a memory location];
}

我在a;

中没有得到正确的值

但是当我这样做时:

void a_func(struct my_struct *a) {
    *a = *(struct my_struct *) [same memory location];
}

我在struct中获得了正确的值;

对此有任何合理的解释吗?

3 个答案:

答案 0 :(得分:2)

让我们看看三种不同的情况:

  1. 在本地更改指针

    void foo(S *a) {
        a = p;
    }
    S* b;
    foo(b);
    

    a是一个指针,此函数更改指针a。它不会更改a指向的对象。它也不会更改b或对象b指向。

  2. 更改指向

    的对象
     void foo(S *a) {
         *a = *p;
     }
     S* b = ...;
     foo(b);
    

    *a = *p执行深层复制。它将p指向的对象复制到a指向的对象上。由于b指向与a相同的对象,b也会看到这些更改。

  3. 获取在函数外使用的指针

     void foo(S **a) {
         *a = p;
     }
     S* b;
     foo(&b);
    

    现在函数foo接受指向指针的指针。通过编写*a = p,我们将a指向的指针更改为p。这可用于检索指针p,因为b与调用p后的foo相同。

答案 1 :(得分:1)

我假设您调用该函数,然后在返回函数后尝试使用a参数,例如

a_func(a);
printf("a->n: %u", a->n);

在这两种情况下,都按值传递指针a。在a_func()中更改指针本身不会反映在a_func()之外。换句话说,a内的a_func()a外部的副本,因此返回后指针的更改不会反映在外面。

尽管如此,更改内存的点将在外面可见。

在第一种情况下(没有*),您可以在a中指定a_func()。如上所述,只要a返回,a_func()的新值就会丢失。

在第二种情况下(使用*),从[a memory location] a指向的内存中复制内存。这意味着,内存a指向必须有效:要么必须在堆栈上,要么在堆上动态分配。传递未初始化的struct my_struct *指针迟早会导致崩溃。

返回后,您可以访问通过传递给a的{​​{1}}指针复制的数据。

正确使用带有本地变量a_func()的副本版本(*)的示例:

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. 的另一个正确版本:

a

一个破碎的例子:

// 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!

答案 2 :(得分:0)

与尝试在函数内部将3到5的整数更改然后失败相同。请检查以下示例:

#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;
}

这是因为,当您在此处将x变量传递到func时,您会传递其值3; func创建一个名为a的变量,使用传递的值3指定它,再次使用值5指定它。没有对x进行任何更改,因此x仍然只是3

如果您要将x的地址作为值传递给以地址作为参数的其他函数,则访问该地址的内容并进行更改,然后您就可以了远程更改x,如下例所示:

#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;
}

您的情况也是如此,只有一个参考/解除引用的步骤。如果要使第一个版本正常工作,请进行类似以下的更改:

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;
}

这里,a_func将地址保持变量(指针)的地址作为参数,并将其存储在一个名为a的新创建变量中,该变量是一个保存地址的变量struct my_struct的地址。然后它访问地址a保持的内容,将其分配给内存位置,依此类推......