[英]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中得到了正确的值;
对此有任何合理的解释吗?
让我们看看三种不同的情况:
在本地更改指针
void foo(S *a) { a = p; } S* b; foo(b);
a
是指针,此函数更改指针a
。 它不会更改a
指向的对象。 它也不会改变b
或b
指向的对象。
更改对象指向
void foo(S *a) { *a = *p; } S* b = ...; foo(b);
*a = *p
执行深层复制。 它将p
指向的对象复制到a
指向的对象上。 由于b
指向同一个对象作为a
, b
也将看到这些变化。
获取在函数外部使用的指针
void foo(S **a) { *a = p; } S* b; foo(&b);
现在函数foo
接受指向指针的指针。 通过编写*a = p
,我们改变指针指向a
以p
。 这可用于检索指针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.