码迷,mamicode.com
首页 > 编程语言 > 详细

链表(C语言实现)

时间:2016-02-06 22:24:03      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

#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还有意义,准备销毁,不过它的内存已经释放,所以重复释放会出错。

我靠,终于一边写,一边找到问题的根本。

链表(C语言实现)

标签:

原文地址:http://www.cnblogs.com/wyc199288/p/5184416.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!