微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

指针和段错误

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

问题描述

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

不同的处理方法

1 h指向被释放的空间

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

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

2 正确的方法

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

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

3 h-> next 为NULL

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

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

4 h->next 为NULL

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

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

5 正确的方法

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

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

涉及到的代码

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

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;
}

list.h

#ifndef __LIST_H__
#define __LIST_H__

#include <stdio.h>
#include <stdlib.h>

#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

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;
}

原文地址:https://www.jb51.cc/wenti/3279506.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐