双指针vs单指针
有人可以向我解释/给出一个推理,为什么变量i在主函数中的值在下面的代码片段中不会通过函数test1改变,而它确实通过test2改变了? 我认为单个指针应该足以改变i的值。 为什么我们应该使用双指针?
#include void test1(int* pp) { int myVar = 9999; pp = &myVar; } void test2(int** pp) { int myVar = 9999; *pp = &myVar; } int main() { printf("Hej\n"); int i=1234; int* p1; p1 = &i; test1(p1); printf("does not change..., p1=%d\n",*p1); test2(&p1); printf("changes..., p1=%d\n",*p1); return 0; }
在C中,参数按值传递。 这意味着在test1
当你传递pp
,副本由指针组成,当你更改它时,对副本而不是指针本身进行更改。 对于test2
,副本是双指针,但是当你取消引用并在此处分配时
*pp = &myVar;
你正在改变所指向的东西,而不是改变pp
本身。 请注意, test2
中的此行为未定义,如此处的其他一些答案中所述
如果要更改T
类型变量的值,则必须在该类型( T*
)上使用指针。 由于您想要更改指针( T = int*
),您必须提供指向指针的指针( T* = int**
),否则您只需要更改副本。
注意
int myVar = 9999; *pp = &myVar;
将导致未定义的行为,因为pp
现在将包含退出函数后无效的局部变量的地址。
但是你没有改变i
的值,你正在改变pp
指向的地址,如果你只想改变i
的值,那么它足以将你的测试更改为:
void test3(int* pp) { int myVar = 9999; *pp = myVar; }
因为f(x)
不能改变x
的值,无论x是int,float还是指针。
void test1(int* pp) { int myVar = 9999; pp = &myVar; }
这个函数传递一个指针pp
。 该函数修改该指针。 但由于参数是按值传递的,因此调用者无法看到该修改。
你需要写这样的函数:
void test1(int* pp) { *pp = 9999; }
期望此函数的调用者传递int
变量的地址。 然后,该函数将int
值(在这种情况下为9999)写入该地址。 这是关键。 您传递了一个地址,然后您将值写入该地址。 你破碎的版本只是修改了地址。 你错过了间接。
当函数返回时,调用者可以观察对其地址传递给函数的int
变量的修改。 调用代码可能如下所示:
int i = 0; test1(&i); // pass address of int variable printf("%d\n", i); // prints the new value, 9999
void test2(int** pp) { int myVar = 9999; *pp = &myVar; }
现在,这是以非常严肃的方式打破的。 这个函数确实返回了一个指向调用者的指针。 但是一旦函数返回,它就会返回一个指向超出范围的对象的指针。 这被称为未定义的行为 。 不要这样做。 永远不要传递一个函数,一个指向该函数中定义的局部变量的指针。
pp = &myVar;
将myVar
的地址分配给指针pp
。 如果要更改pp
指向的值,请使用
*pp = myVar;
代替。
在回答第二个问题时,如果要更改指向的对象而不是更改现有对象的值,请将指针传递给指针。
int* p1; p1 = &i; test1(p1); //1st test2(&p1); //2nd
简单来说,第1个是pass by value
,第2个是pass by address
。
说明:
在第一种情况下,传递指针实际上是test1
内部的p
的副本,因此test1
的pp
是该函数的本地,并且它是在test1
创建的。 你分配了地址,当function失效时,它就被破坏了。
但在第二种情况下,您将指针的地址传递给test2
函数。 因此test2
的指针pp
将指向main中的指针p
,因此使用*pp = &myVar
为pp
分配新地址将自动设置p
的值(因为您正在取消引用指针)。 因此,当test2
终止时, p
将指向修改的位置。