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

时间:2010-11-11 20:30:41

标签: c parameter-passing dynamic-memory-allocation

我正在尝试了解如何通过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.

这两个项目有什么不同?

5 个答案:

答案 0 :(得分:6)

C是按值传递,它不提供传递引用。 在你的情况下,指针(不是它指向的)被复制到函数paramer(指针通过值传递 - 指针的值是一个地址)

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

答案 1 :(得分:3)

实际上并没有太大区别,除了第一个被打破。 :)(嗯,两者都是,但第一个更多的是打破了。)

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

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

第一种情况:

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

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

答案 2 :(得分:1)

您希望修改nmain的值,而不是n 指向的值,因此您需要传递一个指向它的指针。由于n中的main类型为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;
}

答案 3 :(得分:0)

nos发布的答案是正确的。

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

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

答案 4 :(得分:0)

看,第一个项目发生了什么。

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

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

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

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

现在,分配一些内存:

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

将值分配给已分配的var:

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

返回。 alocar():: n只在执行alocar()时才被删除。

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

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