【问题标题】:I thought double pointers were required when wanting to change values我认为想要更改值时需要双指针
【发布时间】:2014-05-20 02:05:08
【问题描述】:

在研究双指针时,普遍的共识似乎是当想要更改任何变量的值并在从函数返回时保留新值时,需要传入其指针值。

如果已经使用指针,则需要传入双指针。

以下示例处理代码主要部分中的指针,将相同的指针传递给函数,更改其值并且新值在 main 中可见。

根据我读到的内容,应该需要一个双指针,否则新值在 main 中将不可见。

如果这确实有效,那么如何修改它以显示需要双指针?

void func1(int *z)
{
(*z)++;
printf("z=%d\n", *z);
}   


int _tmain(int argc, _TCHAR* argv[])
{

int x = 100;
int *y = &x;
printf("y=%d\n", *y);
func1(y);
printf("y=%d\n", *y);
return 0;
}

【问题讨论】:

  • 您正在传递一个 int 的地址,然后递增该地址的值。正如您所说,为什么需要“双指针”?
  • 这个问题非常令人困惑。很少需要“双指针”或指向指针的指针。习惯性使用是混乱的标志。如果要连贯,这个问题的第一句话需要分成两三个部分。为什么你需要在已经有效的事情中寻求证明额外的复杂性是必要的?
  • 如果你想传递一些东西给一个要修改的函数,你需要传递一个指向它的指针。如果你想让它修改int,你需要一个int*。如果要修改int*,则需要int**y 具有 int* 类型,它允许您间接修改 int(在这种情况下为 x

标签: c function pointers pointer-to-pointer


【解决方案1】:

如果您要更改 y 指向的内容,则需要一个指向指针的指针,例如:-

static int blah = 42;
void func1(int **z)
{
(*z) = &blah;
printf("z=%d\n", *(*z));
}   

int _tmain(int argc, _TCHAR* argv[])
{

int x = 100;
int *y = &x;
printf("y=%d\n", *y);
func1(&y);
// y does not point to x anymore;
printf("y=%d\n", *y);
return 0;
}

在您的原始版本中您正在更改 x,在此您将单独留下 x 并更改指针 y。

通常你不会经常使用它们(你会不时使用它们),但更一般地说,指向指针的指针是一种更有趣的类型。

所以...

typedef struct 
{
   int *y;
} Z;

void f(Z *z)
{
  z->y = &blah;
}

void main()
{
  int x;
  Z a;
  a->y = &x;
  f(&a);
}

所以这实际上是同一件事,但是现在您使用结构来保存指针,并且您将结构的指针作为“指向指针的指针”传递,除了现在它指向包含的结构的指针一个指向 int 的指针。

但你的名字更有趣一点:-

typedef struct 
{
  char *name;    
} Person;

static char* default_name = "blah";
void set_default_name_of_person(Person* person)
{
   person->name = default_name;
}

void main()
{
   Person person;
   set_default_name_of_person(&person);
}

现在您的代码开始看起来像您实际编写的内容。 (除了这有点人为的例子)

【讨论】:

  • #include void func1(int z) { int k=11; //(*z)++; *z=k; printf("z=%d\n", *z); } int main (int argc, char argv[]) { int x = 100; int *y = &x; printf("y=%d\n", *y);函数1(y); printf("y=%d\n", *y);返回0; }
【解决方案2】:

首先-说“指向指针”更清楚,因为“双指针”可以是double *

假设T 是某种类型,你有:

T t;
func( &t );

要让func 能够更改t,它必须知道t 的地址。对象的地址是指向该对象的指针(这是术语 pointer 的定义)。

所以函数签名必须是:

func( T *t_ptr )

在您的示例中,Tint。也许您对T 已经是指针类型的示例感到困惑。指针类型没有什么“魔法”。 int *int **int *** 是类型,就像 int 一样。相同的规则适用于所有这些。

如果Tint *,则函数签名必须类似于func( int **t_ptr_ptr ),以此类推。

【讨论】:

    【解决方案3】:

    指针很简单。只需将其视为一种地址。

    有一个盒子。这个盒子有一个号码牌,上面写着 1-101。

    方框是变量,车牌是指针,1-101是实际地址(抽象概念)。

    我可以给你盒子,你可以用纸填满它,但我也只能给你看车牌,你可以拿到盒子去填。

    假设有一个带有“pp1-100”的车牌,您找到了车牌架,但它是另一个带有“p1-100”的车牌。你再次找到持有人,可以找到盒子。

    这是“指向指针的指针”。


    为什么我们需要双/三/四指针?因为我们想要它,出于各种原因(但谁在乎呢?)。

    【讨论】:

      【解决方案4】:

      如果将局部变量的地址分配给单个指针,它仍然可以工作。 所以基思尼古拉斯的开场白很有意义,应该被接受为一个有效的答案。 如果您需要更改原始地址中的值,则需要一个指针,但如果您通过更改位置本身来更改值,则需要指向指针的指针。 您应该了解您正在按值传递指针,因此函数堆栈具有该指针变量(及其值)的副本。 通过取消引用 main 指针变量的副本,原始变量的值会发生变化,因为它是原始变量地址的副本。 但是,如果您将该 ponter 的副本指向不同的值,它将不会得到反映。通过取消注释 1 和 2(一次一个)来运行下面的代码以观察差异。观察原始变量 x 发生了什么

      #include <stdio.h>
      void func1(int *z)
      {
          int k=11;
      
      //*z=k;   //1
      //z=&k;    //2
      printf("z=%d\n", *z);
      }   
      
      
      int main (int argc, char* argv[])
      {
      
      int x = 100;
      int *y = &x;
      printf("y=%d\n", *y);
      func1(y);
      printf("y=%d\n", *y);
      printf ("%d",x);
      return 0;
      }
      

      【讨论】:

        【解决方案5】:

        您已使用该函数更改了x 的值,也称为*y

        您看到的代码 sn-ps 并没有尝试更改x 的值,而是实际上更改了y 的值,以便y 在函数调用后指向不同的东西。为了让函数改变y 的值,它需要一个指向y 的指针。由于y 已经是一个指针,所以你最终会得到一个指向指针的指针。

        这是您重写的代码以更改 y 指向的内容,以便在函数调用之后,y 指向 w 并且 printf 显示 333

        void func1( int **yptr, int *wptr )
        {
            *yptr = wptr;
        }
        
        int main( void )
        {
            int x = 100;
            int w = 333;
        
            int *y = &x;
            func1( &y, &w );
            printf( "*y=%d\n", *y );
        
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-06
          • 1970-01-01
          • 2013-12-15
          • 1970-01-01
          • 2014-11-14
          • 2010-10-28
          • 2012-02-27
          • 2020-11-02
          相关资源
          最近更新 更多