typedef struct list
{
struct list * next;
int val;
}*list_t;
list_t add(list_t l,int e)
{
list_t head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l != NULL)
l=l->next;
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return head;
}
示例驱动程序:
int main()
{
list_t ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
system("pause");
return 0;
}
程序有效,但是“添加”功能会重新排列列表,以便主循环的主体永远不会实现。我很惊讶我,因为我以为我一直把列表作为值传递!你能解释一下这个现象吗?
答案 0 :(得分:2)
问题不在于add函数倒回列表,它根本不起作用:你的代码中没有任何地方说明列表的前一端应该链接到新添加的元素。
我稍微修改了一下:
typedef struct list
{
struct list * next;
int val;
} list_t;
list_t *add(list_t *l,int e)
{
list_t *head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l->next != NULL)
l=l->next;
l->next = malloc(sizeof(list_t));
l=l->next;
l->val = e;
l->next = NULL;
return head;
}
int main()
{
list_t *ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
return 0;
}
现在代码按预期工作。
请记住,l
是add
函数中的局部变量。如果不允许以某种方式离开函数范围(例如,当您返回时,在第一个if内),对l
所做的任何更改都将丢失。使用l
或*
运算符对变量->
所做的更改将对有权访问该变量的任何人有效。
我建议你开始阅读调试技巧。它们根据您的环境而有所不同,可以从神秘的命令行工具(如gdb)转到成熟的图形对象浏览器等。通过这种方式,您将能够逐步查看发生的情况并监控内存更改并检查变量中存储的内容。
编辑:已修复指针问题。内存分配现在提供整个struct变量,并且不再隐式使用指针。
答案 1 :(得分:2)
避免特殊情况。 add()函数只能做一件事:分配一个列表节点并将其指针值分配给恰好为null的链中的第一个节点。链头,中间或尾部的NULL节点之间没有区别。 (当然空节点不能存在于列表的中间。它们可以存在于列表的头部,但是列表将是空的)找到第一个NULL并将新节点放在那里。
struct list *add(struct list *lp, int e)
{
struct list **pp;
for (pp= &lp; *pp; pp = &(*pp)->next) {;}
*pp = malloc(sizeof **pp);
(*pp)->val = e;
(*pp)->next = NULL;
return lp;
}
答案 2 :(得分:1)
l = malloc(sizeof(list_t));
分配指向结构的指针,而不是结构本身。 例如,在64位机器上,malloced大小为8,但它应该是16。
当你后来说
时l->val = ..
l->next = ..
只有上帝知道你要写的地方..
去搜索一些链表的示例代码,并通读,我的意思是在调试器中。