C 堆栈VS堆,这是什么?

C 堆栈VS堆,这是什么?,c,pointers,malloc,storage-duration,C,Pointers,Malloc,Storage Duration,所以我开始玩C,到目前为止玩得很开心 然而,有几件事我无法理解 我知道这会在堆栈上结束 int i = 0; 我知道这将在堆上为整数保留空间并返回地址 int *i = malloc(sizeof(int)); 不过。如果我这样做 int i_one = 1, i_two = 2; int *arr = calloc(2, sizeof(int)); arr[0] = i_one; arr[1] = i_two; 当arr在堆上时,i_1和2是堆栈分配的。这是否意味着arr将把i_1和2的

所以我开始玩C,到目前为止玩得很开心

然而,有几件事我无法理解

我知道这会在堆栈上结束

int i = 0;
我知道这将在堆上为整数保留空间并返回地址

int *i = malloc(sizeof(int));
不过。如果我这样做

int i_one = 1, i_two = 2;
int *arr = calloc(2, sizeof(int));
arr[0] = i_one;
arr[1] = i_two;
当arr在堆上时,i_1和2是堆栈分配的。这是否意味着arr将把i_1和2的值复制到堆上,或者只是在堆栈上保存对变量的2个引用。我假设它是alt one的一个变体(如果我没有错的话),只要我退出这个函数,我的堆栈分配的INT就会被释放

总之,在使用calloc创建动态分配的数组时。数组中的条目也需要分配指针/堆吗?在我看来,这是没有意义的,因为这样我就不会创建一个int指针数组了吗?是的,我知道指针的大小和int一样,所以这个例子有点愚蠢,但你明白了

谢谢你

你这么说的时候

int *i = malloc(sizeof(int));
这将在堆上结束

事实上,事情并没有那么简单


如果变量
i
是函数中的局部变量,则变量本身的空间将位于“自动存储”中,即堆栈中。但是malloc返回的指针将指向堆。

赋值运算符用于将存储在一个对象中的值赋值给另一个对象

所以在这些赋值语句中

arr[0] = i_one;
arr[1] = i_two;
存储在变量
i_one
i_two
中的值被复制到数组元素
arr[0]
arr[1]
占用的内存中。现在,如果您将更改变量
i_one
中存储的值,则
arr[0]
中存储的值将不会更改

如果要在堆中存储对对象
i_one
i_two
的引用,则应编写

int **arr = calloc(2, sizeof(int *));
arr[0] = &i_one;
arr[1] = &i_two;
现在,您可以使用数组元素
arr[0]
以以下方式更改存储在
i_one
中的值

*arr[0] = 10;

我通过打印所有相关类型或符号来检查内存映射(最初我使用静态库、动态加载和运行时加载,但可能有点混乱)

我还装箱了两个“堆变量”,并打印它们的地址和包含地址的本地指针

->->->因此,您可以看到本地指针位于堆栈中,但它们的实际地址位于堆的开头。这就是为什么您可以在堆栈框架之外使用分配的变量-您的本地指针被删除,但地址保留在堆中

这是我的程序输出:

 ------------------COMMAND-LINE------------------
 |*envp--------------------->           140737488347777|
 |*argv--------------------->           140737488347751|
 
 |envp--------------------->            140737488346896|
 |argv--------------------->            140737488346864|
 
 
 ------------------STACK------------------
 |str1--------------------->            140737488346090|
 |alloc_second address----->            140737488346048|
 |alloc_first address------>            140737488346040|
 |const_local_second ------>            140737488346032|
 |const_local_first-------->            140737488346024|
 |argc--------------------->            140737488346012|
 ------------------FUNC-STACK-FRAME------------------
 |fun_var_const------------>            140737488345956|
 |fun_var_second----------->            140737488345952|
 |fun_var------------------>            140737488345948|
 
 
 ------------------HEAP------------------
 
 ------------------------MMS---------------------------------------
 |strlen(library func)----->            140737353401952|
 ----------------------------------------------------------------
 
 |alloc_second------------->                4215488|
 |alloc_first-------------->                4215456|
 
 
 ------------------BSS------------------
 |global_const = 0 -------->                4210812|
 |global_int_first--------->                4210808|
 |global_double_first------>                4210800|
 |static_int_first--------->                4210796|
 |global_int_const--------->                4202504|
 
 |------------------DATA------------------
 |static_int_second-------->                4210784|
 |global_double_second----->                4210776|
 ------------------DATA - READ ONLY------------------
 |const_static_int_second-->                4204408|
 |const_static_int_first--->                4204412|
 |string literal----------->                4202700|
 
 
 ------------------TEXT------------------
 |extern function --------->                4200215|
 |function (define after)-->                4200181|
 |main -------------------->                4199038|
 |static function --------->                4198870|
 
 -----------------------BOTTOM LINE------------------
 

并且可以从程序中的每个点访问,因此如果返回
i
,将发送堆地址back@AsafItach是,将复制并返回
i
的值,该值是堆分配内存的(第一个字节)位置。堆分配内存的生存期是直到
malloc
返回的指针传递到
free
为止。正确!我想你对这篇文章很熟悉。。(即使我每次都免费使用malloc工具)@Someprogrammerdude谢谢你的更正,我把它简单化了。是的,malloc将在堆上为int创建空间,我将保留它的地址,我必须跟踪它,并在不再需要时释放它。int和pointer的大小不同(这取决于系统):)int是4字节,而pointer是字大小(在我们的生命周期中是4/8字节:)。真的吗?我认为指针的字节大小总是与整数的字节大小相同,即4或8字节,具体取决于操作系统。我认为在我的情况下,存储实际值会更容易,因为我不需要它们成为指针,一旦创建,我就不需要修改它们(至少不需要修改原始值)。但这意味着当我做arr[0]=I_one;arr[1]=i_-two;那么i_1和i_2的副本就在堆上,对吗?一旦我做了自由(arr)。那么我想这些副本也会从堆中移除?与指针数组的示例不同。@JohanFredin如果要释放指针arr指向的内存,则动态分配数组中存储的值将不可接受。但是i_1和i_2中存储的值将是活动的。