• 指针和段错误


    在转置链表和链表排序的时候遇到了问题,出现问题的地方在于指针指向了一块已经被free了的内存空间,然在下次malloc动态申请空间之前都能正常的访问,但是只要有动态申请空间,再次访问已经被free的空间的时候就出现段错误

    问题描述

    h是一个一级指针,指向了一个带头节点的链表;现在有一个转置链表的函数,将链表再执行一段头插法,而现在这个新链表的头节点的指针是t,我想要h指向这个转置成功的链表。

    不同的处理方法

    1 h指向被释放的空间

    (*h) = t;		//h是一个二级指针
    free(t);		//t是一个一级指针,是链表的头节点
    t = NULL;
    
    • 1
    • 2
    • 3

    上述是将h的地址当作参数传了进来,这里的h是一个二级指针;
    (*h) = t是将h指向了t,但是后来t所指向的节点被free了,t也指向NULL了,但是(*h)还指向这个节点。当被free掉的这片空间没有被从新分配的时候还是可以正常访问的,一但当则块空间被分配,那么你再次访问就可能是段错误或者是得到了一个错误的结果

    2 正确的方法

    (*h)->next = t->next;		//h是一个二级指针
    free(t);		//t是一个一级指针,是链表的头节点
    t = NULL;
    
    • 1
    • 2
    • 3

    这个也是所使用的方法没有改变h的指向;
    并且在释放t所指向的空间前,使用(*h)->next指向了后面的链表,这样就达到了期望,并且不会出现段错误

    3 h-> next 为NULL

    h = t;			//h是一个节点
    free(t);		//t是一个一级指针,是链表的头节点
    t = NULL;
    
    • 1
    • 2
    • 3

    这里的h传进来的是一个节点的地址,是一个一级指针;相当于值传递,在这里修改h的指向是不会改变实参的。

    4 h->next 为NULL

    h = t->next;	//h是一个节点
    free(t);		//t是一个一级指针,是链表的头节点
    t = NULL;
    
    • 1
    • 2
    • 3

    同上,在这里修改形参不会改变实参,想要形参应该实参,那么需要传递一个二级指针。

    5 正确的方法

    h->next = t->next;//h是一个节点
    free(t);		//t是一个一级指针,是链表的头节点
    t = NULL;
    
    • 1
    • 2
    • 3

    这也是正确的,这里并没有直接修改实参,只是修改了实参指向的空间的内容,所以能达到期望。

    涉及到的代码

    我觉得上面描述的可能有点不清楚,我将代码放到下面,供大家讨论:

    main.c

    #include "list.h"
    
    int main(){
    
        linklist_t *h = LinkListCreate();
        //采用尾插法保持链表中的数据和数组中数据的相对位置一致
        // LinkListCreateAll(h);
        for(int i = 1; i <= 8; i++){
            if(LinkListInsertTail(h,i) == -1){
                printf("插入失败");
                return -1;
            }
        }
        LinkListShow(h);
        //  ReverseLinkList1(&h);       //代码1 2
        ReverseLinkList2(h);            //代码3 4 5 
    
        LinkListShow(h);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    list.h

    #ifndef __LIST_H__
    #define __LIST_H__
    
    #include 
    #include 
    
    #define datatype int
    typedef struct node{
        datatype data;
        struct node *next;
    }linklist_t;
    
    linklist_t *LinkListCreate(void);
    int LinkListInsertTail(linklist_t *h,datatype data);
    int LinkListIsEmpty(linklist_t *h);
    void ReverseLinkList1(linklist_t **h);
    void ReverseLinkList2(linklist_t *h);
    void LinkListShow(linklist_t *h);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    list.c

    #include "list.h"
    
    /*
     *功能:创建循环链表
     *参数:
     *	@:无
     *返回值:成功返回单链表的首地址,失败返回NULL
     *注:创建链表头,将指针域指向NULL,将数据域设置0
     */
    linklist_t* LinkListCreate(void)
    {
        linklist_t* h;
    
        h = (linklist_t*)malloc(sizeof(*h));
        if (h == NULL) {
            printf("alloc memory error\n");
            return NULL;
        }
        h->data = (datatype)0;
        h->next = NULL;
    
        return h;
    }
    
    /*
     *功能:单链表按照尾插法插入数据
     *参数:
     *	@h:单链表的指针
     *   @data:被插入的数据
     *返回值:成功返回0,失败返回-1
     */
    int LinkListInsertTail(linklist_t* h, datatype data)
    {
        linklist_t *tmp, *th = h;
        // 1.分配临时的节点,将data放入到节点的数据域中
        if ((tmp = (linklist_t*)malloc(sizeof(*tmp))) == NULL) {
            printf("malloc memory error\n");
            return -1;
        }
        tmp->data = data;
        while (h->next != NULL)
            h = h->next;
        tmp->next = h->next;
        h->next = tmp;
        return 0;
    }
    
    /*
     *功能:链表的遍历
     *参数:
     *	@h:链表的指针
     *返回值:无
     */
    void LinkListShow(linklist_t* h)
    {
        // 1.如果链表为空,直接返回
        if (LinkListIsEmpty(h))
            return;
    
        // 2.如果链表不为空,挨个成员访问
        while (h->next) {
            h = h->next;
            printf("-%d", h->data);
        }
        printf("-\n");
    }
    
    /*
     *功能:判断单链表是否为空
     *参数:
     *	@h:链表的指针
     *返回值:空返回1,否则返回0
     */
    int LinkListIsEmpty(linklist_t* h)
    {
        return h->next == NULL ? 1 : 0;
    }
    
    /*
     *功能:将链表的逆序
     *参数:
     *	@h:链表头节点的地址
     *返回值:无
     */
    void ReverseLinkList1(linklist_t** h)
    {
    
        linklist_t* t = LinkListCreate();
        linklist_t* tmp = NULL;
    
        while ((*h)->next) { // h->next != NULL
            tmp = (*h)->next;
            (*h)->next = tmp->next;
            tmp->next = t->next;
            t->next = tmp;
        }
        (*h)->next = t->next; //代码2  切记不要写成 *h = t;
        //(*h) = t;          //代码1
        tmp = NULL;
        free(t);
        t = NULL;
    }
    
    void ReverseLinkList2(linklist_t* h)
    {
    
        linklist_t* t = LinkListCreate();
        linklist_t* tmp = NULL;
    
        while ((h)->next) { // h->next != NULL
            tmp = (h)->next;
            (h)->next = tmp->next;
            tmp->next = t->next;
            t->next = tmp;
        }
        // h = t;            //代码3
        // h = t -> next;    //代码4
        (h)->next = t->next; //代码5 切记不要写成 *h = t;
    
        tmp = NULL;
        free(t);
        t = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
  • 相关阅读:
    编码与解码
    <一>从指令角度了解函数堆栈调用过程
    无线智慧城市业务方案建设
    pyhton如何判断字符串中是否只含有数字——isdigit函数的用法及实例
    QT运行错误设置弹窗提示
    Kruskal重构树+AC自动机+树状数组:Gym - 104542F
    我怀疑这是IDEA的BUG,但是我翻遍全网没找到证据!
    Oracle Data Pump与加密
    击败GPT4-Turbo,最强开源代码模型DeepSeek-Coder-V2问世
    【C++】内联函数 ⑤ ( 内联函数总结 | 内联函数代码示例 )
  • 原文地址:https://blog.csdn.net/qq_41555003/article/details/126511854