我刚刚开始学习C并且正在研究链接列表的简单实现。当我尝试打印我的列表时,我发现了一些奇特的东西。即使代码从未执行过,我也会在代码的一部分出现分段错误。怎么会这样?
据我所知,while循环永远不会执行,因为下一个指针不指向任何东西。我在想,也许在评估while循环时它可能会导致它指向导致分段错误的东西,但奇怪的是如果删除行root = root->next
它执行正常(没有任何错误)。即使这样,它也永远不会进入while循环。那么如果代码永远不会被执行,那么代码行如何(root = root->next
会导致错误?代码编译得很好。我在某个地方犯了一个简单的错误吗?
我知道这不是链接列表的正确实现,它是出于学习目的而制作的。
#include <stdio.h>
#include <stdlib.h>
struct linkedlist {
int value;
struct linkedlist * next;
};
typedef struct linkedlist item;
int main(int argc, char **argv) {
item * root;
item * current;
root = malloc(sizeof(item));
root->value = 500;
int i;
for(i = 0; i <= 20; i++) {
current->next = malloc(sizeof(item));
current = current->next;
current->value = i;
}
while(root->next != 0) {
//This is never executed
printf("[%d]\n", root->value);
//the line below does cause the segmentation error
//but how can this affect anything at all if this is never executed?
root = root->next;
}
return 0;
}
答案 0 :(得分:3)
current->next
的第一行是取消引用未初始化的指针。您可能忘记在循环之前将current
初始化为root
。 Derefencing一个未初始化的指针是未定义的行为(UB),这意味着任何事情都可能发生。实际上,未初始化的变量将具有与存储在其存储器位置的任何内容相对应的值。因此,未初始化的指针将被设置为某个半随机地址,并指向内存中的某些半随机内容(可能是其他程序变量)或无效。
在while循环测试root->next
的条件中,还有另一个未初始化的指针被解除引用。通常,您应该确保每个列表项(包括next
)的root
字段设置为0
,否则您将无法检测到链表(再次使用未初始化的指针,因此再次使用UB,实际上该值可能与0
不同)。
在您的代码中纠正此类问题的提案:
#include <stdio.h>
#include <stdlib.h>
struct linkedlist {
int value;
struct linkedlist * next;
};
typedef struct linkedlist item;
int main(int argc, char **argv) {
item * root;
item * current;
root = malloc(sizeof(item));
root->value = 500;
root->next = 0;
current = root;
int i;
for(i = 0; i <= 20; i++) {
current->next = malloc(sizeof(item));
current = current->next;
current->value = i;
current->next = 0;
}
while(root->next != 0) {
printf("[%d]\n", root->value);
root = root->next;
}
return 0;
}