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; //返回头节点的下一个节点
}
片尾
今天我们学习了相关类、结构体、指针相关知识,希望看完这篇文章能对友友们有所帮助!!!
求点赞收藏加关注!!!
谢谢大家!!!

相关文章:
C++蓝桥杯基础篇(十一)
片头 嗨~小伙伴们,大家好!今天我们来学习C蓝桥杯基础篇(十一),学习类,结构体,指针相关知识,准备好了吗?咱们开始咯~ 一、类与结构体 类的定义:在C中&#x…...
【贪心算法4】
力扣452.用最少数量的剪引爆气球 链接: link 思路 这道题的第一想法就是如果气球重叠得越多那么用箭越少,所以先将气球按照开始坐标从小到大排序,遇到有重叠的气球,在重叠区域右边界最小值之前的区域一定需要一支箭,这道题有两…...
Leetcode 698-划分为k个相等的子集
给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。 示例 1: 输入: nums [4, 3, 2, 3, 5, 2, 1], k 4 输出: True 说明: 有可能将其分成 4 个子集&#…...
Word 小黑第2套
对应大猫42 Word1 从文件中导入新样式 样式组 -管理样式 -导入导出 -关闭Normal文件 -打开文件 -修改文件 -选中所需 -复制 调整字符宽度 调整字符间距 -字体组 加宽 适当修改磅值 文字效果通过文字组修改 另起一页,分隔符(布局 -分隔符 -分节符 -下一…...
【最后203篇系列】014 AI机器人-1
说明 终于开张了,我觉得AI机器人是一件真正正确,具有商业价值的事。 把AI机器人当成一笔生意,我如何做好这笔生意?一端是业务价值,另一端是技术支撑。如何构造高质量的内容和服务,如何确保技术的广度和深度…...
沉浸式CSS学习路径
好的!我将以魔法学院成长故事为框架,为您设计一套沉浸式CSS学习路径。以下是叙事化学习提纲: 第一卷:像素学徒的觉醒 章节1:被封印的魔法书 发现HTML的"素颜"本质,通过<!DOCTYPE html>解除网页封印用style标签打开CSS魔法书,学会给文字穿上color斗篷和…...
ctfshow做题笔记—栈溢出—pwn69~pwn72
目录 前言 一、pwn69(可以尝试用ORW读flag flag文件位置为/ctfshow_flag) 二、pwn70(可以开始你的个人秀了 flag文件位置为/flag) 三、pwn71(32位的ret2syscall) 四、pwn72 前言 学了一些新的东西,pwn69的文档忘保存了(悲),…...
重要!!! 改进 梯度方差(Fisher 信息近似) 指数移动平均
改进 梯度方差(Fisher 信息近似) 指数移动平均 目录 改进 梯度方差(Fisher 信息近似) 指数移动平均1. 指数移动平均(Exponential Moving Average, EMA)2. 引入正则化项3. 分簇加权计算一、指数移动平均(EMA)概述二、EMA 公式参数作用三、举例说明场景 1:股票价格波动分…...
同盾v2 2025版 blackbox , wasm加解密,逆向协议算法生成,小盾安全
声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! # 欢迎交流 wjxch1004...
c++领域展开第十六幕——STL(vector容器的了解以及模拟实现、迭代器失效问题)超详细!!!!
文章目录 前言一、vector的介绍和使用1.1 vector的介绍1.2 vector的使用1.2.1 vector的定义1.2.2 vector iterator 的使用1.2.3 vector的空间增长问题1.2.4 vector的增删改查 二、vector在 oj 中的使用只出现一次的数删除有序数组中的重复项杨辉三角 总结 前言 在c专栏的上一篇…...
ubuntu2404 安装 过程中 手动设置网络
ubuntu2404 安装 过程中 手动设置网络 https://blog.csdn.net/2401_83947353/article/details/138454379 6.1 可以直接Done(不配置P) 6.2 可以配置ip地址,选择manual 6.2.1 search domains填 6.2.2 search domains不填 6.3 更深层次的…...
去北京的前端实习经历
趁现在对这部分还有深刻的感受记忆,赶紧记录下来。因为工作久了会发现真的对以前的事记不起来了。 公司: 北京的实习公司首先有学长学姐在,而且这个公司知名度还挺高的,但是工资比较低,3k左右吧,但是管2顿…...
QT创建项目(项目模板、构建系统、选择类、构建套件)
1. 项目模版 项目类型界面技术适用场景核心依赖模块开发语言Qt Widget ApplicationC Widgets传统桌面应用(复杂控件)Qt WidgetsCQt Console Application无 GUI命令行工具、服务Qt CoreCQt Quick ApplicationQML/Quick现代跨平台应用(动画/触…...
力扣热题 100:动态规划专题经典题解析
系列文章目录 力扣热题 100:哈希专题三道题详细解析(JAVA) 力扣热题 100:双指针专题四道题详细解析(JAVA) 力扣热题 100:滑动窗口专题两道题详细解析(JAVA) 力扣热题 100:子串专题三道题详细解析(JAVA) 力…...
变量赋值汇编
一、核心概念 寄存器:CPU内部的高速存储单元(如EAX、EBX、x86中的RAX、ARM中的R0等) 内存地址:变量存储在内存中的位置(如 0x1000) 指令:操作寄存器和内存的命令(如 MOV, STR, LDR…...
页面白屏出现的原因
🤖 作者简介:水煮白菜王,一位前端劝退师 👻 👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。 感谢支持💕💕&#…...
【大模型统一集成项目】让 AI 聊天更丝滑:WebSocket 实现流式对话!
🌟 在这系列文章中,我们将一起探索如何搭建一个支持大模型集成项目 NexLM 的开发过程,从 架构设计 到 代码实战,逐步搭建一个支持 多种大模型(GPT-4、DeepSeek 等) 的 一站式大模型集成与管理平台ÿ…...
boarding_passes(登机牌)表的作用
boarding_passes(登机牌)表的作用 boarding_passes 这张表的主要作用是记录旅客的登机信息,包括: 票号 (ticket_no) - 关联到 tickets 表,表示这张票属于哪个旅客。航班 ID (flight_id) - 关联到 flights 表…...
【2025】Electron Git Desktop 实战一(上)(架构及首页设计开发)
源代码仓库: Github仓库【electron_git】 Commit : bb40040 Github Desktop 页面分析 本节目标: 1、实现类似Github Desktop的「空仓库」提示页 2、添加本地仓库逻辑编写从 Github Desktop 我们看到 他的 主要页面分为三个区域 Head头部区域…...
14 | fastgo 三层架构设计
提示: 所有体系课见专栏:Go 项目开发极速入门实战课; 在实现业务代码之前,还需要先设计一个合理的软件架构。一个好的软件架构不仅可以大大提高项目的迭代速度,还可以降低项目的阅读和维护难度。目前,行业中…...
【机器学习-基础知识】统计和贝叶斯推断
1. 概率论基本概念回顾 1. 概率分布 定义: 概率分布(Probability Distribution)指的是随机变量所有可能取值及其对应概率的集合。它描述了一个随机变量可能取的所有值以及每个值被取到的概率。 对于离散型随机变量,使用概率质量函数来描述。对于连续型随机变量,使用概率…...
面向对象Demo01
面向对象 什么是面向对象 回顾方法的定义 package oop; import java.io.IOException; public class Demo01 {public static void main(String[] args) {}//public String sayHello() {return "hello, world!";}public void sayHi() {return;}public int max(i…...
C++设计模式-抽象工厂模式:从原理、适用场景、使用方法,常见问题和解决方案深度解析
一、模式基本概念 1.1 定义与核心思想 抽象工厂模式(Abstract Factory Pattern)是创建型设计模式的集大成者,它通过提供统一的接口来创建多个相互关联或依赖的对象族,而无需指定具体类。其核心思想体现在两个维度: …...
solana区块链地址生成
solana官网地址:https://solana.com 先引入相关依赖solana/web3.js;bip39;ethereumjs/wallet 生成助记词 const mnemonic bip39.generateMnemonic(); 生成种子 const seed bip39.mnemonicToSeedSync(mnemonic); 生成密钥对 const root hdkey.EthereumHDKey.from…...
基于python的升级队列加速决策
a-f大等级是3级 a-c建筑每升1级分别需要8天 d-f建筑每升1级分别需要10天 目前以下建筑队列正在从0级升至1级 建筑A升级需要7天05:16:20 建筑b升级需要06:06:54 建筑c升级需要00:37:00 建筑d升级需要…...
Ragflow技术栈分析及二次开发指南
Ragflow是目前团队化部署大模型+RAG的优质方案,不过其仍不适合直接部署使用,本文将从实际使用的角度,对其进行二次开发。 1. Ragflow 存在问题 Ragflow 开源仓库地址:https://github.com/infiniflow/ragflow Ragflow 当前版本: v0.17.0 Ragflow 目前主要存在以下问题: …...
vue上传文件的请求头携带token校验、和携带另外的参数请求
拿element plus UI库举例,(不使用element plus的话js方法通用): <template><el-upload class"upload-demo":http-request"myUploadHttp" action"https://run.mocky.io/v3/9d059bf9-4660-45f2-…...
MySQL的 where 1=1会不会影响性能?
在MySQL中,WHERE 11 是一种常见的SQL编写技巧,通常用于动态生成SQL语句时简化条件拼接。虽然它看起来多余,但在实际使用中,WHERE 11 对性能的影响可以忽略不计。以下是详细分析: 1. WHERE 11 的作用 WHERE 11 是一个恒…...
MyBatis 中SQL 映射文件是如何与 Mapper 接口关联起来的? MyBatis 如何知道应该调用哪个 SQL 语句?
1. 命名空间 (Namespace): SQL 映射文件 (XML): 在 SQL 映射文件的 <mapper> 根元素中,有一个 namespace 属性。这个 namespace 属性的值必须是 Mapper 接口的全限定名(包名 接口名)。 <mapper namespace"com.example.mapper.…...
SICK Ranger3源码分析——断线重连
前言 本文可在https://paw5zx.github.io/SICK-Ranger3-source-code-analysis-01/中阅读,体验更佳 简单分析一下SICK Ranger3源码中断线重连的实现,这一块算是比较容易的,先择出来分析一下。 代码示例仅贴出关键部分以便分析 使用SDK版本为…...
