我是C编程语言的初学者。我有点理解堆栈内存,堆内存,malloc,指针和内存地址的一般定义。但是我对理解何时在实践中使用每种技术以及它们之间的区别感到不知所措。
我已经编写了三个小程序作为示例。它们都做相同的事情,我想对它们之间的区别进行一些评论和解释。我确实意识到这是一个幼稚的编程问题,但是我希望在这里连接一些基本点。
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();
}
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();
}
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();
}
请检查我的理解
netWorth
在堆栈上分配内存 ,并使用指向该堆栈内存地址的指针直接直接修改变量{{1 }}。这是通过引用传递的示例。没有复制netWorth
变量。netWorth
,这会在其堆栈存储器上创建值B()
的本地存储副本,并递增该本地副本,然后将其作为netWorth
返回给A()
。这是按值传递的示例。
result
的本地副本会被销毁吗?worthRef
(变量)在堆上分配内存 ,并使用指向该堆内存地址的指针直接 修改变量{ {1}}。这是通过引用传递的示例。没有复制netWorth
变量。我主要的困惑点是在程序1和程序3之间。仅仅是一个将指针传递给堆栈变量而将一个指针传递给堆变量,对吗?但是在这种情况下,为什么我什至需要堆呢?我只希望有一个函数可以直接更改单个值,而无需使用netWorth
就可以了。
堆允许程序员选择变量的生存期,对吗?在什么情况下程序员只想保留一个变量(例如netWorth
)?在这种情况下,为什么不只是将其设置为全局变量呢?
答案 0 :(得分:1)
我有点了解堆栈内存,堆的一般定义 内存,malloc,指针和内存地址...我想要一点 关于它们之间的区别的评论和解释 是...
<=确定...
程序1在堆栈上为变量netWorth分配内存,并且 使用指向该堆栈存储器地址的指针直接修改 可变净值。这是通过引用传递的示例。
<=绝对正确!
问:程序2 ...返回的wortherRef的本地副本是否被销毁?
A:int netWorth
仅存在于A()的范围内,其中包括对B()的调用。
程序1和程序3 ...一种是将指针传递给堆栈变量,另一种是将指针传递给堆变量。 问:但是在这种情况下,为什么我甚至需要堆?
A:你不知道。像在程序1中一样简单地获取addressof(&)int是完全可以的(可以说是 preferable )。
问:堆允许程序员选择变量的生存期,对吗?
A:是的,这是动态分配内存的一方面。你是对的。
问:在这种情况下,为什么不只是将其设为全局变量?
A:是的,这是另一种选择。
以下任何问题的答案:“为什么选择一个设计替代方案而不是另一个?”通常是“取决于”。
例如,也许您不能仅将所有内容声明为“局部变量”,因为您所处的环境恰好具有非常小的有限堆栈。它发生了:)
通常
如果可以声明局部变量而不是分配堆,通常应该这样做。
如果可以避免声明全局变量,通常应该这样做。
答案 1 :(得分:1)
检查您的理解
A()
的 功能堆栈框架内的netWorth
的地址,作为指向此B()
允许{{ 1}} 直接修改存储在该内存地址的变量 的 值 < / strong>。这是B()
,这将在其堆栈存储器上创建值netWorth的本地存储副本,递增该本地副本,然后返回 整数 返回到B()
的结果。 (函数始终可以返回其自身的类型)这是按值传递的示例( ,因为C中仅按值传递 ) 。(返回worthRef的本地副本是否会被销毁?-回答是,但是由于函数始终可以返回其自身的类型,因此可以将A()
的值返回给int
[由平台的调用约定处理]]
A()
分配内存,并使用指向该netWorth
进行分配时,内存块具有 分配的存储持续时间 ,这对于程序的生命周期或释放内存块都非常有用。 (这里还有malloc/calloc/realloc
和static
的存储期限不相关),请参见:C11 Standard - 6.2.4 Storage durations of objects thread local
最初返回的地址的指针始终用于引用此内存位置。。