C++蓝桥杯基础篇(十一)

片头

嗨~小伙伴们,大家好!今天我们来学习C++蓝桥杯基础篇(十一),学习类,结构体,指针相关知识,准备好了吗?咱们开始咯~


一、类与结构体

类的定义:在C++中,类的定义是通过关键字"class"来完成的。一个类定义一舿数据的结构和方法。

class Person {private:				//私有的成员变量int age, height;double money;string books[100];public:					//公有的成员变量,成员函数string name;void say() {cout << "I'm " << name << endl;}void set_age(int a) {age = a;}int get_age() {return age;}void set_height(int h) {height = h;}int get_height() {return height;}void add_money(double x) {money += x;}
};

上面的例子定义了一个名为Person的类,包含了5个数据成员name,age,height,money,books,以及3个成员函数say()用来打招呼,set_age()用来设置年龄,get_age()用来获取年龄,add_money()用来增加零钱的数量。可以通过实例化这个类来创建具体的对象并访问其成员和方法。

类中的变量和函数被统一称为类的成员变量。

private后面的内容是私有成员变量,在类的外部不能访问;public后面的内容是公有成员变量,在类的外部可以访问。

类的使用:

 正确示例代码如下:

int main() {Person c;c.name = "小明";    //正确!访问公有变量//c.age = 18;		//错误!访问私有变量c.set_age(18);		//正确!set_age()是公有成员变量c.set_height(185);  //正确!set_height()是公有成员变量c.add_money(100);	//设置零钱为100块c.say();cout << c.get_age() << endl;cout << c.get_height() << endl;return 0;
}

结构体和类的作用是一样的。不同点在于,类默认是private,结构体默认是public。 


二、构造函数

结构体构造函数是一种特殊的函数,用于创建结构体并对其进行初始化。在C++中,结构体构造函数与类构造函数类似,用于初始化结构体的成员变量,可以通过传入参数来指定初始值。结构体构造函数的名称与结构体本身相同,不需要指定返回类型。

struct Person1 {int age, height;double money;Person1 () {};Person1(int _age, int _height, double _money) {age = _age;height = _height;money = _money;}
};int main() {Person1 p(18,185,100);    //调用有参构造cout << p.age << " " << p.height << " " << p.money << endl;Person1 a;                //调用无参构造cout << a.age << " " << a.height << " " << a.money << endl;return 0;
}

 此外,我们还可以使用初始化列表来初始化成员变量

struct Person2 {int age, height;double money;Person2() {};  //无参构造Person2(int _age, int _height) :age(_age), height(_height) {}; //使用初始化列表构造Person2(int _age, int _height, double _money) :age(_age),height(_height),money(_money) {}
};int main() {Person2 p(18, 185, 100);cout << p.age << " " << p.height << " " << p.money << endl;Person2 a;cout << a.age << " " << a.height << " " << a.money << endl;return 0;
}

三、指针和引用

指针指向存放变量的值的地址。因此,我们可以通过指针来修改变量的值。

int main() {int a = 10;int* p = &a;*p += 5;cout << *p << endl;		//15cout << a << endl;		//15return 0;
}

上面代码中,指针p存放的是a的地址,修改*p的值,a的值也会被修改。

数组名是一种特殊的指针。指针可以做运算。

int main() {char c;int a[5] = { 1,2,3,4,5 };printf("%p\n", &c);printf("%p\n", &a);return 0;
}

我们将数组a中每个元素的地址都打印一遍:

int main() {char c;int a[5] = { 1,2,3,4,5 };printf("字符c的地址为: %p\n", &c);printf("数组名a的地址为: %p\n", &a);for (int i = 0; i < 5; i++) {printf("a[%d] = %p\n",i, &a[i]);}cout << endl;return 0;
}

由此,我们发现,数组名和首元素的地址相同。数组名 = 首元素地址。每个地址之间相差4个字节,因为是int类型的数组,每个int类型的整数占4个字节。

我们还可以通过指针+1来访问下一个元素

int main() {char c;int a[5] = { 1,2,3,4,5 };int* p = a;		//p代表首元素a[0]的地址cout << p << endl;cout << p + 1 << endl;return 0;
}

 因此,如果我们想直接访问a[2]的话,也可以写成 *(p+2)

int main() {int a[5] = { 1,2,3,4,5 };int* p = a;					//p代表首元素a[0]的地址cout << p << endl;			//a[0]的地址cout << *p << endl;			//a[0]的值cout << p + 1 << endl;		//a[1]的地址cout << *(p + 1) << endl;	//a[1]的值cout << p + 2 << endl;		//a[2]的地址cout << *(p + 2) << endl;	//a[2]的值return 0;
}

因此,遍历整个数组的代码如下:

int main() {int a[5] = { 1,2,3,4,5 };int* p = a;//之前的for (int i = 0; i < 5; i++) {cout << a[i] << " ";}cout << endl;//现在的for (int i = 0; i < 5; i++) {cout << *(p + i) << " ";}return 0;
}

同理,输出可以用指针实现,那么输入也可以:

int main() {char c;int a[5] = { 1,2,3,4,5 };scanf("%d", a + 1);		//输入a[1]的值//相当于 scanf("%d",&a[1]);//因为数组名 = 首元素的地址//数组名+1 = 下一个元素的地址for (auto e : a) {cout << e << " ";}cout << endl;return 0;
}

那么,难道指针只能进行加法运算码?不是的~ 可以进行减法运算

int main() {int a[5] = { 1,2,3,4,5 };int* p = &a[0];int* q = &a[2];cout << q - p << endl; //2return 0;
}

引用和指针类似,相当于给变量起个别名。

int main() {int a = 10;int& p = a;			 //p是a的别名p += 5;cout << p << endl;   //p的值被修改为15cout << a << endl;	 //a的值被修改为15return 0;
}


 四、链表

单链表在C语言中可以定义为一个结构体,其中包含一个指向下一个节点的指针。

// 定义单链表节点
struct Node {int data; // 节点数据struct Node *next; // 指向下一个节点的指针
};// 定义单链表
struct LinkedList {struct Node *head; // 头节点指针
};

在这个定义中,struct Node 代表单链表的节点,包含节点的数据和指向下一节点的指针。struct LinkedList 代表整个单链表,其中包含一个头节点指针 head,指向链表的第一个节点。

struct Node {int val;		//节点里面的值Node* next;		//指向下一节点的next指针Node(int _val):val(_val),next(NULL){}
};int main() {Node* p = new Node(1);   //创建p节点Node* q = new Node(2);   //创建q节点Node* o = new Node(3);	 //创建o节点p->next = q;			 //p节点的next指针指向q节点q->next = o;			 //q节点的next指针指向o节点Node* pcur = p;			 //pcur节点从第1个节点p开始//链表的遍历方式for (Node* i = pcur; i != NULL; i = i->next) {cout << i->val << " -->" << " ";}cout << "NULL" << endl;return 0;
}

  如何在链表中添加节点呢?并且添加在第一个位置,也就是头插

	Node* p = new Node(1);   //创建p节点Node* q = new Node(2);   //创建q节点Node* o = new Node(3);	 //创建o节点p->next = q;			 //p节点的next指针指向q节点q->next = o;			 //q节点的next指针指向o节点Node* head = p;			 //pcur节点从第1个节点p开始//添加节点Node* u = new Node(4);u->next = head;head = u;

那么如何删除节点呢?删除链表中第2个节点

	Node* p = new Node(1);   //创建p节点Node* q = new Node(2);   //创建q节点Node* o = new Node(3);	 //创建o节点p->next = q;			 //p节点的next指针指向q节点q->next = o;			 //q节点的next指针指向o节点Node* head = p;			 //pcur节点从第1个节点p开始//删除节点head->next = head->next->next;


五、习题
第1题  斐波那契数列

错误代码如下:

class Solution {
public:int Fibonacci(int n) {if (n <= 2) return 1;		//错误,这是第0项为1return Fibonacci(n - 1) + Fibonacci(n - 2);}
};

为啥错了呢?因为,题目告诉我们从0开始,第0项为0

因此,正确代码如下:

//f(0)=0,f(1)=1
//f(2)=f(0)+f(1)=1
//f(3)=f(1)+f(2)=2class Solution {
public:int Fibonacci(int n) {if (n <= 1) return n;	//当n==0,返回0	//当n==1,返回1return Fibonacci(n - 1) + Fibonacci(n - 2); //从n==2开始,都满足这个规律}
};

第2题  替换空格

代码如下:

class Solution {
public:string replaceSpaces(string& str) {string res;			  //定义res字符串,用来保存最后结果for (auto c : str) {if (c == ' ') res += "%20";else res += c;}return res;}
};

第3题  求1+2+3+...+n

题目要求我们不能使用乘除法、for、while、if、else、switch、case以及条件判断语句(A?B:C) ,那么我们可以使用短路与&&和递归来解决此类问题。

sum(n) = n+sum(n-1),但是要注意终止条件,由于求的是 1+2+3+....+n 的和,所以需要在n=0的时候跳出递归。但是题目要求不能使用if,while等分支判断,可以考虑利用&&短路运算来终止判断。

代码如下:

方法一:

class Solution {
public:int getSum(int n) {int res = n;n > 0 && (res += getSum(n - 1) + n);  //短路与&&//只要左边的表达式错误,那么右边也不会再执行//利用短路与&&终止递归return 0;}
};

方法二:我们还可以采用函数递归来解决。在外部定义递归函数,内部调用即可。

//调用函数
class Solution {
public:int getSum(int n) {return f(n);}int f(int n) {if (n == 0) return 0;return f(n - 1) + n;}
};

第4题  在O(1)时间删除链表结点

代码如下:

struct ListNode {int val;ListNode* next;ListNode(int x):val(x),next(NULL){}
};class Solution {
public:void deleteNode(ListNode* node) {node->val = node->next->val;	//伪装成下一个点node->next = node->next->next;	//将下一个点删掉}
};

 还有一种更简便的方法:

struct ListNode {int val;ListNode* next;ListNode(int x):val(x),next(NULL){}
};class Solution {
public:void deleteNode(ListNode* node) {*(node) = *(node->next);}
};
第5题  合并两个排序的链表

这道题,我们先来一种易理解的方法:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if (list1 == NULL)//如果list1为空,则返回list2return list2;if (list2 == NULL)//如果list2为空,则返回list1return list1;ListNode* l1 = list1;	//定义l1变量,指向list1ListNode* l2 = list2;	//定义l2变量,指向list2ListNode* newHead = NULL;  //定义新链表的头节点ListNode* newTail = NULL;  //定义新链表的尾节点while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小if (newHead == NULL) {//如果链表为空newHead = newTail = l1;}else {//链表不为空newTail->next = l1;newTail = l1;}l1 = l1->next;	//l1指向下一个节点}else {//l2比l1小if (newHead == NULL) {//如果链表为空newHead = newTail = NULL;}else {//链表不为空newTail->next = l2;newTail = l2;}l2 = l2->next;	//l2指向下一个节点}}if (l1) {//l1没有遍历完链表newTail->next = l1;}if (l2) {//l2没有遍历完链表newTail->next = l2;}return newHead;//返回头节点
}

好啦,这道题我们基本上做完了。但是,看看这代码,有重复冗余的部分,我们如何优化代码呢?

有啦!我们可以定义一个哨兵节点,这个节点可以不存放数据,让它指向新链表的头节点

	ListNode* node = (ListNode*)malloc(sizeof(ListNode));		//创建一个哨兵节点ListNode* newHead = node;									//头节点指向哨兵节点ListNode* newTail = node;									//尾节点指向哨兵节点

 中间的循环也要进行更改,不用判断链表是否为空了

	while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小newTail->next = l1;newTail = l1;l1 = l1->next;	//l1指向下一个节点}else {//l2比l1小newTail->next = l2;newTail = l2;l2 = l2->next;	//l2指向下一个节点}}

malloc了空间,但这块空间实际上用不了,最后我们需要将哨兵节点释放

	//malloc了空间,但这块空间实际上用不了,最后我们需要将哨兵节点释放ListNode* ret = newHead->next;free(newHead);return ret;		 //返回头节点的下一个节点

 欧克,优化过的代码如下:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if (list1 == NULL)//如果list1为空,则返回list2return list2;if (list2 == NULL)//如果list2为空,则返回list1return list1;ListNode* l1 = list1;	//定义l1变量,指向list1ListNode* l2 = list2;	//定义l2变量,指向list2ListNode* node = (ListNode*)malloc(sizeof(ListNode));		//创建一个哨兵节点ListNode* newHead = node;									//头节点指向哨兵节点ListNode* newTail = node;									//尾节点指向哨兵节点while (l1 && l2) {if (l1->val < l2->val) {//l1比l2小newTail->next = l1;newTail = l1;l1 = l1->next;	//l1指向下一个节点}else {//l2比l1小newTail->next = l2;newTail = l2;l2 = l2->next;	//l2指向下一个节点}}if (l1) {//l1没有遍历完链表newTail->next = l1;}if (l2) {//l2没有遍历完链表newTail->next = l2;}//malloc了空间,但这块空间实际上用不了,最后我们需要将哨兵节点释放ListNode* ret = newHead->next;free(newHead);return ret;		 //返回头节点的下一个节点
}

片尾

今天我们学习了相关类、结构体、指针相关知识,希望看完这篇文章能对友友们有所帮助!!!

点赞收藏加关注!!!

谢谢大家!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/897550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css中实现border距离视图左右两侧有距离

首先看效果图 再看css是如何实现 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.main {background-color: aqua;display: block;width: 300px;padding: 0px 32px;box-sizing: border-box;}/…

Ubuntu 22.04 无法进入图形界面的解决方法

Ubuntu 22.04 无法进入图形界面&#xff0c;只能进入 tty&#xff0c;可能是由于图形界面相关的配置或驱动程序出现了问题。以下是一些常见的解决方法&#xff1a; 1. 检查图形界面服务状态 首先&#xff0c;检查图形界面服务&#xff08;通常是 gdm 或 lightdm&#xff09;的…

Tweak Power:全方位电脑系统优化的高效工具

在日常使用电脑时&#xff0c;系统性能的下降、垃圾文件的堆积以及硬盘的老化等问题常常困扰着用户。为了提升电脑性能、优化系统运行&#xff0c;许多人会选择系统优化工具。然而&#xff0c;国内一些系统优化软件常常因为广告过多或功能冗杂而让人望而却步。此时&#xff0c;…

深入浅出Bearer Token:解析工作原理及其在Vue、Uni-app与Java中的实现Demo

目录 前言1. 基本知识2. Demo3. 实战 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 1. 基本知识 Bearer Token是一种基于Token的认证机制&#xff0c;用于在HTTP请求中传递用户的身份信息 应用于RESTful A…

kubernetes——part3-5 核心概念 Service

一、 service作用 使用kubernetes集群运行工作负载时&#xff0c;由于Pod经常处于用后即焚状态&#xff0c;Pod经常被重新生成&#xff0c;因此Pod对应的IP地址也会经常变化&#xff0c;导致无法直接访问Pod提供的服务&#xff0c;Kubernetes中使用了Service来解决这一问题&am…

从零开始 | C语言基础刷题DAY1

❤个人主页&#xff1a;折枝寄北的博客 DAY1[2025.3.11] 1. 求两个数的较大值2.从键盘输入的两个数的大小关系3.一个整数的奇偶性&#xff0c;请判断4. 考试分数是否通过5.考试成绩是否完美&#xff0c;请判断 1. 求两个数的较大值 题目&#xff1a; 写一个函数求两个整数的较…

开源模型时代的 AI 开发革命:Dify 技术深度解析

开源模型时代的AI开发革命&#xff1a;Dify技术深度解析 引言&#xff1a;AI开发的开源新纪元 在生成式AI技术突飞猛进的2025年&#xff0c;开源模型正成为推动行业创新的核心力量。据统计&#xff0c;全球超过80%的AI开发者正在使用开源模型构建应用&#xff0c;这一趋势不仅…

Dify Web 前端独立部署指南(与后端分离,独立部署)

背景:单独拆分前端出来部署,二开前后端 本文档专注于 Dify Web 前端的部署流程和配置,适用于需要将项目部署到各种环境的运维人员和开发者。 1. 环境准备 1.1 部署环境要求 Node.js >= 18.17.0Nginx 或其他Web服务器(生产环境推荐)Docker(可选,用于容器化部署)1.…

《苍穹外卖》SpringBoot后端开发项目核心知识点整理(DAY1 to DAY3)

目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功&#xff1a; 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具&#xff1a;Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…

大数据hadoop课程笔记

1.课程导入 柯洁 Alpha Go是人工智能领域的里程碑。 深度学习 大模型deepseek chatgpt 大模型 和 大数据 之间有着非常紧密的关系。可以说&#xff0c;大数据是大模型发展的基石&#xff0c;而大模型是大数据价值挖掘的重要工具。 https://youtu.be/nN-VacxHUH8?sifj7Ltk…

架构学习第八周--Kubernetes博客搭建

目录 一、整体架构 二、部署MySQL主从 三、部署Redis哨兵 四、部署WordPress 五、注意事项 一、整体架构 本项目为在一主三从的Kubernetes集群上部署WordPress博客。因为WordPress部分容器版本自行集成Apache和PHP服务&#xff0c;因此在Kubernetes上部署WordPress只需提供…

Application.OnTime如何引用带参数的过程

Application.OnTime方法本身并不直接支持传递参数给被调用的过程。不过&#xff0c;有几种方法可以间接实现这个需求。 方法1&#xff1a;使用单引号表达式 使用单引号表达式来传递参数时&#xff0c;不能在表达式中使用变量&#xff0c;需要把参数值直接写到表达中&am…

网络安全之tcpdump工具

引言 wireshark是一款非常不错的抓包软件&#xff0c;在图形化界面占绝对统治地位&#xff1b;尽管其在字符界面下有些许选项可供使用&#xff0c;但终究不太方便&#xff0c;下面我再介绍一款NB的终端抓包工具 tcpdump 1、混杂模式 linux的网卡有混杂模式一说&#xff0c;当开…

VC++ 获取目的IP的路由

GetBestRoute 函数获取到目的IP的最佳匹配路由。 第一个参数为&#xff1a;destination&#xff08;目的IP&#xff09; 第二个参数为&#xff1a;source&#xff08;源IP&#xff09; 通常不需要指定第二个source&#xff0c;这个一般用来匹配具体某一个网卡接口路由的&…

JavaScript 模块 vs C# 类:封装逻辑的两种哲学

引言 在现代软件开发中&#xff0c;模块化和面向对象设计是代码组织的核心课题。本文通过对比 JavaScript 模块&#xff08;ES6 Module&#xff09;与 C# 类&#xff08;Class&#xff09;的实现方式&#xff0c;探讨两种语言在封装逻辑时的不同哲学&#xff0c;并给出实际应用…

大模型在甲状腺癌诊疗全流程预测及方案制定中的应用研究

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 1.3 国内外研究现状 二、大模型预测甲状腺癌的理论基础 2.1 甲状腺癌相关医学知识 2.2 大模型技术原理与特点 2.3 大模型在医疗领域的应用潜力 三、术前预测方案 3.1 预测模型构建 3.1.1 数据收集与预处理 …

electron+vue+webview内嵌网页并注入js

vue内嵌网页可以使用iframe实现内嵌网页&#xff0c;但是只能通过postMessage间接通信&#xff0c;在electron环境下&#xff0c;vue可以直接使用webview来内嵌网页&#xff0c;支持 executeJavaScript、postMessage、send 等丰富的通信机制。 使用 webview的优势 性能更佳&…

leetcode日记(95)将有序数组转换为二叉搜索树

很简单&#xff0c;感觉自己越来越适应数据结构题目了…… /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : va…

【threejs实战教程一】初识Three.js,场景Scene、相机Camera、渲染器Renderer

Three.js是一个基于WebGL的JavaScript 3D图形库&#xff0c;用于在浏览器中创建和显示3D内容 Three.js中最基础的三个关键要素就是场景Scene、相机Camera、渲染器Renderer 通俗一点理解&#xff0c;场景就是我们生活中一个具体的场景&#xff0c;比如自然环境中的一栋建筑&…

【leetcode hot 100 138】随机链表的复制

解决一&#xff1a;回溯 哈希表 本题要求我们对一个特殊的链表进行深拷贝。如果是普通链表&#xff0c;我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在&#xff0c;当我们拷贝节点时&#xff0c;「当前节点的随机指针指向的节点」可能还没创建&#xf…