当我做类似的事情时:
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中获得了正确的值;
对此有任何合理的解释吗?
答案 0 :(得分:2)
让我们看看三种不同的情况:
在本地更改指针
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
,因为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
保持的内容,将其分配给内存位置,依此类推......