双指针vs单指针

时间:2012-12-04 12:34:59

标签: c pointers

有人可以向我解释/给出一个推理,为什么在下面的代码片段中main函数中的变量i的值不会通过函数test1改变而它通过test2改变了吗?我认为单个指针应该足以改变i的值。为什么我们应该使用双指针?

#include <stdio.h>

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

7 个答案:

答案 0 :(得分:6)

在C中,参数按值传递。这意味着在test1中,当您传递pp时,副本由指针组成,当您更改它时,更改将更改为而非指针本身。使用test2副本是双指针,但是当您取消引用并在此处分配时

*pp = &myVar;

您正在改变所指向的内容,而不是更改pp本身。请注意,test2中的此行为未定义,如此处的其他一些答案中所述

答案 1 :(得分:4)

但是你没有改变i的值,你改变了pp指向的地址,如果你只想改变i的值那么它就足够了将测试更改为:

void test3(int* pp)
{
   int myVar = 9999;
   *pp = myVar;
}

答案 2 :(得分:3)

如果要更改T类型变量的值,则必须使用该类型的指针(T*)。由于您想要更改指针(T = int*),您必须提供指向指针(T* = int**)的指针,否则您只会更改副本。

请注意

int myVar = 9999;
*pp = &myVar;

将导致未定义的行为,因为pp现在将包含退出函数后无效的局部变量的地址。

答案 3 :(得分:2)

因为f(x)无法更改x的值,无论x是int,float还是指针。

答案 4 :(得分:2)

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

现在,这种情况非常严重。这个函数确实返回了一个指向调用者的指针。但是一旦函数返回,它就会返回一个指向超出范围的对象的指针。这被称为未定义的行为。不要这样做。永远不要传递一个函数,一个指向该函数中定义的局部变量的指针。

答案 5 :(得分:1)

int* p1;

   p1 = &i;

   test1(p1);  //1st

   test2(&p1);  //2nd

简单来说,第一个是pass by value,第二个是pass by address

描述:

在第一种情况下,传递指针实际上是ptest1的副本,因此test1内的pp是该函数的本地,并且它是在test1中创建的。你分配了地址,当功能失效时,它就被破坏了。

但在第二种情况下,您将指针的地址传递给test2函数。因此pp中的指针test2将指向main中的指针p,因此使用pp*pp = &myVar分配新地址将自动设置{的值{ {1}}(因为你要取消引用指针)。因此,当p终止时,test2将指向已修改的位置。

答案 6 :(得分:1)

pp = &myVar;myVar的地址指定给指针pp。如果要更改pp指向的值,请使用

*pp = myVar;

代替。

在回答第二个问题时,如果要更改指向的对象而不是更改现有对象的值,请将指针传递给指针。