C26.【C++ Cont】动态内存管理和面向对象的方式实现链表

embedded/2025/1/31 15:58:21/

🧨🧨🧨🧨🧨🧨🧨🧨🧨除夕篇🧨🧨🧨🧨🧨🧨🧨🧨🧨

目录

1.知识回顾

2.两个操作符

new操作符

示例代码1:申请一个变量

示例代码2:申请连续的内存空间

delete操作符

示例代码3


1.知识回顾

C语言中的动态内存管理知识回顾:

68.【C语言】动态内存管理(重点)(1)

69.【C语言】动态内存管理(重点)(2)

70.【C语言】动态内存管理(重点)(3)

71.【C语言】动态内存管理(重点)(4)

E37.【C语言】动态内存管理练习题

2.两个操作符

和C语言一样,在堆区上自行申请空间和释放空间,注意:new和delete应该配对使用

new操作符

new申请一个变量的空间,new[ ]申请一个数组的空间

new返回的是申请到的内存空间的起始地址,因此需要指针来接收

示例代码1:申请一个变量

格式:new 数据类型 或 new 数据类型(初始值)

//p1指向申请的int类型的空间,但未初始化
int* p1 = new int;
if (p1==nullptr)
{perror("new");return 1;
}//p2指向申请的int类型的空间,已初始化为5
int* p2 = new int(5); 
if (p2==nullptr)
{perror("new");return 1;
}

注:为防止new开辟空间失败,建议判断p1和p2是否为空,或者assert断言

VS2022调试模式下在内存窗口输入&p1

再跳到0x0128a288查看,4字节的cd,显然未初始化

VS2022调试模式下在内存窗口输入&p2

再跳到0x0128a2b8查看,为05 00 00 00,已初始化为5

示例代码2:申请连续的内存空间

申请连续的内存空间即申请数组空间

格式:new 数据类型[元素个数]

int* p3 = new int[10];//申请10个int类型的空间

注:new不是只能给内置类型开辟空间,也可以给自定义类型开辟空间,例如结构体

delete操作符

delete负责释放一个变量的空间,delete[ ]释放一个数组的空间

格式:delete 指针 或 delete[] 指针(数组的空间)

示例代码3

	int* p1 = new int;if (p1==nullptr){perror("new");return 1;}int* p2 = new int(5);if (p2==nullptr){perror("new");return 1;}int* p3 = new int[10];if (p1==nullptr){perror("new");return 1;}delete p1;p1 = nullptr;delete p2;p2 = nullptr;delete[] p3;p3 = nullptr;

要养成良好的习惯,delete后防止野指针要手动为指针置空

有关malloc和new,delete和free的区别这里不做讲解,竞赛中只需要知道怎么用就行

注意:在竞赛中数据结构的模拟实现不会采用malloc和free或者 new 和 delete 的方式,代码量大和运行速度慢而是采用静态的足够大的数组来模拟实现

3.面向对象的方式实现链表

1.知识回顾

63.【C语言】再议结构体(上)
86.【C语言】数据结构链表的总体概述

87.【C语言】数据结构链表的头插和尾插

91.【C语言】数据结构之单向链表的头删和尾删

92.【C语言】数据结构之单向链表的查找,中间插入和删除,销毁

上面的这些文章实际上是面向过程的方式实现链表

2.面向对象的方式实现

竞赛中一般使用数组去模拟链表,这里简单了解就行

面向对象的方式:可以使用结构体去封装链表的各个操作(隐藏对象的内部实现细节,只暴露必要的接口供外部使用),之后借助点操作符去调用成员函数

(有关C++结构体的内容参见C24.【C++ Cont】结构体文章)

实现代码

struct List
{Node* phead;//指向头节点的指针Node* ptail;//指向尾节点的指针List()//构造函数用于初始化指向头节点的指针{phead = nullptr;ptail = nullptr;}~List()//析构函数用于销毁链表{while (phead){SLTPopFront();}phead = nullptr;ptail = nullptr;}Node* BuySLTNode(SLTDataType x)//新建节点{Node* newnode = new  Node;if (newnode == nullptr){perror("new");return nullptr;}newnode->val = x;newnode->next = nullptr;return newnode;}void SLTPushFront(SLTDataType x)//头插节点{Node* newnode = BuySLTNode(x);if (phead == nullptr){phead = ptail= newnode;}else{newnode->next = phead;phead = newnode;//不用改动ptail}}void SLTPushBack(SLTDataType x)//尾插节点{Node* newnode = BuySLTNode(x);if (phead == nullptr){ptail = phead = newnode;//如果是第一次插入需要同时更新首尾指针}else{ptail->next = newnode;ptail = ptail->next;}}void SLTPopFront()//头删节点{if (phead == nullptr){cout << "链表为空,禁止头删" << endl;return;}Node* tmp = phead;phead = tmp->next;delete tmp;tmp = nullptr;}void SLTPopBack()//尾删节点{if (phead == nullptr){cout << "链表为空,禁止尾删" << endl;return;}Node* tmp = phead;if (phead->next == nullptr){delete phead;ptail= phead = nullptr;//删除最后一个节点,注意将首尾指针都置为空return;}while (tmp->next != ptail)//寻找尾节点前面的节点{tmp = tmp->next;}delete ptail;ptail = tmp;ptail->next = nullptr;tmp = nullptr;}void SLTPrint()//打印链表的所有节点{Node* cur = phead;while (cur){cout << cur->val << "-->";cur = cur->next;}cout << "NULL"<<endl;}
};

如果用类写:

class List
{private:Node* phead;Node* ptail;public:List(){//......}~List(){//......}Node* BuySLTNode(SLTDataType x){//......}void SLTPushFront(SLTDataType x){//......}void SLTPushBack(SLTDataType x){//......}void SLTPopFront(){//......}void SLTPopBack(){//......}void SLTPrint(){//......}
};

封装后的接口说明

只需要向开发者提供接口说明,供开发者调用,例如:

/
//文件名:list.cpp
//作者:zhancod
//版本:v1.0
//完成日期:2025.1.28
//修改记录:......
//
//描述:单链表API
//提醒:1.使用前先创建链表(List list;),之后调用接口函数(list.函数(?))
//     2.链表存储的数据类型定义在typedef  int SLTDataType;
//     3.不需要手动new和delete链表
//
//1.函数:SLTPushFront
//  功能:头插节点
//  使用方式:list.SLTPushFront(data)
//
//2.函数:SLTPushBack
//  功能:尾插节点
//  使用方式:list.SLTPushBack(data)
//
//3.函数:SLTPopFront
//  功能:头删节点
//  使用方式:list.SLTPopFront()
//
//4.函数:SLTPopBack
//  功能:尾删节点
//  使用方式:list.SLTPopBack()
//
//5.函数:SLTPrint
//  功能:打印链表的所有节点
//  使用方式:list.SLTPrint()
//

调用接口的代码

int  main()
{{List list;list.SLTPushFront(1);list.SLTPushBack(2);list.SLTPushFront(3);list.SLTPushBack(4);list.SLTPushFront(5);list.SLTPopFront();list.SLTPrint();list.SLTPopBack();list.SLTPrint();list.SLTPopBack();list.SLTPopFront();list.SLTPopBack();list.SLTPopFront();list.SLTPopBack();list.SLTPrint();}return 0;
}

执行结果

练习

稍微修改上方的代码可以提交本题:707. 设计链表 - 力扣(LeetCode)

之后会单独出一篇文章讲解

🎉❤️🎉❤️🎉❤️🎉❤️🎉❤️祝各位码农们蛇年大吉 巳巳如意!❤️🎉❤️🎉❤️🎉❤️🎉❤️🎉


http://www.ppmy.cn/embedded/158394.html

相关文章

DeepSeek能执行程序吗?

1. 前言 大过年的&#xff0c;继续蹭DeepSeek的热点&#xff0c;前面考察了DeepSeek能否进行推理&#xff08;DeekSeek能否进行逻辑推理&#xff09;&#xff0c;其实似乎没有结论&#xff0c;因为还没有到上难度&#xff0c;DeepSeek似乎就纠结在一些与推理无关的事情上了&am…

AI 计算的未来:去中心化浪潮与全球竞争格局重塑

引言 人工智能(AI)正以前所未有的速度发展,尤其是大模型训练和推理效率的提升,使得 AI 计算成本迅速下降,呈现出向去中心化演进的趋势。 最新的 DeepSeek r1 模型,以仅 600 万美元 的训练成本,达到了 OpenAI o1 级别的性能,表明 AI 技术正迈向更具普惠性的阶段。这一趋…

【Uniapp-Vue3】uni-icons的安装和使用

一、uni-icon的安装 进入到如下页面中&#xff0c;点击“点击下载&安装”。 uni-icons 图标 | uni-app官网 点击“下载插件并导入HBuilder”&#xff0c;如果没有登录就登陆一下 网页中会打开Hbuilder&#xff0c;进入Hbuilder以后&#xff0c;选择需要使用该插件的项目进…

微服务入门(go)

微服务入门&#xff08;go&#xff09; 和单体服务对比&#xff1a;里面的服务仅仅用于某个特定的业务 一、领域驱动设计&#xff08;DDD&#xff09; 基本概念 领域和子域 领域&#xff1a;有范围的界限&#xff08;边界&#xff09; 子域&#xff1a;划分的小范围 核心域…

【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)

目录 1 -> 生命周期 1.1 -> 应用生命周期 1.2 -> 页面生命周期 2 -> 资源限定与访问 2.1 -> 资源限定词 2.2 -> 资源限定词的命名要求 2.3 -> 限定词与设备状态的匹配规则 2.4 -> 引用JS模块内resources资源 3 -> 多语言支持 3.1 -> 定…

数据结构与算法学习笔记----容斥原理

数据结构与算法学习笔记----容斥原理 author: 明月清了个风 first publish time: 2025.1.30 ps⭐️介绍了容斥原理的相关内容以及一道对应的应用例题。 Acwing 890. 能被整除的数 [原题链接](890. 能被整除的数 - AcWing题库) 给定一个整数 n n n和 m m m个不同的质数 p 1 …

大模型知识蒸馏技术(2)——蒸馏技术发展简史

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl2006年模型压缩研究 知识蒸馏的早期思想可以追溯到2006年,当时Geoffrey Hinton等人在模型压缩领域进行了开创性研究。尽管当时深度学习尚未像今天这样广泛普及,但Hinton的研究已经为知识迁移和模…

StarRocks BE源码编译、CLion高亮跳转方法

阅读SR BE源码时&#xff0c;很多类的引用位置爆红找不到&#xff0c;或无法跳转过去&#xff0c;而自己的Linux机器往往缺乏各种C依赖库&#xff0c;配置安装比较麻烦&#xff0c;因此总体的思路是通过CLion远程连接SR社区已经安装完各种依赖库的Docker容器&#xff0c;进行编…