鱼C论坛

 找回密码
 立即注册
查看: 1237|回复: 7

[已解决]发了两次贴还是没搞懂为什么释放内存会错。。。拜托求解!

[复制链接]
发表于 2023-6-26 22:10:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
首先申明此代码不释放内存已经验证通过测试题检测

题目:

设计函数分别求两个一元多项式的乘积与和。
输入格式:

输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
输出格式:

输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。
输入样例:

4 3 4 -5 2  6 1  -2 0
3 5 20  -7 4  3 1

输出样例:

15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0

我的代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. typedef struct Node *node;
  4. struct Node
  5. {
  6.     int x;
  7.     int z;
  8.     node next;
  9. };

  10. node read();
  11. void print(node list);
  12. node he(node list1,node list2);
  13. node ji(node list1,node list2);
  14. void freeList(node head);

  15. node read()
  16. {
  17.         int i;
  18.         scanf("%d",&i);
  19.         node head = (node)malloc(sizeof(node));
  20.         head->next = NULL;
  21.         node p = head;
  22.         
  23.         while(i--)
  24.         {
  25.                 node temp = (node)malloc(sizeof(node));
  26.                 scanf("%d %d",&temp->x,&temp->z);
  27.                 p->next = temp;
  28.                 p = p->next;
  29.         }
  30.         p->next = NULL;
  31.         
  32.         return head;
  33. }

  34. node he(node list1,node list2)
  35. {
  36.         node temp;
  37.         node head = (node)malloc(sizeof(struct Node));
  38.         head->next = NULL;
  39.         node p = head;
  40.         
  41.         if(list2->next == NULL)
  42.         {
  43.         
  44.                 return list1;

  45.                 }
  46.         else
  47.         {
  48.                 list1 = list1->next;
  49.                 list2 = list2->next;

  50.                 while(list1 && list2)
  51.                 {
  52.                         
  53.                         temp = (node)malloc(sizeof(struct Node));
  54.                         if(list1->z == list2->z)
  55.                         {        
  56.                                 temp->x = list1->x + list2->x;
  57.                                 temp->z = list1->z;
  58.                                 list1 = list1->next;
  59.                                 list2 = list2->next;
  60.                         }
  61.                         else if(list1->z > list2->z)
  62.                         {
  63.                                 temp->x = list1->x;
  64.                                 temp->z = list1->z;
  65.                                 list1 = list1->next;
  66.                         }
  67.                         else
  68.                         {
  69.                                 temp->x = list2->x;
  70.                                 temp->z = list2->z;
  71.                                 list2 = list2->next;
  72.                         }
  73.                         p->next = temp;
  74.                         p = p->next;                        
  75.                 }
  76.                 for(;list1;list1 = list1->next)temp = (node)malloc(sizeof(struct Node)),temp->x = list1->x,temp->z = list1->z,p->next = temp,p = p->next;
  77.                 for(;list2;list2 = list2->next)temp = (node)malloc(sizeof(struct Node)),temp->x = list2->x,temp->z = list2->z,p->next = temp,p = p->next;
  78.                 p->next = NULL;
  79.                
  80.               
  81.         return head;
  82.         }
  83. }

  84. node ji(node list1,node list2)
  85. {
  86.         
  87.         node t,L = (node)malloc(sizeof(struct Node));
  88.         L->next = NULL;
  89.         list1 = list1->next;
  90.         list2 = list2->next;
  91.                
  92.         for(list1;list1;list1=list1->next)
  93.         {
  94.                 node temp;
  95.                 node head = (node)malloc(sizeof(struct Node));
  96.                 head->next = NULL;
  97.                 node p = head;
  98.                 for(t = list2;t;t=t->next)
  99.                 {
  100.                         temp = (node)malloc(sizeof(struct Node));
  101.                         temp->x = list1->x * t->x;
  102.                         temp->z = list1->z + t->z;

  103.                         p->next = temp;
  104.                         p = p->next;
  105.                 }
  106.                 p->next = NULL;
  107.               
  108.                 printf("合并前head:");
  109.                 print(head);
  110.                 printf("合并前L:");
  111.                 print(L);
  112.                 L = he(head,L);
  113.                 printf("合并后head:");
  114.                 print(head);
  115.                 printf("合并后L:");
  116.                 print(L);


  117.                 freeList(head);



  118.         }
  119.         //L->next = NULL;
  120.         return L;
  121.                
  122. }

  123. void freeList(node head)
  124. {
  125.     node temp;
  126.     while (head != NULL)
  127.         {
  128.         temp = head;
  129.         head = head->next;
  130.         free(temp);
  131.     }
  132. }

  133. void print(node list)
  134. {
  135. //        node t = list;
  136.         int flag = 1;
  137.         if(list->next)
  138.         list = list->next;
  139.         else
  140.         {
  141.                 printf("0 0\n");
  142.                 return;
  143.          }
  144.         for(;list;list = list->next)
  145.         {
  146.                 if(!flag && list->x)   //控制空格输出
  147.                         printf(" ");
  148.                 if(list->x){   // 如果系数为 0,不输出
  149.                         printf("%d %d",list->x,list->z);
  150.                         flag =0;               
  151.                 }
  152.         }
  153.         if(flag)
  154.                 printf("0 0");
  155.         printf("\n");
  156. }



  157. int main()
  158. {
  159.     node list1,list2;
  160.     list1 = read();
  161.     list2 = read();

  162. //   print(list1);
  163. //   print(list2);
  164.         print(ji(list1,list2));
  165.        // print(he(list1,list2));
  166.         
  167.         freeList(list1);
  168.         freeList(list2);

  169.   return 0;
  170. }
复制代码


问题我在求两个一元多项式乘积的函数  node ji(node list1,node list2);
里释放掉一个临时生成的单链表(因为一元多项式乘积是依次各项相乘再相加 从而我遍历了两个一元多项式相乘另一个多项式 前一个每一项的多项式乘以后一个多项式每一项生成一个分配了空间的临时链表头节点为head  然后传入求和函数node he(node list1,node list2);
合并掉相同的指数项 得到一个新的合并后并分配了内存空间的链表头节点为L 这个新链表是在求和函数node he(node list1,node list2);中新生成的链表  我理解应该来说是和求积函数node ji(node list1,node list2);
的head链表是相互独立的存在  所以free掉这个临时的单链表  然后进入到第一个一元多项式下一个项依次乘以另一个多项式的项生成新的链表头节点为head  但是我free掉head这个链表之后  L链表就受到影响 L链表是求和里面return出来的 请问大佬是什么原因了! 拜托求解!)

这是在求积函数中测试段代码和释放内存函数
  1. printf("合并前head:");
  2.                 print(head);
  3.                 printf("合并前L:");
  4.                 print(L);
  5.                 L = he(head,L);
  6.                 printf("合并后head:");
  7.                 print(head);
  8.                 printf("合并后L:");
  9.                 print(L);


  10.                 freeList(head);
复制代码


ef593654dd1d91499efe9074f4354ac.png

最佳答案
2023-6-26 22:17:32
您的问题在于,您试图释放在  he()  函数内部创建并返回的链表(通过  L = he(head,L);  语句),然后立即释放该链表的原始版本( head )。在  he()  函数中,您并没有创建新的节点,而是重新使用了  head  和  L  中的节点。这就意味着  L  和  head  实际上是共享一些节点的,这就解释了为什么当你释放  head  时, L  也受到影响。

所以,当您在  ji()  函数中执行  freeList(head);  时,其实就是释放了  L  中的一部分或全部节点。这样做是不正确的,因为这些节点仍在  L  中使用。在释放  head  后, L  中的这些节点已经被释放,所以再次访问它们(例如,通过  print(L) )就会出现错误。

解决这个问题的一种方法是,在  he()  函数中创建新的节点,而不是重用  head  和  L  中的节点。这样,您可以安全地在  ji()  函数中释放  head ,因为它不再与  L  共享任何节点。

以下是一种可能的解决方案,将您的  he()  函数修改为:

  1. node he(node list1,node list2)
  2. {
  3.     node head = (node)malloc(sizeof(struct Node));
  4.     head->next = NULL;
  5.     node p = head;

  6.     list1 = list1->next;
  7.     list2 = list2->next;

  8.     while(list1 && list2)
  9.     {
  10.         node temp = (node)malloc(sizeof(struct Node));
  11.         if(list1->z == list2->z)
  12.         {        
  13.             temp->x = list1->x + list2->x;
  14.             temp->z = list1->z;
  15.             list1 = list1->next;
  16.             list2 = list2->next;
  17.         }
  18.         else if(list1->z > list2->z)
  19.         {
  20.             temp->x = list1->x;
  21.             temp->z = list1->z;
  22.             list1 = list1->next;
  23.         }
  24.         else
  25.         {
  26.             temp->x = list2->x;
  27.             temp->z = list2->z;
  28.             list2 = list2->next;
  29.         }
  30.         p->next = temp;
  31.         p = p->next;                        
  32.     }

  33.     while(list1) {
  34.         node temp = (node)malloc(sizeof(struct Node));
  35.         temp->x = list1->x;
  36.         temp->z = list1->z;
  37.         p->next = temp;
  38.         p = p->next;
  39.         list1 = list1->next;
  40.     }

  41.     while(list2) {
  42.         node temp = (node)malloc(sizeof(struct Node));
  43.         temp->x = list2->x;
  44.         temp->z = list2->z;
  45.         p->next = temp;
  46.         p = p->next;
  47.         list2 = list2->next;
  48.     }

  49.     p->next = NULL;

  50.     return head;
  51. }
复制代码

我这里对您原有的代码进行了一些修改,使其在合并链表时,始终生成新的节点,而不是复用原有的节点。这样就解决了原有的问题。希望这个解答对您有所帮助!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-6-26 22:12:45 | 显示全部楼层
问题出在这段代码中:

  1. printf("合并前head:");
  2. print(head);
  3. printf("合并前L:");
  4. print(L);
  5. L = he(head,L);
  6. printf("合并后head:");
  7. print(head);
  8. printf("合并后L:");
  9. print(L);

  10. freeList(head);
复制代码

在执行L = he(head, L);之后,L的值被修改为了合并后的链表,而head仍然指向原来的链表。所以当执行freeList(head);时,实际上是释放了合并前的临时链表,但是L仍然指向这个已经被释放的内存空间。

解决这个问题的方法是,在释放完合并前的链表之后,将head赋值为NULL,避免对已经释放的内存进行操作。修改的代码如下:

  1. printf("合并前head:");
  2. print(head);
  3. printf("合并前L:");
  4. print(L);
  5. L = he(head, L);
  6. printf("合并后head:");
  7. print(head);
  8. printf("合并后L:");
  9. print(L);

  10. freeList(head);
  11. head = NULL;
复制代码

这样就可以确保在释放内存之后不再使用已经释放的指针了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-26 22:17:32 | 显示全部楼层    本楼为最佳答案   
您的问题在于,您试图释放在  he()  函数内部创建并返回的链表(通过  L = he(head,L);  语句),然后立即释放该链表的原始版本( head )。在  he()  函数中,您并没有创建新的节点,而是重新使用了  head  和  L  中的节点。这就意味着  L  和  head  实际上是共享一些节点的,这就解释了为什么当你释放  head  时, L  也受到影响。

所以,当您在  ji()  函数中执行  freeList(head);  时,其实就是释放了  L  中的一部分或全部节点。这样做是不正确的,因为这些节点仍在  L  中使用。在释放  head  后, L  中的这些节点已经被释放,所以再次访问它们(例如,通过  print(L) )就会出现错误。

解决这个问题的一种方法是,在  he()  函数中创建新的节点,而不是重用  head  和  L  中的节点。这样,您可以安全地在  ji()  函数中释放  head ,因为它不再与  L  共享任何节点。

以下是一种可能的解决方案,将您的  he()  函数修改为:

  1. node he(node list1,node list2)
  2. {
  3.     node head = (node)malloc(sizeof(struct Node));
  4.     head->next = NULL;
  5.     node p = head;

  6.     list1 = list1->next;
  7.     list2 = list2->next;

  8.     while(list1 && list2)
  9.     {
  10.         node temp = (node)malloc(sizeof(struct Node));
  11.         if(list1->z == list2->z)
  12.         {        
  13.             temp->x = list1->x + list2->x;
  14.             temp->z = list1->z;
  15.             list1 = list1->next;
  16.             list2 = list2->next;
  17.         }
  18.         else if(list1->z > list2->z)
  19.         {
  20.             temp->x = list1->x;
  21.             temp->z = list1->z;
  22.             list1 = list1->next;
  23.         }
  24.         else
  25.         {
  26.             temp->x = list2->x;
  27.             temp->z = list2->z;
  28.             list2 = list2->next;
  29.         }
  30.         p->next = temp;
  31.         p = p->next;                        
  32.     }

  33.     while(list1) {
  34.         node temp = (node)malloc(sizeof(struct Node));
  35.         temp->x = list1->x;
  36.         temp->z = list1->z;
  37.         p->next = temp;
  38.         p = p->next;
  39.         list1 = list1->next;
  40.     }

  41.     while(list2) {
  42.         node temp = (node)malloc(sizeof(struct Node));
  43.         temp->x = list2->x;
  44.         temp->z = list2->z;
  45.         p->next = temp;
  46.         p = p->next;
  47.         list2 = list2->next;
  48.     }

  49.     p->next = NULL;

  50.     return head;
  51. }
复制代码

我这里对您原有的代码进行了一些修改,使其在合并链表时,始终生成新的节点,而不是复用原有的节点。这样就解决了原有的问题。希望这个解答对您有所帮助!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-26 23:18:51 | 显示全部楼层
isdkz 发表于 2023-6-26 22:17
您的问题在于,您试图释放在  he()  函数内部创建并返回的链表(通过  L = he(head,L);  语句),然后立即 ...

感谢!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-27 08:13:19 | 显示全部楼层
sfqxx 发表于 2023-6-26 22:12
问题出在这段代码中:

555你能不能罢工一天
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-27 09:12:03 | 显示全部楼层

不可以
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-6-27 09:15:11 From FishC Mobile | 显示全部楼层
sfqxx 发表于 2023-6-27 09:12
不可以

哎(叹息)
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-6-27 11:59:24 From FishC Mobile | 显示全部楼层
还有个问题能回答我一下吗?为什么你给出的代码 temp结构体指针要在每次循环里定义分配内存空间。 而我是在he函数一开始就声明一个temp结构体指针,再在每个循环里定义malloc分配内存空间。这两种做法有什么区别吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 02:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表