MeowMoo 发表于 2021-1-22 15:06:05

关于链表多次插入的问题

这个程序是创建一个保存学生编号和成绩的链表,然后实现在链表里插入一个学生的信息和成绩。单次插入学生信息的函数我写完了,就是那个add()函数,现在我想用这个函数来实现多次插入信息。我截的这一段程序是输入要插入的学生信息然后调用add函数,完整程序在后面。我的思路是,当addstu这个节点完成插入后,将它释放然后重新赋值,再次插入,但是写的这段代码有问题,问题在哪呢,又该怎么实现多次插入节点?求大佬解答。
while(1)
        {
                addstu=(struct student *)malloc(sizeof(struct student));
                addstu->num=0;
                addstu->score=0;
                addstu->next=NULL;
                printf("请输入你想加入的学生的编号和成绩(输入0结束添加):");
                scanf("%d,%f",&addstu->num,&addstu->score);
                printf("\n");
                add(stu,addstu);
                free(addstu);
                if(0==addstu->num)
                {
                        break;
                }
        }


完整程序:

#include <stdio.h>
#include <malloc.h>


struct student
{
        int num;
        float score;
        struct student *next;
};
int n;
int main(void)
{
        struct student *creat();
        void print(struct student *r);
        void del(struct student *q,int num1);
        void add(struct student *a,struct student *a0);

        int m;
        struct student *stu;
        struct student *addstu;

        stu=creat();
        printf("\nThere are %d record!\n\n",n);
        print(stu);

        printf("请输入你想删除的学生的编号:");
        scanf("%d",&m);
        while(m==0)
        {
                printf("不能为0请重新输入:");
                scanf("%d",&m);
        }
        printf("\n");
        del(stu,m);

        while(1)
        {
                addstu=(struct student *)malloc(sizeof(struct student));
                addstu->num=0;
                addstu->score=0;
                addstu->next=NULL;
                printf("请输入你想加入的学生的编号和成绩(输入0结束添加):");
                scanf("%d,%f",&addstu->num,&addstu->score);
                printf("\n");
                add(stu,addstu);
                free(addstu);
                if(0==addstu->num)
                {
                        break;
                }
        }

        printf("\n\n");
}
struct student *creat()
{
        struct student *p1,*p2,*head;
        n=0;
        head=NULL;
        p2=(struct student *)malloc(sizeof(struct student));
        while(1)
        {
                p1=(struct student *)malloc(sizeof(struct student));
                printf("Please enter this student number:");
                scanf("%d",&p1->num);
                printf("Please enter this student score:");
                scanf("%f",&p1->score);
                if(0==p1->num)
                {
                        break;
                }
                else
                {
                        n++;
                        if(1==n)
                        {
                                head=p1;
                                p2=p1;
                        }
                        else
                        {
                                p2->next=p1;
                                p2=p1;
                        }
                }               
}
        p2->next=NULL;

        return head;
}
void print(struct student *r)
{
       
        while(r)
        {
                printf("第 %d 位学生的成绩是 %.2f\n",r->num,r->score);
                r=r->next;
        }
        printf("\n");
}
void del(struct student *q,int num1)
{
        void print(struct student *r);

        struct student *q1,*q2,*q3;
        q1=q3=q;

        if(q==NULL)
        {
                printf("空表不能操作!");
        }
        else
        {
                while(1)
                {
                        int i=0;
                        while(1)
                        {
                                if(num1==q3->num)
                                {
                                        i=1;
                                        break;
                                }
                                if(q3->next==NULL)
                                {
                                        break;
                                }
                                q3=q3->next;
                        }
                        if(0==i)
                        {
                                printf("没有该学生信息!\n请重新输入:");
                                scanf("%d",&num1);
                                q3=q;
                        }
                        if(1==i)
                                break;
                }
                printf("\n");
                if(num1==q1->num)
                {
                        q=q->next;
                }
                else
                {
                        while(1)
                        {
                                if(num1!=q1->num)
                                {
                                        q2=q1;
                                        q1=q1->next;
                                }
                                else
                                {
                                        q2->next=q1->next;
                                        free(q1);
                                        break;
                                }
                        }
                }
                printf("\nThere are %d record!\n\n",n-1);
                print(q);
                printf("%d号学生成绩已删除\n\n",num1);
        }

}
void add(struct student *a,struct student *a0)
{
        struct student *a1,*a2,*a3;
        a1=a;

        if(a0->num<a->num)//第一种情况,插入节点编号在首节点前
        {
                a0->next=a;
                a=a0;
        }
        else
        {
                while(1)
                {
                        if(a1->next==NULL)
                        {
                                a3=a1;
                                break;
                        }
                        a1=a1->next;
                }

                a1=a;
                if(a0->num>a3->num)
                {
                        a3->next=a0;
                        a0->next=NULL;
                }
                else
                {
                        while(1)
                        {
                                if(a0->num<a1->num)
                                {
                                        a2->next=a0;
                                        a0->next=a1;
                                        break;
                                }
                                a2=a1;
                                a1=a1->next;

                        }
                }
        }
        printf("\nThere are %d record!\n\n",n);
        print(a);//函数嵌套使用
        printf("%d号学生成绩添加成功\n\n",a0->num);
}

xieglt 发表于 2021-1-22 15:57:42

代码太长,没细看。至少有两个主要问题。

1、被链接到链表的节点为什么要 free ? 内存分配后,只要还要使用,就不能 free,free后就不能再去访问。

2、add()这个函数里没有判断表头是否为空,都表头为空时,访问出错。

还有就是 malloc 分配的内存在程序结束前没有 free。
create 函数里,输入学号0 的时候,不生成表头,但是分配的内存又没有释放。

MeowMoo 发表于 2021-1-22 16:13:27

xieglt 发表于 2021-1-22 15:57
代码太长,没细看。至少有两个主要问题。

1、被链接到链表的节点为什么要 free ? 内存分配后,只要还要 ...

哦,去掉free就可以多次了,free函数没仔细去研究,我以为free完后只要重新分配内存就可以用。
add没判断是因为我懒得去写了,然后前面直接声明不让输入0,但是后来前面的声明又改了{:10_266:}
还有我想问一下,你说free后不能用了只是当前函数不能用了吗?
还有你说程序结束前free,是在主程序的末尾free吗?如果不free会怎么样?
求大哥解答!

xieglt 发表于 2021-1-22 16:32:44

MeowMoo 发表于 2021-1-22 16:13
哦,去掉free就可以多次了,free函数没仔细去研究,我以为free完后只要重新分配内存就可以用。
add没判 ...

分配的内存不释放会造成内存泄露。
如果你的程序一直在分配内存而不释放,会造成系统可用内存越来越少,最后只能重启电脑了。

当你确定你分配的内存不再使用时就可以free。当你无法确认你分配的内存用不用,就在 main 函数尾部free

MeowMoo 发表于 2021-1-22 16:45:13

xieglt 发表于 2021-1-22 16:32
分配的内存不释放会造成内存泄露。
如果你的程序一直在分配内存而不释放,会造成系统可用内存越来越少, ...

我刚刚试了在子函数释放内存很容易出错,但是我有个疑问,形参在使用完成后不是系统会自动释放内存吗,意思子函数内部是不是不必使用free函数,只需要在main函数执行free操作就行了?

xieglt 发表于 2021-1-22 16:53:31

MeowMoo 发表于 2021-1-22 16:45
我刚刚试了在子函数释放内存很容易出错,但是我有个疑问,形参在使用完成后不是系统会自动释放内存吗,意 ...

好难解释。
子函数内部分配的内存,如果能把内存指针传出来,在main里面free就可以。
比如说链表节点,这个节点在后面还要使用的,你malloc出来立刻又free掉
跟没有malloc有什么区别?如果不能传递出来,就在子函数内部free.


MeowMoo 发表于 2021-1-22 17:00:18

xieglt 发表于 2021-1-22 16:53
好难解释。
子函数内部分配的内存,如果能把内存指针传出来,在main里面free就可以。
比如说链表节点, ...

哈哈哈好吧,我再研究一下,谢谢你

MeowMoo 发表于 2021-1-25 11:03:43

xieglt 发表于 2021-1-22 16:53
好难解释。
子函数内部分配的内存,如果能把内存指针传出来,在main里面free就可以。
比如说链表节点, ...

哥我再请教一下关于free函数的问题,是不是可以这样理解,只有直接使用malloc函数分配内存的变量才需要去free,而在其他函数调用这些变量的形参是不用去free的,除非在函数内又使用了malloc。比如我在main函数用malloc给p1分配了内存,然后在子函数的形参q1调用了p1,那q1是不用free的?

xieglt 发表于 2021-1-25 11:29:59

本帖最后由 xieglt 于 2021-1-25 11:31 编辑

MeowMoo 发表于 2021-1-25 11:03
哥我再请教一下关于free函数的问题,是不是可以这样理解,只有直接使用malloc函数分配内存的变量才需要去 ...

没错。凡是用malloc , calloc , realloc 分配的内存都需要用free 去释放。
通常遵循谁分配,谁释放的原则。需要传递到函数外面的指针例外。
所以通常尽量少用(不用)在函数里分配内存,传递到函数外面,因为有可能会忘记free。

1、主函数里分配,主函数里释放

void fun1 (char * buffer)
{
   strcpy(buffer,"Hello,world");
}

int main()
{
    char * str = (char *)malloc(100);
    fun1(str);
    printf("%s",str);
    free(str);
    return 0;
}


2、子函数里分配,子函数里释放

voidfun2()
{
      char * temp = (char *)malloc(100);
      strcpy(temp,"hello,world");
      printf("%s\n",temp);
      free(temp);
}

int main()
{
      fun2();
}


3、子函数里分配,main里释放
(这是非常差的编程习惯,尤其是当你的函数编译成库提供给别人用的时候,别人无法把握这个指针需不需要释放)

char * fun3()
{
      char * buffer = (char *)malloc(100);
      strcpy(buffer,"hello,world");
      return buffer;
}

int main()
{
       char * str = fun3();
       printf("%s\n",str);
       free(str);
       return 0;
}

xieglt 发表于 2021-1-25 11:49:33

MeowMoo 发表于 2021-1-25 11:03
哥我再请教一下关于free函数的问题,是不是可以这样理解,只有直接使用malloc函数分配内存的变量才需要去 ...

操作系统对内存管理通常是这样的。
用户程序提出内存分配申请 ----> 操作系统在内存中寻找一块符合用户申请大小的内存,如找到,将
这块内存标记为已使用,并将内存地址返回给用户,如找不到,则返回null ---> 用户使用完内存,free
内存 ----> 操作系统接到free请求,将该块内存标记为未使用。

如果你只分配内存,却不释放。那么系统里的内存渐渐地都被标记为已使用,最后导致无内存可用。

MeowMoo 发表于 2021-1-25 13:19:27

xieglt 发表于 2021-1-25 11:49
操作系统对内存管理通常是这样的。
用户程序提出内存分配申请 ----> 操作系统在内存中寻找一块符合用户 ...

好的,明白了,非常感谢!
页: [1]
查看完整版本: 关于链表多次插入的问题