提问人:R.Duarte 提问时间:10/15/2023 最后编辑:R.Duarte 更新时间:10/16/2023 访问量:80
我可以对某些节点使用分配,而其他节点不在 C 的链表中使用分配吗?
Can I use allocation for some nodes and others don't in a linked list in C
问:
我不明白为什么有必要使用指针然后使用动态内存来分配结构。有什么能阻止我这样做吗:
typedef struct node {
char name[100];
int age;
struct node *next;
} node_t ;
int main(){
node_t *head = NULL;
node_t person2 = {"Alex", 15, NULL};
head = person2.name;
return 0;
}
取而代之的是:
typedef struct node {
char name[100];
int age;
struct node *next;
} node_t ;
int main(){
node_t *head = NULL;
node_t *person1;
person1 = (node_t*)malloc(sizeof(node_t));
person1->next = NULL;
head = person1;
return 0;
}
我知道我们分配内存的地方是不同的,但实际上,这两种方式的工作方式不同吗?我提出问题的原因是因为我只在网上的每个示例中看到指向 malloc 方式的指针。
我可以同时使用这两种方式吗?
我要么将整个节点指向下一个节点:
head = person1;
下一个节点可能指向下一个节点的名称,例如:
person1->next = person2.name;
如果我没有弄错,当我们指向动态内存地址时,我们指向第一个数据类型的字节,在这种情况下将是 name[0] 字节。
答:
主要问题是知道如何以及何时释放链表使用的内存 - 分配的内存必须释放,而在堆栈上分配的内存不能释放 amd 将在包含帧退出时自动释放。更糟糕的是,在帧退出后传递或尝试使用它会导致未定义的行为,并且这两种情况一开始似乎都有效,后来会导致问题。malloc
free
free
free
一种可能性是用一个位标志来标记每个节点,该标志是为使用 malloc 分配的节点设置的,并为其他节点清除。这样,您至少知道是否应该将给定节点传递给 。这仍然无助于释放来自堆栈上分配的节点的悬空指针的可能性,而这些指针仍在列表中。onHeap
free
另一种可能性是“正常”地在堆上分配节点,但在极少数情况下,您希望分配和释放同一范围内的节点,您可以在堆栈上执行此操作。因此,您可能有如下所示的代码:
void func(struct node *list) { // list (probably) on the heap
struct node local; // a new node we'll prepend
// init fields of local with some data
local.next = list;
func2(&local); // some other function
}
在这里,调用它的代码“拥有”正在传入的列表,并且可以以任何方式分配它(在堆上使用 malloc 或其他方式)并以相同的方式清理它。 然后只拥有它预先传递给 func2 的单个节点(它在列表中没有任何内容,因此不会释放任何内容),并在返回时自动释放。在这里使用堆栈可以看作是分配的局部优化。func
func
local
评论
free
malloc
在第一个代码片段中,我认为您的意思是
head = &person2;
而不是
head = person2.name;
当然,您可以使用局部变量作为列表的节点。但是在这种情况下,如果列表需要存储大量节点,那么您将需要声明不同的大量局部变量,这些变量将表示效率低下的节点,并使您的程序非常庞大,无法读取。
寿命是问题所在。如果你的节点是自动声明的,你可以回避这个问题,但是一旦节点开始源自其他函数,就会出现这个问题。main
假设我们创建了一个函数,该函数接受一个 int 值和一个指向下一个节点的指针,并返回一个新节点。create_node
struct node {
int value;
struct node *next;
};
struct node *create_node(int value, struct node *next) {
struct node new_node = {.value=value, .next=next};
return &new_node;
}
这将返回指向局部变量的指针。随之而来的是未定义的行为。
如果我们动态分配内存,则节点的寿命将超过函数的范围。
struct node *create_node(int value, struct node *next) {
struct node *new_node = malloc(sizeof(struct node));
if (!new_node) return NULL;
new_node->value = value;
new_node->next = next;
return new_node;
}
我们现在可以安全地写出这样的东西:
struct node *prepend_value(struct node *list, int value) {
struct node *new_node = create_node(value, list);
return new_node;
}
评论
struct
int is_allocated;
free
head = &person2;
malloc