繁体   English   中英

将内存转换为结构指针

[英]Casting memory into a struct pointer

当我做的事情:

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

我没有得到正确的价值;

但当我做的事情如下:

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

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

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

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

  1. 在本地更改指针

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

    a是指针,此函数更改指针a 它不会更改a指向的对象。 它也不会改变bb指向的对象。

  2. 更改对象指向

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

    *a = *p执行深层复制。 它将p指向的对象复制到a指向的对象上。 由于b指向同一个对象作为ab也将看到这些变化。

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

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

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

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

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

在这两种情况下,你通过指针a按值。 a_func()更改指针本身不会反映在a_func() 换句话说, a内部a_func()是副本a外面,所以指针变化不会回国后外部的反射。

但是,更改内存的点将在外部可见。

在第一种情况下(没有* ),您在a_func()指定a自身。 正如刚刚解释的那样, a_func()返回后, a的新值将丢失。

在第二种情况下(与* ),复制从存储器[a memory location]所述存储器通过指向a 这意味着,存储器a点必须是有效的:要么它必须是在堆栈上,或在堆上动态分配的。 传递未初始化的struct my_struct *指针迟早会导致崩溃。

返回后,您可以访问通过传递给a_func() a指针复制的数据。

正确使用带有局部变量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!

一个破碎的例子:

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!

它与尝试在函数内部将整数从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保持的地址的内容,将其分配给内存位置,依此类推......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM