【问题标题】:double pointer vs single pointer双指针与单指针
【发布时间】:2012-12-04 12:34:58
【问题描述】:

有人可以向我解释/解释为什么下面代码 sn-p 中 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;
}

【问题讨论】:

  • 请注意,程序格式错误,因为局部变量的地址被超出其范围使用。
  • 我注意到了 test2 中的缺陷,但我故意将其保留在这里,因为它举例说明了要避免的危险情况。感谢所有响应者的启发..
  • 我推荐这个有趣的阅读:meta.slashdot.org/story/12/10/11/0030249/… :) 在底部你可以找到一个与 C 相关的问题。

标签: c pointers


【解决方案1】:

在 C 中,参数是按值传递的。这意味着在test1 中,当您传递pp 时,会复制指针,而当您更改它时,会复制到副本,而不是指针本身。使用 test2 时,副本是双指针,但是当您取消引用并在此处分配时

*pp = &myVar;

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

【讨论】:

  • 这并不“危险”。这只是错误的、破碎的、未定义的行为。它不会工作,除非在一些非常罕见的测试用例中,星星正好对齐以使其发生工作。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    注意

    int myVar = 9999;
    *pp = &myVar;
    

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

    【讨论】:

    • 不,OP 想要更改值。
    【解决方案4】:

    因为f(x)不能改变x的值,无论x是int、float还是指针。

    【讨论】:

      【解决方案5】:
      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;
      }
      

      现在,这被严重破坏了。这个函数确实返回了一个指向调用者的指针。但它返回一个指向对象的指针,该对象在函数返回时立即超出范围。这被称为未定义的行为。不要这样做。永远不要从函数中传递出一个指向该函数中定义的局部变量的指针。

      【讨论】:

        【解决方案6】:

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

        *pp = myVar;
        

        改为。

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

        【讨论】:

          【解决方案7】:
          int* p1;
          
             p1 = &i;
          
             test1(p1);  //1st
          
             test2(&p1);  //2nd
          

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

          说明:

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

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

          【讨论】:

            猜你喜欢
            • 2023-03-14
            • 1970-01-01
            • 1970-01-01
            • 2020-10-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-20
            • 1970-01-01
            相关资源
            最近更新 更多