C:我对堆和栈分配细节的理解是否正确?
C: Is my understanding about the specifics of heap and stack allocation correct?
我在 C 中实现了一种链表(代码在底部)(它有明显的问题,但我不是在询问这些或链表;例如,我知道没有调用free()
分配的内存)下面给出了我所期望的(据我检查)。我的问题是关于 addnodeto()
函数的前几行以及它对 heap/stack.
的作用
我的理解是调用malloc()
在堆上留出一些内存,然后returns分配给struct node *newnode
的那个内存的地址(指向开头)它本身在堆栈上。第一次调用函数时,*nodetoaddto
是指向struct node first
的指针,两者都在栈上。因此 (*nodeaddto)->next = newnode
设置 first.next
等于 newnode
的值,这是新分配内存的地址。
当我们离开这个函数,继续执行main()
函数时,是否*newnode
从栈中移除(不确定'deallocated'是否正确),只留下struct node first
指向堆上的'next'node struct
?如果是这样,这个 'next' struct node
在堆栈或堆上是否也有一个变量名,或者它也只是指向一些内存?此外,是否可以说 struct node first
在堆栈上,而所有后续节点都在堆上,并且在 main()
returns 0
之前没有 structs/variables在 struct node first
以外的堆栈上?或者 is/are 还有 1 个/多于 1 个 *newnode
还在堆栈中?
我确实尝试使用 GDB,它显示 struct node *newnode
两次都位于相同的内存地址 addnodeto()
被调用(所以它被删除然后恰好是 re-defined/allocated 在到相同的位置,或者也许是编译器很聪明,甚至在函数第一次退出后就把它留在那里,或者其他?),但我无法具体地解决其他问题。谢谢。
代码:
#include <stdio.h>
#include <stdlib.h>
#define STR_LEN 5
struct node {
char message[STR_LEN];
struct node *next;
};
void addnodeto(struct node **nodeaddto, char letter, int *num_of_nodes){
struct node *newnode = malloc(sizeof(struct node));
(*nodeaddto)->next = newnode;
newnode->message[0] = letter;
(*nodeaddto) = newnode;
*num_of_nodes += 1;
}
int main(void){
struct node first = {"F", NULL};
struct node *last = &first;
int num_nodes = 1;
addnodeto(&last, 'S', &num_nodes);
addnodeto(&last, 'T', &num_nodes);
addnodeto(&last, 'I', &num_nodes);
printf("Node: %d holds the char: %c\n", num_nodes-3, first.message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-2, (first.next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-1, ((first.next)->next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes, (last)->message[0]);
return 0;
}
当 运行 输出时:
Node: 1 holds the char: F
Node: 2 holds the char: S
Node: 3 holds the char: T
Node: 4 holds the char: I
符合预期。
My understanding is that calling malloc() sets aside some memory on the heap, and then returns the address of that memory (pointing to the beginning)…
是的,但是称其为“堆”的人对术语的理解很草率。堆是一种数据结构,如 linked 列表、二叉树或散列 table。堆可用于跟踪可用内存以外的其他用途,并且可以使用堆以外的数据结构来跟踪可用内存。
我实际上不知道内存管理例程管理的内存的特定术语。实际上有几组不同的内存我们可能需要术语:
- 他们目前从操作系统获取并正在管理的所有内存,包括当前分配给客户端的内存和已释放(尚未归还给操作系统)且可用于重用;
- 当前分配给客户端的内存;
- 当前可重用的内存;和
- 正在管理的整个内存范围,包括部分虚拟地址 space 为将来映射保留,以便在必要时从操作系统请求更多内存。
我看到过用“pool”来形容这种内存,但是没有看到具体的定义。
… which is assigned to struct node *newnode which is itself on the stack.
struct node *newnode
在普通 C 实现中确实名义上在堆栈上。然而,C 标准仅将其归类为自动存储持续时间,这意味着其内存由 C 实现自动管理。堆栈是最常见的实现方式,但专门的 C 实现可能以其他方式实现。此外,一旦编译器优化了程序,newnode
可能不在堆栈上;编译器可能会生成仅将其保存在寄存器中的代码,并且还有其他可能性。
这里的一个复杂问题是,当我们谈论 C 程序中的内存使用时,我们可以谈论模型计算机中的内存使用,C 标准用于描述程序的语义或实际实践中的内存使用。例如,正如 C 标准所描述的那样,每个对象在其生命周期内都为其保留了一些内存。然而,当一个程序被编译时,编译器可以生成它想要的任何代码,这些代码可以获得与 C 标准所要求的相同的结果。 (程序的输出必须相同,并且某些其他交互的行为也必须相同。)因此编译器可能根本不会为对象使用内存。优化后,一个对象可能一次在内存中,另一次在寄存器中,或者它可能一直在寄存器中,从不在内存中,也可能在不同的时间在不同的寄存器中,也可能不在任何特定的地方因为它可能已被合并到其他事物中。例如,在 int x = 3; printf("%d\n", 4*x+2);
中,编译器可能会完全消除 x
并只打印“14”。所以,问东西在内存中的什么位置的时候,要分清楚是要讨论C标准使用的模型计算机中的语义还是优化程序中的实际做法。
When the function is first called, *nodetoaddto
is a pointer to struct node
first, both of which are on the stack.
nodetoaddto
可能在堆栈上,如上所述,但也可能在寄存器中。函数参数在寄存器中传递是很常见的。
指向astruct node
。 struct node
本身就是一个类型,所以它只是一个概念,而不是要指向的对象。相反,“a struct node
”是该类型的对象。该对象可能在也可能不在堆栈上; addnodeto
不在乎;无论它在内存中的什么位置,它都可以 link 。您的 main
例程确实创建了具有自动存储持续时间的 first
和 last
节点,但它也可以使用 static
,然后这些节点可能位于内存的不同部分而不是堆栈,addnodeto
不关心。
Thus the (*nodeaddto)->next = newnode
sets first.next
equal to the value of newnode
which is the address of the newly allocated memory.
是:在main
中,last
被初始化为指向first
的指针。然后&last
传递给addnodeto
,所以nodeaddto
是指向last
的指针。所以 *nodeaddto
是指向 first
的指针。所以 (*nodeaddto)->next
是 `first.
中的 next
成员
When we leave this function, and continue executing the main()
function, is *newnode
removed from the stack (not sure if 'deallocated' is the correct word), leaving only struct node first
pointing to the 'next' node struct
on the heap?
newnode
是一个在addnodeto
里面自动存储时长的对象,所以它的内存会在addnodeto
结束时自动释放。
*newnode
是一个 struct node
分配的存储持续时间,所以它的内存不会在函数结束时释放。它的内存在调用 free
时释放,或者可能是其他一些可能释放内存的例程,如 realloc
.
If so, does this 'next' struct node
have a variable name also on the stack or heap, or it is merely some memory pointed [to]?
堆栈或堆中没有变量名。变量名称仅存在于源代码中(在编译时存在于编译器中以及与编译程序相关的调试信息中,但调试信息通常与程序的正常执行是分开的)。当我们使用分配的内存时,我们通常只通过指向它的指针来使用它。
Moreover, is it true to say that struct node first
is on the stack, whilst all subsequent nodes will be on the heap,…
是的,受上面关于堆栈和“堆”的警告约束。
… and that just before main()
returns 0
there are no structs/variables on the stack other than struct node first
?
main
中的所有自动对象都在堆栈上(或以其他方式自动管理):first
、last
和 num_nodes
。
Or is/are there 1/more than 1 *newnode
still on the stack?
没有
我在 C 中实现了一种链表(代码在底部)(它有明显的问题,但我不是在询问这些或链表;例如,我知道没有调用free()
分配的内存)下面给出了我所期望的(据我检查)。我的问题是关于 addnodeto()
函数的前几行以及它对 heap/stack.
我的理解是调用malloc()
在堆上留出一些内存,然后returns分配给struct node *newnode
的那个内存的地址(指向开头)它本身在堆栈上。第一次调用函数时,*nodetoaddto
是指向struct node first
的指针,两者都在栈上。因此 (*nodeaddto)->next = newnode
设置 first.next
等于 newnode
的值,这是新分配内存的地址。
当我们离开这个函数,继续执行main()
函数时,是否*newnode
从栈中移除(不确定'deallocated'是否正确),只留下struct node first
指向堆上的'next'node struct
?如果是这样,这个 'next' struct node
在堆栈或堆上是否也有一个变量名,或者它也只是指向一些内存?此外,是否可以说 struct node first
在堆栈上,而所有后续节点都在堆上,并且在 main()
returns 0
之前没有 structs/variables在 struct node first
以外的堆栈上?或者 is/are 还有 1 个/多于 1 个 *newnode
还在堆栈中?
我确实尝试使用 GDB,它显示 struct node *newnode
两次都位于相同的内存地址 addnodeto()
被调用(所以它被删除然后恰好是 re-defined/allocated 在到相同的位置,或者也许是编译器很聪明,甚至在函数第一次退出后就把它留在那里,或者其他?),但我无法具体地解决其他问题。谢谢。
代码:
#include <stdio.h>
#include <stdlib.h>
#define STR_LEN 5
struct node {
char message[STR_LEN];
struct node *next;
};
void addnodeto(struct node **nodeaddto, char letter, int *num_of_nodes){
struct node *newnode = malloc(sizeof(struct node));
(*nodeaddto)->next = newnode;
newnode->message[0] = letter;
(*nodeaddto) = newnode;
*num_of_nodes += 1;
}
int main(void){
struct node first = {"F", NULL};
struct node *last = &first;
int num_nodes = 1;
addnodeto(&last, 'S', &num_nodes);
addnodeto(&last, 'T', &num_nodes);
addnodeto(&last, 'I', &num_nodes);
printf("Node: %d holds the char: %c\n", num_nodes-3, first.message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-2, (first.next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes-1, ((first.next)->next)->message[0]);
printf("Node: %d holds the char: %c\n", num_nodes, (last)->message[0]);
return 0;
}
当 运行 输出时:
Node: 1 holds the char: F
Node: 2 holds the char: S
Node: 3 holds the char: T
Node: 4 holds the char: I
符合预期。
My understanding is that calling malloc() sets aside some memory on the heap, and then returns the address of that memory (pointing to the beginning)…
是的,但是称其为“堆”的人对术语的理解很草率。堆是一种数据结构,如 linked 列表、二叉树或散列 table。堆可用于跟踪可用内存以外的其他用途,并且可以使用堆以外的数据结构来跟踪可用内存。
我实际上不知道内存管理例程管理的内存的特定术语。实际上有几组不同的内存我们可能需要术语:
- 他们目前从操作系统获取并正在管理的所有内存,包括当前分配给客户端的内存和已释放(尚未归还给操作系统)且可用于重用;
- 当前分配给客户端的内存;
- 当前可重用的内存;和
- 正在管理的整个内存范围,包括部分虚拟地址 space 为将来映射保留,以便在必要时从操作系统请求更多内存。
我看到过用“pool”来形容这种内存,但是没有看到具体的定义。
… which is assigned to struct node *newnode which is itself on the stack.
struct node *newnode
在普通 C 实现中确实名义上在堆栈上。然而,C 标准仅将其归类为自动存储持续时间,这意味着其内存由 C 实现自动管理。堆栈是最常见的实现方式,但专门的 C 实现可能以其他方式实现。此外,一旦编译器优化了程序,newnode
可能不在堆栈上;编译器可能会生成仅将其保存在寄存器中的代码,并且还有其他可能性。
这里的一个复杂问题是,当我们谈论 C 程序中的内存使用时,我们可以谈论模型计算机中的内存使用,C 标准用于描述程序的语义或实际实践中的内存使用。例如,正如 C 标准所描述的那样,每个对象在其生命周期内都为其保留了一些内存。然而,当一个程序被编译时,编译器可以生成它想要的任何代码,这些代码可以获得与 C 标准所要求的相同的结果。 (程序的输出必须相同,并且某些其他交互的行为也必须相同。)因此编译器可能根本不会为对象使用内存。优化后,一个对象可能一次在内存中,另一次在寄存器中,或者它可能一直在寄存器中,从不在内存中,也可能在不同的时间在不同的寄存器中,也可能不在任何特定的地方因为它可能已被合并到其他事物中。例如,在 int x = 3; printf("%d\n", 4*x+2);
中,编译器可能会完全消除 x
并只打印“14”。所以,问东西在内存中的什么位置的时候,要分清楚是要讨论C标准使用的模型计算机中的语义还是优化程序中的实际做法。
When the function is first called,
*nodetoaddto
is a pointer tostruct node
first, both of which are on the stack.
nodetoaddto
可能在堆栈上,如上所述,但也可能在寄存器中。函数参数在寄存器中传递是很常见的。
指向astruct node
。 struct node
本身就是一个类型,所以它只是一个概念,而不是要指向的对象。相反,“a struct node
”是该类型的对象。该对象可能在也可能不在堆栈上; addnodeto
不在乎;无论它在内存中的什么位置,它都可以 link 。您的 main
例程确实创建了具有自动存储持续时间的 first
和 last
节点,但它也可以使用 static
,然后这些节点可能位于内存的不同部分而不是堆栈,addnodeto
不关心。
Thus the
(*nodeaddto)->next = newnode
setsfirst.next
equal to the value ofnewnode
which is the address of the newly allocated memory.
是:在main
中,last
被初始化为指向first
的指针。然后&last
传递给addnodeto
,所以nodeaddto
是指向last
的指针。所以 *nodeaddto
是指向 first
的指针。所以 (*nodeaddto)->next
是 `first.
next
成员
When we leave this function, and continue executing the
main()
function, is*newnode
removed from the stack (not sure if 'deallocated' is the correct word), leaving onlystruct node first
pointing to the 'next'node struct
on the heap?
newnode
是一个在addnodeto
里面自动存储时长的对象,所以它的内存会在addnodeto
结束时自动释放。
*newnode
是一个 struct node
分配的存储持续时间,所以它的内存不会在函数结束时释放。它的内存在调用 free
时释放,或者可能是其他一些可能释放内存的例程,如 realloc
.
If so, does this 'next'
struct node
have a variable name also on the stack or heap, or it is merely some memory pointed [to]?
堆栈或堆中没有变量名。变量名称仅存在于源代码中(在编译时存在于编译器中以及与编译程序相关的调试信息中,但调试信息通常与程序的正常执行是分开的)。当我们使用分配的内存时,我们通常只通过指向它的指针来使用它。
Moreover, is it true to say that
struct node first
is on the stack, whilst all subsequent nodes will be on the heap,…
是的,受上面关于堆栈和“堆”的警告约束。
… and that just before
main()
returns 0
there are no structs/variables on the stack other thanstruct node first
?
main
中的所有自动对象都在堆栈上(或以其他方式自动管理):first
、last
和 num_nodes
。
Or is/are there 1/more than 1
*newnode
still on the stack?
没有