我使用以下代码创建了一个链接列表。正如您所看到的,我已经使用malloc创建了一个大小为3的列表。但我运行了大小为10的for循环来初始化和打印。
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
struct node {
int value;
struct node *next;
};
int main() {
//code
struct node **head;
struct node *curr;
curr = (struct node *) malloc(sizeof(struct node)*3);
head = &curr;
printf("done 1\n");
(*head)->value = 0;
(*head)->next = NULL;
for(int i = 1; i < 10; i++) {
(*head+i-1)->next = (*head+i);
(*head+i)->value = i;
(*head+i)->next = NULL;
}
curr = *head;
printf("done 2\n");
for(int i = 0; i < 10; i++) {
printf("%d\t", (*head + i)->value);
//curr = curr->next;
}
printf("\ndone 3\n");
//free(curr);
return 0;
}
当我编译并运行代码时,获得的结果是,
done 1
done 2
0 1 2 3 154208560 842282289 876087600 154744882 808859448 875837236
done 3
为什么我能够为第4个节点分配值并在实际创建大小为3的列表时访问它?
我看到垃圾值正在从第5个节点访问到第10个节点。但是如何创建第4个节点?
P.S:
我知道10!= 3。当我将循环置于其限制内时,代码正常运行。我想看看当我们走出界限时会发生什么。我看到第4个节点也被创建了,因为当我实际创建一个大小为3的列表时,我能够分配值。
这纯粹是为了看我是否会遇到段错误。
答案 0 :(得分:7)
您正在调用undefined behavior。执行此操作时,程序可能会崩溃,它可能看起来正常工作,或者它可能以看似随机的方式运行。
C不对数组或已分配的内存执行任何类型的边界检查。这是让它变得快速的事情之一。这也意味着它将允许你做你不应该做的事情。它相信程序员“做正确的事”。
在您的特定计算机上,您会在第三个元素后看到随机数据。当我在我的机器上运行相同的代码时,我碰巧得到了预期的输出,就像分配了足够的内存一样。此外,如果我取消对free
的调用,则程序崩溃。这是未定义的行为。
试图理解未定义的行为通常是徒劳的。这完全取决于编译器及其运行的机器的实现细节。在这种情况下,写入的内存可能是在正确分配的内存之后堆中的未分配内存。根据malloc的实现方式,内存的这一部分可能包含malloc和其他函数正常运行所需的数据。重点是写在数组末尾不能保证崩溃,所以你需要小心。
答案 1 :(得分:1)
此代码在不同的操作系统上的行为会有所不同。
即使分配了所有10个整数并正确打印,您也可能会离开。
您的代码将列表的开头放在堆上,只有3个元素的分配。
你可能会幸运并为所有10个元素使用内存,否则你的程序将在第4个版本中崩溃!