了解动态分配通过引用传递参数

Posted

技术标签:

【中文标题】了解动态分配通过引用传递参数【英文标题】:understand passing parameters by reference with dynamic allocation 【发布时间】:2011-05-08 17:19:00 【问题描述】:

我正在尝试了解如何在 C 语言中通过引用传递参数。 所以我写了这段代码来测试参数传递的行为:

#include <stdio.h>
#include <stdlib.h>

void alocar(int* n)
   n = (int*) malloc( sizeof(int));
   if( n == NULL )
      exit(-1);
   *n = 12;
   printf("%d.\n", *n);

int main()

   int* n;
   alocar( n );
   printf("%d.\n", *n);
   return 0;

这里是打印出来的:

12. 0。

示例 2:

#include <stdio.h>
#include <stdlib.h>

void alocar(int* n)
   *n = 12;
   printf("%d.\n", *n);


int main()

   int* n;
   n = (int*) malloc(sizeof(int));
   if( n == NULL )
      exit(-1);
   alocar( n );
   printf("%d.\n", *n);
   return 0;

打印出来了:

12. 12.

这两个程序有什么区别?

【问题讨论】:

指针不是整数。您的格式说明符应该是%p,而不是%d。在您的第一个示例中(现在您已了解原因),n 从未初始化,因此使用它会给您带来未定义的行为。任何事情都有可能发生。 关于未初始化的指针是正确的,但格式说明符本身在这些示例中是正确的。 【参考方案1】:

C 是按值传递,它不提供按引用传递。 在您的情况下,指针(不是它指向的内容)被复制到函数参数(指针按值传递 - 指针的值是地址)

void alocar(int* n)
   //n is just a local variable here.
   n = (int*) malloc( sizeof(int));
  //assigning to n just assigns to the local
  //n variable, the caller is not affected.

你想要这样的东西:

int *alocar(void)
   int *n = malloc( sizeof(int));
   if( n == NULL )
      exit(-1);
   *n = 12;
   printf("%d.\n", *n);
   return n;

int main()

   int* n;
   n = alocar();
   printf("%d.\n", *n);
   return 0;

或者:

void alocar(int** n)
   *n =  malloc( sizeof(int));
   if( *n == NULL )
      exit(-1);
   **n = 12;
   printf("%d.\n", **n);

int main()

   int* n;
   alocar( &n );
   printf("%d.\n", *n);
   return 0;

【讨论】:

我想这是一个观点问题,但我会说地址运算符可以通过引用传递值。 @Christoffer:这是一个事实上的术语,但它仍然是一个值。 这是真的。 C 不支持按引用传递。所以实际上我没有将地址传递给“aloca”,因为 n 不存储地址。 @adriano ,您确实将地址传递给 alloca,'n' 存储一个地址(但它不是 TO 'n' 的地址)alloca 收到该地址的副本,但更改副本不会t 更改原件。但是和第二个例子一样,你可以传递 'n' 的地址,允许 alloca 改变 main 中的 'n'。【参考方案2】:

其实差别不大,只是第一个坏了。 :)(嗯,两者都是,但第一个更坏)。

让我解释一下第二种情况会发生什么:

pointer-to-int 类型的变量 n 在堆栈上分配 一个int类型的新变量被分配到栈中,它的地址存储在变量n中 函数alocar被调用,传递变量n的副本,这是我们int类型变量地址的副本 该函数将n指向的int变量设置为12 该函数打印n (12) 所指向的变量的值 函数返回

第一种情况:

pointer-to-int 类型的变量 n 在堆栈上分配 函数 alocar 使用变量 n 的副本调用(该变量仍未初始化 - 包含未知值) 在内存中创建了一个 int 类型的新变量,并将函数 alocar 中变量 n 的本地副本设置为指向该新变量 变量(由函数的 n 的本地副本指向)设置为 12 并打印 函数返回,再次在 main() 函数中: 由于main中原来的n变量还没有初始化,它指向内存中的一个随机位置。因此打印内存中随机位置的值(这可能会使您的程序崩溃)。

另外,这两个程序都被破坏了,因为它们没有释放 malloc() 分配的内存。

【讨论】:

我知道这需要释放分配的内存。我通常释放它。我明白你的解释。你是对的。非常感谢!!! 很高兴我提供了帮助 :),还请记住,在 SE 上,每次您回答问题时,在您最喜欢的答案旁边打勾是礼貌的,以表明问题已解决(并获得一些美味的分数,高兴!:))。【参考方案3】:

你想修改mainn的值,而不是n所指向的,所以你需要传递一个指向它的指针。由于mainn的类型是int *,所以alocar的参数需要是int **类型:

void alocar(int **n)

  *n = malloc(sizeof **n); // note no cast, operand of sizeof
  if (!*n)
    exit(-1);

  **n = 12;
  printf("%d\n", **n);


int main(void)

  int *n;
  alocar(&n);
  printf("%d\n", *n);  // we've already tested against n being NULL in alocar
  free(n);             // always clean up after yourself
  return 0;

【讨论】:

【参考方案4】:

nos发布的答案是正确的。

另外请注意,当 main() 中的 printf 行尝试取消引用 main 的指针 n(从未设置)时,两个发布程序中的第一个实际上会在许多系统上崩溃:

   printf("%d.\n", *n);

【讨论】:

【参考方案5】:

看看,第一个程序发生了什么。

在调用 alocar 之前,我们在 main 中只有变量 n,指向一些未定义的地方:

 main()::n [  X--]--->(?)

(方括号中的值,未定义,标记为X)。然后我们调用 alocar,我们在 alocar 的作用域中有另一个变量,它有一个 origianl var 的副本。

 main()::n   [  X--]--->(?)
 alocar()::n [  X--]-----^

现在,分配一些内存:

 main()::n   [  X--]--->(?)
 alocar()::n [  *--]--->[   Y  ]

为分配的变量赋值:

 main()::n   [  X--]--->(?)
 alocar()::n [  *--]--->[  12  ]

返回。 alocar()::n 仅在执行 alocar() 时才会被移除。

 main()::n   [  X--]--->(?)
                        [  12  ]

main()::n 仍然指向某个未定义的位置...(可能存储值 0)并且没有人指向分配的位置。

【讨论】:

以上是关于了解动态分配通过引用传递参数的主要内容,如果未能解决你的问题,请参考以下文章

引用传递和动态内存分配之间有啥区别[关闭]

将数组动态分配到带有指针参数的函数中

转载二维数组的动态分配和参数传递

检测动态分配的对象?

Qt中的2D游戏:初始化怪物并将动态分配的数组作为指针参数传递[关闭]

如何复制动态分配的对象(具有一个类的 const 成员)