鱼C论坛

 找回密码
 立即注册
查看: 1566|回复: 18

[已解决]C++里加了delete语句就报错,不加就可以运行,请问我释放内存的操作哪里有问题?

[复制链接]
发表于 2019-6-1 16:08:39 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 菜鸟小乔 于 2019-6-1 16:14 编辑

代码功能:创建循环链表,实现初始化赋值、插入元素的功能。(目前只写了插入函数、初始化函数)

问题描述:在插入函数和打印函数里,用new分配内存,在函数结尾delete释放——报错读取访问冲突。
                如果把delete语句注释掉程序就可以运行,但感觉这样不严谨。

求助大神们帮忙看看,我的delete语句为什么释放内存出错?

完整代码如下:(出错的delete语句在.cpp文件69行处、94行处)

--------C_list.h文件---------数据类型定义、函数声明---------------------------
  1. #ifndef CircularLinkList_h_include
  2. #define CircularLinkList_h_include
  3. /*    《循环链表》
  4. */
  5. #include<iostream>
  6. #include<string>
  7. using namespace std;

  8. //#define MAX_SIZE 255
  9. //#define  TRUE 1
  10. //#define  FALSE 0

  11. //定义一种数据类型
  12. typedef struct {
  13.         int id;
  14.         string name ="初始名字";
  15. }EleType;

  16. //循环链表节点,
  17. typedef struct Node {
  18.         EleType data;
  19.         struct Node* next;
  20. }Node;

  21. //定义 循环链表的结构
  22. typedef struct C_LinkList {
  23.         Node* next;        //头指针(有头节点,)
  24.         int length;        //链表长度,初始值为0.
  25. }C_LinkList;


  26. //插入元素
  27. void Insert(C_LinkList* list_c, int pos, EleType element);

  28. //初始化
  29. void Init(C_LinkList* list_c, EleType* dataArray, int len);

  30. //打印
  31. void Print(C_LinkList* list_c);

  32. #endif
复制代码

--------.cpp文件------------函数实现-------------------------
  1. #include<iostream>
  2. #include<string>
  3. #include"C_list.h"
  4. using namespace std;

  5. //初始化
  6. void Init(C_LinkList* list_c, EleType* dataArray, int len)
  7. {
  8.         for (int i = 0; i < len; i++)
  9.         {
  10.                 Insert(list_c, i + 1, dataArray[i]);
  11.         }

  12. }

  13. //插入元素
  14. void Insert(C_LinkList* list_c, int pos, EleType element)
  15. {
  16.         Node* node = new Node;
  17.         node->data = element;
  18. //        element.id = 5;
  19. //        element.name = "名字";
  20.         node->next = NULL;

  21.         if (pos == 1)
  22.         {
  23.                 node->next = list_c->next;

  24.                 if (!node->next) //如果链表长度为零
  25.                 {
  26.                         //cout << "长度为零" << endl;
  27.                         node->next = node;
  28.                 }
  29.                 else//长度不为零,找到最后一个节点,并改变其指针域
  30.                 {
  31.                         //cout << "长度不为零" << endl;
  32.                         Node* lastnode = list_c->next;
  33.                         for (int i = 1; i < list_c->length; i++)
  34.                         {
  35.                                 lastnode = lastnode->next;
  36.                         }
  37.                         lastnode->next = node;
  38.                 }
  39.                 list_c->next = node;
  40.                 list_c->length++;
  41.                 return;
  42.         }//

  43.         //cout << "pos不等于1" << endl;                //插入pos不是第一个,从第一个开始遍历
  44.         Node* currNode = new Node;       
  45.         currNode->next = NULL;
  46.        
  47.         currNode = list_c->next;               
  48.         for (int i = 1; currNode && i < pos - 1; i++)
  49.         {
  50.                 currNode = currNode->next;
  51.         }
  52.         if (currNode)
  53.         {
  54.                 //cout << "pos不等于1" << endl;
  55.                 node->next = currNode->next;
  56.                 currNode->next = node;
  57.                 list_c->length++;
  58.                 if (pos == list_c->length)//如果是最后一个结点
  59.                 {
  60.                         node->next = list_c->next;//改变最后一个节点的指针域为指向第一个结点
  61.                 }
  62.         }
  63.         //delete node;                        //这里4行释放内存的语句加进去,也报错读取访问冲突。
  64.         //node = NULL;
  65.         //delete currNode;
  66.         //currNode->next = NULL;
  67. }
  68. ///////////////////////////////////
  69. void Print(C_LinkList *list_c)
  70. {
  71.         if (list_c->length == 0 || list_c->next == NULL)
  72.         {
  73.                 cout << "链表为空,无内容可打印!" << endl;
  74.                 list_c->length = 0;
  75.                 return;
  76.         }

  77.         Node* node = new Node;
  78.         node->next = NULL;
  79.        
  80.         node = list_c->next;        //创建临时结点第一个结点开始遍历
  81.        
  82.                 for (int i = 0; i < list_c->length; i++)
  83.                 {
  84.                         cout << node->data.id << ":" << node->data.name << endl;
  85.                         node = node->next;       
  86.                 }
  87.                 //delete node;                //添加delete就会报错,访问冲突。
  88.                 //node = NULL;
  89. cout << "*****打印结束*******" << endl;
  90. }
复制代码

--------main.cpp文件----------------------------
  1. #include<iostream>
  2. #include<string>
  3. #include"C_list.h"
  4. using namespace std;

  5. //测试数据
  6. EleType dataArray[]{
  7.         {1,"香蕉"},
  8.         {2,"樱桃"},
  9.         {3,"菠萝"},
  10.         {4,"苹果"}
  11. };
  12. //测试函数
  13. void test();

  14. int main()
  15. {
  16.         test();
  17.         return 0;
  18. }
  19. ////////////////
  20. void test()
  21. {
  22.         C_LinkList* clist = new C_LinkList;
  23.         clist->next = NULL;
  24.         clist->length = 0;
  25.        
  26.         Init(clist, dataArray, 4);//初始化赋值
  27.         Print(clist);//打印

  28.         Insert(clist, 1, dataArray[0]);//插入
  29.         Print(clist);//打印

  30.         Insert(clist, 2, dataArray[1]);
  31.         Print(clist);//打印

  32.         delete clist;
  33.         clist = NULL;
  34. }
复制代码

最佳答案
2019-6-1 20:29:11
菜鸟小乔 发表于 2019-6-1 18:53
delete node;这个操作是释放node指向的内存,这个我理解;
但是为什么这里不能直接释放块内存呢?这块 ...

你的变量是临时的,可是链表里面的空间并不是.你把new出来的节点直接接插入链表,即该地址以后还会用,所以不能delete
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-6-1 16:33:57 | 显示全部楼层
本帖最后由 Krant5 于 2019-6-1 16:52 编辑

new出来的节点,刚刚才插入链表,是不能释放的 在销毁链表时候释放就好
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 16:53:15 | 显示全部楼层
Krant5 发表于 2019-6-1 16:33
好好的new出来的节点,刚刚才插入链表,你释放他干啥啊? 就不能销毁链表时候再释放吗?,你这是在破坏链表结构

我把它理解为:相当于一个临时变量,函数执行完了,就没用了。。。。

而且函数内部的new出来的变量,只能用在函数内部,释放也应该在函数内部释放吧。。。。


是我理解错了吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 16:58:45 | 显示全部楼层
菜鸟小乔 发表于 2019-6-1 16:53
我把它理解为:相当于一个临时变量,函数执行完了,就没用了。。。。

而且函数内部的new出来的变量, ...

那你就用局部变量咯,插入链表的还是new出来那个对象,是不能释放的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 17:03:00 | 显示全部楼层
Krant5 发表于 2019-6-1 16:58
那你就用局部变量咯,插入链表的还是new出来那个对象,是不能释放的

下面这段插入功能的函数,node是在这个函数里定义的,难道它不是局部变量吗?
  1. void Insert(C_LinkList* list_c, int pos, EleType element)
  2. {
  3.         Node* node = new Node;
  4.         node->data = element;
  5. //        element.id = 5;
  6. //        element.name = "名字";
  7.         node->next = NULL;

  8.         if (pos == 1)
  9.         {
  10.                 node->next = list_c->next;

  11.                 if (!node->next) //如果链表长度为零
  12.                 {
  13.                         //cout << "长度为零" << endl;
  14.                         node->next = node;
  15.                 }
  16.                 else//长度不为零,找到最后一个节点,并改变其指针域
  17.                 {
  18.                         //cout << "长度不为零" << endl;
  19.                         Node* lastnode = list_c->next;
  20.                         for (int i = 1; i < list_c->length; i++)
  21.                         {
  22.                                 lastnode = lastnode->next;
  23.                         }
  24.                         lastnode->next = node;
  25.                 }
  26.                 list_c->next = node;
  27.                 list_c->length++;
  28.                 return;
  29.         }//

  30.         //cout << "pos不等于1" << endl;                //插入pos不是第一个,从第一个开始遍历
  31.         Node* currNode = new Node;       
  32.         currNode->next = NULL;
  33.        
  34.         currNode = list_c->next;               
  35.         for (int i = 1; currNode && i < pos - 1; i++)
  36.         {
  37.                 currNode = currNode->next;
  38.         }
  39.         if (currNode)
  40.         {
  41.                 //cout << "pos不等于1" << endl;
  42.                 node->next = currNode->next;
  43.                 currNode->next = node;
  44.                 list_c->length++;
  45.                 if (pos == list_c->length)//如果是最后一个结点
  46.                 {
  47.                         node->next = list_c->next;//改变最后一个节点的指针域为指向第一个结点
  48.                 }
  49.         }
  50.         //delete node;                        //这里4行释放内存的语句加进去,也报错读取访问冲突。
  51.         //node = NULL;
  52.         //delete currNode;
  53.         //currNode->next = NULL;
  54. }
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 17:08:33 | 显示全部楼层
菜鸟小乔 发表于 2019-6-1 17:03
下面这段插入功能的函数,node是在这个函数里定义的,难道它不是局部变量吗?


学C/C++的还是要了解一下栈内存和堆内存还有指针,node是局部变量没错了,但是你delete node / free(node)操作的是node本身吗???????????????=====>你操作的是node指向的地址,不是node变量本身!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 17:18:01 | 显示全部楼层
菜鸟小乔 发表于 2019-6-1 17:03
下面这段插入功能的函数,node是在这个函数里定义的,难道它不是局部变量吗?

另外局部变量会自动销毁,就更加用不着释放了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 18:29:15 | 显示全部楼层
怎么老是你
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 18:45:02 | 显示全部楼层

因为初学,每天都遇到各种问题。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 18:48:44 | 显示全部楼层
本帖最后由 我就是个弟弟 于 2019-6-1 18:50 编辑
菜鸟小乔 发表于 2019-6-1 18:45
因为初学,每天都遇到各种问题。。。

  1. void Print(C_LinkList *list_c)
  2. {
  3.         if (list_c->length == 0 || list_c->next == NULL)
  4.         {
  5.                 cout << "链表为空,无内容可打印!" << endl;
  6.                 list_c->length = 0;
  7.                 return;
  8.         }

  9.         Node* node = new Node;
  10.         node->next = NULL;

  11.         node = list_c->next;        //创建临时结点第一个结点开始遍历

  12.                 for (int i = 0; i < list_c->length; i++)
  13.                 {
  14.                         cout << node->data.id << ":" << node->data.name << endl;
  15.                         node = node->next;
  16.                 }
  17.                 //delete node;                //添加delete就会报错,访问冲突。
  18.                 //node = NULL;
  19. cout << "*****打印结束*******" << endl;
  20. }
复制代码


        Node* node = new Node;
        node->next = NULL;

        node = list_c->next;        //创建临时结点第一个结点开始遍历
这一段有错误吧
刚刚申请的内存就没有指针指向了,
应该写成
Node *node = nullptr; 才对吧
你这个node就是想顺着链表走一遍是吧,你就直接Node *node = nullptr; 就行了
要不然const Node *node = nullptr;这样好一些。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 18:53:10 | 显示全部楼层
Krant5 发表于 2019-6-1 17:08
学C/C++的还是要了解一下栈内存和堆内存还有指针,node是局部变量没错了,但是你delete node / free(node ...

delete node;这个操作是释放node指向的内存,这个我理解;
但是为什么这里不能直接释放块内存呢?这块内存不就是用来存放一个临时的结点吗,函数都执行完了,这个临时结点也不需要了,为什么不能delete呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 18:59:24 | 显示全部楼层
本帖最后由 菜鸟小乔 于 2019-6-1 19:04 编辑
我就是个弟弟 发表于 2019-6-1 18:48
Node* node = new Node;
        node->next = NULL;


没有啊,
Node* node = new Node;  //让node指向一块新申请的内存;
node->next = NULL;  //因为node里面包含指针域 Node*next,要给这个指针 Node*next赋初值NULL,不然Node*next就成野指针了。

        你是不是理解成node=NULL了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 19:04:28 | 显示全部楼层
程序运行是要装载到内存中的。 内存不是一坨浆糊是有人为(操作系统)划分的
程序中有的变量时存放在栈中的,有的变量时存放在自由存储区(堆)中的,函数中声明定义的变量都是存放在栈中的
C++中使用new 申请的内存时从自由存储区中申请的内存。
栈中的数据不能使用delete回收,
栈中的数据,不是回收,而是栈顶指针覆盖。(CPU老子很忙的,没时间把一堆零写道内存中)


弟弟的小小见解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 19:08:31 | 显示全部楼层
我就是个弟弟 发表于 2019-6-1 19:04
程序运行是要装载到内存中的。 内存不是一坨浆糊是有人为(操作系统)划分的
程序中有的变量时存放在栈中 ...

new出来的是node指向的堆内存,我现在就是想要释放这个堆内存,难道delete node执行的不是这个操作吗?

我要晕了。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 19:08:50 | 显示全部楼层
本帖最后由 我就是个弟弟 于 2019-6-1 19:11 编辑
菜鸟小乔 发表于 2019-6-1 18:59
没有啊,
Node* node = new Node;  //让node指向一块新申请的内存;
node->next = NULL;  //因为node ...


  1.     Node* node = new Node;
  2.     node->next = NULL;
  3.     node = list_c->next;        //创建临时结点第一个结点开始遍历
复制代码

不是,你再解释一遍,你是不是对指针有什么误解。
指针的初始化时指针的初始化,
Node的初始化时Node的事情。

指针指向的时地址,地址呀。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 19:13:02 | 显示全部楼层
菜鸟小乔 发表于 2019-6-1 19:08
new出来的是node指向的堆内存,我现在就是想要释放这个堆内存,难道delete node执行的不是这个操作吗?
...

哈哈哈,晕就对了,第一次都晕。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-1 19:54:57 | 显示全部楼层
我就是个弟弟 发表于 2019-6-1 19:08
不是,你再解释一遍,你是不是对指针有什么误解。
指针的初始化时指针的初始化,
Node的初始化时No ...


Node是一个结点的数据类型,结点本身就包含了一个指向下一节点的指针next,所以初始化node,还要初始化它所包含的node->next。前两句是创建了一个空的结点,第三句把链表第一个结点赋给这个空结点。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 20:29:11 | 显示全部楼层    本楼为最佳答案   
菜鸟小乔 发表于 2019-6-1 18:53
delete node;这个操作是释放node指向的内存,这个我理解;
但是为什么这里不能直接释放块内存呢?这块 ...

你的变量是临时的,可是链表里面的空间并不是.你把new出来的节点直接接插入链表,即该地址以后还会用,所以不能delete
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-6-2 13:26:04 | 显示全部楼层
本帖最后由 菜鸟小乔 于 2019-6-2 13:30 编辑
Krant5 发表于 2019-6-1 20:29
你的变量是临时的,可是链表里面的空间并不是.你把new出来的节点直接接插入链表,即该地址以后还会用,所以 ...


哦~好像理解了~多谢大神指点~~~

PS:不好意思啊,我级别太低,还没有权限添加好友。。。尴尬。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-14 01:45

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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