通过引用传递并使用malloc

时间:2019-03-24 19:59:53

标签: c malloc

我是C编程语言的初学者。我有点理解堆栈内存,堆内存,malloc,指针和内存地址的一般定义。但是我对理解何时在实践中使用每种技术以及它们之间的区别感到不知所措。

我已经编写了三个小程序作为示例。它们都做相同的事情,我想对它们之间的区别进行一些评论和解释。我确实意识到这是一个幼稚的编程问题,但是我希望在这里连接一些基本点。

Program 1

void B (int* worthRef) {
  /* worthRef is a pointer to the
     netWorth variable allocated
     on the stack in A.
  */
  *worthRef = *worthRef + 1;
}

void A() {
  int netWorth = 20;
  B(&netWorth);

  printf("%d", netWorth);  // Prints 21
}

int main() {
  A();
}

Program 2

int B (int worthRef) {
  /* worthRef is now a local variable. If
     I return it, will it get destroyed
     once B finishes execution?
  */
  worthRef = worthRef + 1;
  return (worthRef);
}

void A() {
  int netWorth = 20;
  int result = B(netWorth);

  printf("%d", result);  // Also prints 21
}

int main() {
  A();
}

Program 3

void B (int* worthRef) {
  /* worthRef is a pointer to the
     netWorth variable allocated on
     the heap.
  */
  *worthRef = *worthRef + 1;
}

void A() {
  int *netWorth = (int *) malloc(sizeof(int));
  *netWorth = 20;

  B(netWorth);

  printf("%d", *netWorth);  // Also prints 21

  free(netWorth);
}

int main() {
  A();
}

请检查我的理解

  • 程序1为变量netWorth在堆栈上分配内存 ,并使用指向该堆栈内存地址的指针直接直接修改变量{{1 }}。这是通过引用传递的示例。没有复制netWorth变量。
  • 程序2调用netWorth,这会在其堆栈存储器上创建值B()本地存储副本,并递增该本地副本,然后将其作为netWorth返回给A()。这是按值传递的示例。
    • 返回result的本地副本会被销毁吗?
  • 程序3为变量worthRef(变量)在堆上分配内存 ,并使用指向该堆内存地址的指针直接 修改变量{ {1}}。这是通过引用传递的示例。没有复制netWorth变量。

我主要的困惑点是在程序1和程序3之间。仅仅是一个将指针传递给堆栈变量而将一个指针传递给堆变量,对吗?但是在这种情况下,为什么我什至需要堆呢?我只希望有一个函数可以直接更改单个值,而无需使用netWorth就可以了。

堆允许程序员选择变量的生存期,对吗?在什么情况下程序员只想保留一个变量(例如netWorth)?在这种情况下,为什么不只是将其设置为全局变量呢?

2 个答案:

答案 0 :(得分:1)

  

我有点了解堆栈内存,堆的一般定义   内存,malloc,指针和内存地址...我想要一点   关于它们之间的区别的评论和解释   是...

<=确定...

  

程序1在堆栈上为变量netWorth分配内存,并且   使用指向该堆栈存储器地址的指针直接修改   可变净值。这是通过引用传递的示例。

<=绝对正确!

  

问:程序2 ...返回的wortherRef的本地副本是否被销毁?

A:int netWorth仅存在于A()的范围内,其中包括对B()的调用。

  

程序1和程序3 ...一种是将指针传递给堆栈变量,另一种是将指针传递给堆变量。   问:但是在这种情况下,为什么我甚至需要堆?

A:你不知道。像在程序1中一样简单地获取addressof(&)int是完全可以的(可以说是 preferable )。

  问:堆允许程序员选择变量的生存期,对吗?

A:是的,这是动态分配内存的一方面。你是对的。

  

问:在这种情况下,为什么不只是将其设为全局变量?

A:是的,这是另一种选择。

以下任何问题的答案:“为什么选择一个设计替代方案而不是另一个?”通常是“取决于”。

例如,也许您不能仅将所有内容声明为“局部变量”,因为您所处的环境恰好具有非常小的有限堆栈。它发生了:)

通常

  1. 如果可以声明局部变量而不是分配堆,通常应该这样做。

  2. 如果可以避免声明全局变量,通常应该这样做。

答案 1 :(得分:1)

检查您的理解

  • 程序1在变量A() 功能堆栈框架内的上分配的内存,并传递 netWorth 的地址,作为指向此堆栈内存地址的指针 功能B()允许{{ 1}} 直接修改存储在该内存地址的变量 < / strong>。这是通过引用传递 按值传递变量的“地址” 的示例。 (在C中没有通过引用传递-都是通过值传递)没有复制netWorth变量。
  • 程序2调用B(),这将在其堆栈存储器上创建值netWorth的本地存储副本,递增该本地副本,然后返回 整数 返回到B()的结果。 (函数始终可以返回其自身的类型)这是按值传递的示例( ,因为C中仅按值传递 ) 。

(返回worthRef的本地副本是否会被销毁?-回答是,但是由于函数始终可以返回其自身的类型,因此可以将A()的值返回给int [由平台的调用约定处理]]

  • 程序3在堆上为变量A()分配内存,并使用指向该 heap 内存地址的指针直接修改变量netWorth。尽管“堆栈/堆” 是常用术语,但是C没有堆栈或堆的概念,但区别在于变量是使用 自动存储持续时间 < / strong>限于声明为或-的范围,当您使​​用netWorth进行分配时,内存块具有 分配的存储持续时间 ,这对于程序的生命周期或释放内存块都非常有用。 (这里还有malloc/calloc/reallocstatic的存储期限不相关),请参见:C11 Standard - 6.2.4 Storage durations of objects 这是通过引用传递的示例。 全部通过值传递! )没有复制netWorth变量。 指向thread local最初返回的地址的指针始终用于引用此内存位置。