#include <stdio.h> #include <stdlib.h> /*自由定义类型,类似于c++模板*/ /*链表的头是head,head无意义:head->1st node->2nd node->NULL*/ typedef int type; struct Node{ type data; Node* next; }; /*创建链表,一个空的head节点,返回head*/ Node* Create() { Node* head = (Node*)malloc(sizeof(Node)); head->next = NULL; return head; } /*判断链表是否为空。空表的head->next为NULL*/ int IsEmpty(Node* head) { return head ->next== NULL;//1 is empty } /*清空链表,但是head还在还占内存*/ void MakeEmpty(Node* head) { Node* p = head; while (p != NULL) { Node* del = p;//p储存下 p = p->next;//储存p后面的节点 free(del);//删除当前p节点 } head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL } /*指定位置插入元素,n=0在head后第一个元素前插入,=1在第1个元素后面插入*/ void Insert(type val, Node* head, int n) { /*新建节点*/ Node* new_node = (Node*)malloc(sizeof(Node)); if (new_node == NULL) { printf("new_node malloc failed!\n"); return; } new_node->data = val; new_node->next = NULL; /*插入*/ Node* p = head; while (n--) { p = p->next; if (p->next == NULL) { printf("Already End!\n");//此时p已经是最后一个节点 break; } } new_node->next = p->next;//这里很重要! p->next = new_node; } /*删除指定位置节点*/ void Delete(Node* head, int n) { /*如果空就返回*/ if (IsEmpty(head)) { printf("Empty now!"); return; } else { Node* p = head; while (n--) { p = p->next; if (p->next == NULL) { printf("Already End!\n"); break; } } Node* tmp = p->next;//链表不能对上访问,就是说遍历到p你想知道p的上一个不行的,得重新遍历,除非是双向链表。 p->next = tmp->next;//目的是删除p->next。把其后一个接到前一个的后面。删除中间那个。 free(tmp); } } void Print(Node* head) { if (IsEmpty(head)) { printf("Already Empty!\n"); } else { Node* p = head->next; while (p != NULL) { printf("%d\n", p->data); p = p->next; } } printf("\n"); } int main() { Node* head=Create(); Insert(1, head, 0); Insert(2, head, 1); Insert(3, head, 2); Print(head); Insert(4, head, 2); Print(head); Delete(head, 1); Print(head); MakeEmpty(head); Print(head); //free(head); return 0; }
这段代码,注释很完整了,相信我多年之后看还能快速明白主旨。不过有个问题,我习惯把断电设在return 0;或者system(“pause”)处,先看看结果:
但是一旦继续程序就挂了:
以前也遇到过,不过经验不足没有解决。问题肯定是处在MakeEmpty上。
void MakeEmpty(Node* head) { Node* p = head->next; while (p != NULL) { Node* del = p;//p储存下 p = p->next;//储存p后面的节点 free(del);//删除当前p节点 } head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL }
改成如上形式。
开始时如果把head赋给p,开始就把head内存给删除了,最终是链表的每个节点都delete了。如果想删除head,在return前面加free(head);
但是为什么我空着head,就不会挂掉,而通过循环del就会挂掉呢?
我想是回收机制的问题。在main return时,主线程终止了,堆内会把分配的变量都回收销毁。但是可能是这个head的指针跟实际的内存块链接已经断了,导致它销毁发生错误,才会出现这样的内存错误。
可以试下:
void MakeEmpty(Node* head) { Node* p = head; while (p != NULL) { Node* del = p;//p储存下 p = p->next;//储存p后面的节点 free(del);//删除当前p节点 } //head->next = NULL;//重要,因为IsEmpty的依据是->next==NULL }
这样,只要不print是没问题的。就是说,如果没有head->next,就可以。而加上这句,就是你把内存全释放了,head也没有,还在head的next挂个NULL。return时,它认为你的head还有意义,准备销毁,不过它的内存已经释放,所以重复释放会出错。
我靠,终于一边写,一边找到问题的根本。