C语言 链表清空的问题

在学习C语言 链表的时候,遇到一个问题 比较困惑,请看如下:

程序就是 创建一个 带头结点的链表 打印出来 再清空链表,在清空的时候 遇到一个不理解的问题:

程序:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

#define  Array_length   40 

typedef struct  node 

{
    int list_length;
    
    char name[Array_length];
    
    int score;
    
    struct node  *next;
} Node;

typedef Node * List;

List createList(int length);      // 创建一个具有length个结点的链表 

void printList(List header);      //打印链表 

void freeList(List header);

char *s_gets(char *restal,int n);

int main(void)

{
    List Class_6_student;
    
    int list_length;
    
    printf("Please enter the length of the list you will create : \n");
    
    scanf("%d",&list_length);
    
    while(getchar()!='\n') ;
    
    Class_6_student=createList(list_length);
    
    printList(Class_6_student);    
    
    printf("Now the list will be free. \n");
    
    freeList(Class_6_student);
    
    if(Class_6_student==NULL)  printf("Free Success! \n");  //这一步总是出不来,好像是 虽然释放了结点,但是并不是完全为空 
    
    return 0;
    
    
}

List createList(int length)

{
    List header=NULL;
    
    List newnode=NULL;
    
    List tailnode=NULL; //定义头结点  新结点  尾结点
    
    int i;
    
    header=(List) malloc(sizeof(Node));
    
    if(header==NULL)  exit(-1);
    
    header->list_length=0;
    
    header->next=NULL;
    
    tailnode=header;
    
    for(i=0;i<length;i++)
    
    {
        newnode=(List)malloc(sizeof(Node));
        
        if(newnode==NULL) exit(-1);
        
        printf("Please enter the name  of NUMBER %d student : \n",i+1);
        
        s_gets(newnode->name,Array_length);
        
        printf("Please enter the score of NUMBER %d student : \n",i+1);
        
        scanf("%d",&newnode->score);
        
        while(getchar()!='\n') ;
        
        newnode->next=NULL;
        
        tailnode->next=newnode;
        
        tailnode=newnode;
        
        header->list_length++;    
        
    }
     
    return header;
    
}


char *s_gets(char *restal,int n)

{
    char *pt;
    
    int i=0;
    
    pt=fgets(restal,n,stdin);
    
    if(pt)
    
    {
        while(restal[i]!='\0'&&restal[i]!='\n') i++;
    
        if(restal[i]=='\n') restal[i]='\0';
    
        else 
    
        while(getchar()!='\n') continue;
    }
    
    
    return pt;    
}

void printList(List header)

{
    List temp;
    
    int i;
    
    temp=header->next;
    
    printf("There are %d student information in this list, which as follow :\n",header->list_length);
    
    while(temp!=NULL) 
    
    {
        i=1;
        
        printf("************\n");
        
        printf("NUMBER %d      %-20s     %d  \n ",i,temp->name,temp->score);
        
        printf("************\n");
        
        i++;
        
        temp=temp->next;    
        
    }    
}

void freeList(List header)

{
    List plist=NULL;
    
    int i=0;
    
    while(header!=NULL)
    
    {
        plist=header;
        
        header=header->next;
        
        free(plist);    
        
        printf("NOW number %d node was free! \n",i++);    
    }
}

不明白的地方 就是 这一步:
freeList(Class_6_student);

if(Class_6_student==NULL)  printf("Free Success! \n");  //这一步总是出不来,好像是 虽然释放了结点,但是并不是完全为空 

printf("Free Success! \n"); 这一步总是不会执行,说明 Class_6_student 链表不为空,可是我已经清空了啊,

因为 while(header!=NULL) (freeList(List header) 函数中) 这一步能够执行完,说明 链表就是NULL了, 为什么到这里 又执行不出来呢?

你好,这个问题其实是你free函数没有掌握好,free的确是会释放掉开辟的空间的,但是他并不会把指向那块空间的指针置为空指针的,也就是说我们在free一块空间的时候都需要将那块空间的指针进行手动的置为空指针的,这是一个重要的良好习惯。

函数参数的传递,本身相当于是一个变量的拷贝

List a = xxx
List b = a;
b = NULL;
//这是a当然不会是NULL

在freeList函数里清空链表是成功了的,可以在freeList里测试
if(header==NULL) printf("Free Success! \n");

但函数不改变main里的链表,所以改为
List freeList(List header)
返回一个链表即可

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

#define  Array_length   40

typedef struct  node

{
    int list_length;

    char name[Array_length];

    int score;

    struct node  *next;
} Node;

typedef Node * List;

List createList(int length);      // 创建一个具有length个结点的链表

void printList(List header);      //打印链表

List freeList(List header);

char *s_gets(char *restal,int n);

int main(void)

{
    List Class_6_student;

    int list_length;

    printf("Please enter the length of the list you will create : \n");

    scanf("%d",&list_length);

    while(getchar()!='\n') ;

    Class_6_student=createList(list_length);

    printList(Class_6_student);

    printf("Now the list will be free. \n");

    Class_6_student=freeList(Class_6_student);

    if(Class_6_student==NULL)  printf("Free Success! \n");  //这一步总是出不来,好像是 虽然释放了结点,但是并不是完全为空

    return 0;


}

List createList(int length)

{
    List header=NULL;

    List newnode=NULL;

    List tailnode=NULL; //定义头结点  新结点  尾结点

    int i;

    header=(List) malloc(sizeof(Node));

    if(header==NULL)  exit(-1);

    header->list_length=0;

    header->next=NULL;

    tailnode=header;

    for(i=0; i<length; i++)

    {
        newnode=(List)malloc(sizeof(Node));

        if(newnode==NULL) exit(-1);

        printf("Please enter the name  of NUMBER %d student : \n",i+1);

        s_gets(newnode->name,Array_length);

        printf("Please enter the score of NUMBER %d student : \n",i+1);

        scanf("%d",&newnode->score);

        while(getchar()!='\n') ;

        newnode->next=NULL;

        tailnode->next=newnode;

        tailnode=newnode;

        header->list_length++;

    }

    return header;

}


char *s_gets(char *restal,int n)

{
    char *pt;

    int i=0;

    pt=fgets(restal,n,stdin);

    if(pt)

    {
        while(restal[i]!='\0'&&restal[i]!='\n') i++;

        if(restal[i]=='\n') restal[i]='\0';

        else

            while(getchar()!='\n') continue;
    }


    return pt;
}

void printList(List header)

{
    List temp;

    int i;

    temp=header->next;

    printf("There are %d student information in this list, which as follow :\n",header->list_length);

    while(temp!=NULL)

    {
        i=1;

        printf("************\n");

        printf("NUMBER %d      %-20s     %d  \n ",i,temp->name,temp->score);

        printf("************\n");

        i++;

        temp=temp->next;

    }
}

List freeList(List header)

{
    List plist=NULL;

    int i=0;

    while(header!=NULL)

    {
        plist=header;

        header=header->next;

        free(plist);

        printf("NOW number %d node was free! \n",i++);
    }
    return header;
   // if(header==NULL)  printf("Free Success! \n");
}

这个原因很简单,就是你在释放完成后没有赋值为NULL,但实际已经释放了,无需担心!

free只是把空间还给系统,里面的内容还是之前的,但是你没有使用权限了,需要手动置空
相当于你开了一间房子,你退房将房子还给酒店,你没有居住权限了,里面有你居住过的痕迹,需要人工打扫收拾(手动置空)


  freeList(Class_6_student);

    Class_6_student=NULL;

    if(Class_6_student==NULL)  printf("Free Success! \n");  
 

img

参数传递本身是有复制操作的,你在freeList函数中虽然吧header清空了,但是这个header并没有传递出去,所以主函数的header不是空,你可以在主函数的printList后面将Class_6_student的地址打印出来,然后在FreeList函数在打印一次header的地址,看看是不是一样的就知道了

List Class_6_student;
这个定义放到main外面,弄成全局变量。就不用参数传递了,也就不会有这种问题