【发布时间】:2013-10-06 21:41:45
【问题描述】:
我正在学习 C,在这个程序中我试图实现一个简单的链表。
列表的每个节点都包含一个整数和一个指向下一个节点的指针。
指针head指向列表中的第一个节点,但是最初列表是空的,所以我初始化了head = NULL。
我想对列表执行两个操作 - 填充它,然后打印它。
为了填充列表,我使用两个参数调用函数insert_node:head,以及我要插入的整数。
问题是我需要函数insert_node 来更改head 的值(所以它指向更新的列表,而不是NULL)。我不知道该怎么做,所以我将head 设为全局变量,并尝试更改它的值。
由于某种原因,即使head 的值在函数insert_node 内部发生了变化,当我再次调用该函数时,head 的值仍然为 NULL。
问题:
为什么全局变量的值没有全局改变?
我知道使用全局变量不是一个好习惯,那么如何正确更新指向列表的指针? 我在考虑让
insert_node函数实际上返回一个指向列表的指针,这是一个好方法吗?
#include<stdio.h> #include<stdlib.h> struct node { int data; struct node *link; }; void insert_node(struct node *head, int n); void print_list(struct node *head); struct node *head = NULL; main() { int i; for(i=1; i<5; i++) insert_node(head, i*i); print_list(head); } void print_list(struct node *head) { if(head == NULL) return; else { printf("%i ", head->data); print_list(head->link); } return; } void insert_node(struct node *head, int n) { struct node N = {n, NULL}; struct node *next, *prev; int prev_data = 0; //case one: list is empty - point head to N, and set N.link to NULL if(head == NULL) head = &N; //case two: n is less than first element in the list: else if(n < head->data) { N.link = head; head = &N; } else { next = head; //case three: N.data is equal to existing element, do nothing: while(next != NULL) { if(n == next->data) { printf("this element already exists.\n\n"); return; } prev = next; //save the current element next = next->link; //look at the next element } //case four: N.data is greater than last element: if(n > prev->data) { prev->link = &N; return; } //case five: N.data is in between list elements: next = head; while(next != NULL) { prev_data = next->data; //save the current element prev = next; //save pointer to current element next = next->link; //look at the next element if((n > prev_data) && (n < next->data)) { prev->link = &N; N.link = next; return; } } } return; }
【问题讨论】:
-
如果您使用 GCC,请使用
-Wshadow以及其他警告选项(至少为-Wall)进行编译。它会让您知道函数的head参数意味着这些函数无法访问全局变量head(局部变量隐藏了全局变量)。 (在 C++ 中,有一个作用域运算符来消除歧义(head与::head),但在 C 中没有。) -
您将
head pointer传递给insert函数的每个值,而它应该通过引用传递。你应该使用insert_node ( struct node ** head); -
与
head处理方式的变化无关,您需要为新节点动态分配内存(malloc()和错误检查)。目前,您将数据存储在局部变量中,然后将该局部变量的地址添加到列表中。这不是幸福的秘诀。您的案例 3、4、5 应该更简单地处理。由于您按排序顺序维护列表,因此当下一个指针为空或下一个节点中的数据大于或等于您要添加的节点时,您需要停止扫描。您不应该从头开始重新扫描列表。 -
乔纳森,你对“(不)幸福的秘诀”是正确的。修复影子变量名称后,我一直只将最后一个元素放入列表中。我花了几个小时调试 - 结果发现,每次调用
insert_node函数时,都会在同一地址创建局部变量N。由于head指向N,这意味着head将始终指向最新的N。这个问题是使用 malloc 的原因吗? -
乔纳森,我真的很感谢你的 cmets。我将研究改进案例 3-5。还有几个问题:应该进行哪些错误检查?关于 gcc 选项 - 还有什么其他好的选项可以使用(对于像我这样的初学者)?
标签: c linked-list global-variables