C 双指针与单指针

C 双指针与单指针,c,pointers,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; } i

有人能解释/给我一个理由,为什么在下面的代码片段中,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;
}
#包括
无效测试1(int*pp)
{
int-myVar=9999;
pp=&myVar;
}
无效测试2(整数**pp)
{
int-myVar=9999;
*pp=&myVar;
}
int main()
{
printf(“Hej\n”);
int i=1234;
int*p1;
p1=&i;
试验1(p1);
printf(“不改变…,p1=%d\n”,*p1);
测试2(&p1);
printf(“更改…,p1=%d\n”,*p1);
返回0;
}

在C中,参数是按值传递的。这意味着,在
test1
中,当您通过
pp
时,指针将被复制,而当您更改它时,将更改为副本而不是指针本身。使用
test2
时,副本是一个双指针,但当您在此处取消引用并赋值时

*pp = &myVar;

您正在更改指向的内容,而不是更改
pp
本身。请注意,
test2
中的这种行为是未定义的,正如这里的一些其他答案所记录的那样

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

注意

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

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

int* p1;

   p1 = &i;

   test1(p1);  //1st

   test2(&p1);  //2nd
简单地说,第一个是
传递值
,第二个是
传递地址

说明:

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


但在第二种情况下,您将指针的地址传递给
test2
函数。因此
test2
中的指针
pp
将指向main中的指针
p
,因此使用
*pp=&myVar
pp
分配一个新地址将自动设置
p
的值(因为您正在解除对指针的引用)。因此,当
test2
终止时,
p
仍将指向修改的位置。

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

*pp = myVar;
相反


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

但您没有更改
i
的值,而是更改
pp
指向的地址,如果您只想更改
i
的值,那么将测试更改为:

void test3(int* pp)
{
   int myVar = 9999;
   *pp = myVar;
}
此函数被传递一个指针
pp
。该函数修改该指针。但由于参数是按值传递的,因此调用方看不到该修改

您需要这样编写函数:

void test1(int* pp)
{
   *pp = 9999;
}
int i = 0;
test1(&i); // pass address of int variable
printf("%d\n", i); // prints the new value, 9999
此函数的调用方应传递
int
变量的地址。然后,函数将
int
值(本例中为9999)写入该地址。这是关键。向您传递一个地址,然后向该地址写入一个值。你的坏版本只是修改了地址。你错过了间接的过程

当函数返回时,调用方可以观察对
int
变量的修改,该变量的地址已传递给函数。调用代码可以如下所示:

void test1(int* pp)
{
   *pp = 9999;
}
int i = 0;
test1(&i); // pass address of int variable
printf("%d\n", i); // prints the new value, 9999


现在,这是在一个非常严重的方式打破。此函数确实返回指向调用方的指针。但它返回一个指向一个对象的指针,该对象在函数返回后立即超出范围。这被称为未定义的行为。不要这样做。切勿从函数中传出指向该函数中定义的局部变量的指针。

请注意,由于局部变量的地址超出了它的使用范围,程序的格式不正确。我注意到test2中的缺陷,但我在这里故意不去碰它,因为它举例说明了需要避免的危险情况。感谢所有回复者的启发……我建议大家阅读以下有趣的内容:)在底部,你可以找到一个与C相关的问题。它并不“危险”。这只是错误的、破碎的、未定义的行为。它不会工作,除非在一些非常罕见的测试用例中,星星正好对齐,使其正常工作。不,OP想要更改值。