我试图实现自己的链表,并且一直在搞乱关于动态内存分配和指针等的代码学习。当我尝试在链接列表中添加一些东西时,我得到一个段错误,并且在使用调试器时我意识到这是因为最初我的链表的头指针没有指向null然后我的添加功能没有识别出头是空的。但是我有一个初始化函数,它将链表的头指针设置为NULL但由于某种原因,一旦我退出initialize函数并进入add函数,头部就不再指向NULL。
这是我的代码:
list.h
typedef struct node{
int value;
struct node *next;
} Node;
typedef struct list{
Node *head;
} List;
list.c
void initialize(List *l){
if(l != NULL){
l = malloc(sizeof(List));
l->head = NULL;
}
}
void add(List *l, int a){
//Code
}
int main(){
List l;
initialize(&l)
add(&l, 2);
}
一进入add函数并打印出* l,我就看到磁头没有指向0x0。我一直在摸不着为什么不这样做。我认为这与传递价值有关,但我不认为它是。我在这做错了什么?
答案 0 :(得分:2)
是的,按值传递是您的罪魁祸首。您正在按值传递指针。
假设l
中的main()
位于地址0xABCD
。然后你的main()
被编译为
int main(void) {
List l;
initialize(0xABCD);
add(0xABCD, 2);
}
并且您的initialize()
调用看起来像这样(假设malloc()
成功并在地址0xCDEF
分配内存:
void initialize(List *l) {
if(l != 0x0) {
l = 0xCDEF; // malloc()
l->head = 0x0;
}
}
l = 0xCDEF
不会传播到main()
,因为l
是按值传递的。
你想做的是
void initialize(List **l) {
if(l != NULL) {
*l = malloc(sizeof(List)); // note dereferencing the passed-by-value pointer
(*l)->head = NULL;
}
}
int main(void) {
List * l;
initialize(&l);
add(l, 2);
}
会将指针传递给指向列表的指针(实际上是main()
中指针的地址。它允许initialize()
中的代码更改l
中的main()
变量}。
或者,您可以使用
List * list_init() {
List * retval = malloc(sizeof(List));
if(retval == NULL) { // you should check malloc return value
// abort(), print warning or just
return NULL;
}
retval->head = NULL;
return retval;
}
int main(void) {
List * l = list_init();
if(l == NULL) {
// handle the error
}
add(l, 2);
}
答案 1 :(得分:1)
在main()中声明一个存在于堆栈中的List。您将指向该List的指针传递给initailize()。然后,您在堆上创建一个新列表。从initialize()返回时,您仍然使用开头的堆栈上的List。堆上的列表已泄露,您无法访问它。所以你永远不会初始化你传递的List作为add()的指针。你可以忘记初始化()并且只有
l.head = NULL;
代替。
答案 2 :(得分:0)
你编写这行代码android:background
似乎很奇怪。
创建一个只有一个参数的结构并不是很有用,一个简单的typedef就可以完成这项工作:l->malloc(sizeof(list));