备战蓝桥杯----C/C++组 (一)所需C++基础知识(下)

wengqidaifeng

个人主页:

wengqidaifeng

✨永远在路上,永远向前走

个人专栏:

数据结构
C语言
嵌入式小白启动!
重要OJ算法题详解

文章目录


C++竞赛语法基础(下篇):进阶语法与实用技巧前言

书接上文,本文继续讲解蓝桥杯编程竞赛所需的基本C++基础语法知识。

在掌握基础语法后,进一步学习数组、字符串、函数、结构体等进阶内容,为算法竞赛打下坚实基础

10. 逻辑操作符

操作符含义说明
!逻辑非取反
&&逻辑与两边都为真才为真

短路特性

  • a && b:如果a为假,b不会被执行
  • a || b:如果a为真,b不会被执行

11. 条件操作符(三目操作符)

表达式1? 表达式2: 表达式3// 如果表达式1为真,执行表达式2,否则执行表达式3int max =(a > b)? a : b;// 求a和b的最大值

12. switch语句

switch(表达式){case 常量1:// 代码break;case 常量2:// 代码break;default:// 默认代码break;}

特点:

  • 表达式必须是整型
  • case后必须是整型常量
  • 每个case后要加break,否则会继续执行下一个case

13. 循环结构

13.1 while循环

while(条件){// 循环体}// 示例:打印1~10int i =1;while(i <=10){ cout << i <<" "; i++;}

13.2 for循环

for(初始化; 条件; 调整){// 循环体}// 示例:打印1~10for(int i =1; i <=10; i++){ cout << i <<" ";}

13.3 do-while循环

do{// 循环体}while(条件);// 特点:至少执行一次循环体

13.4 break和continue

  • break:跳出整个循环
  • continue:跳过本次循环的剩余部分,进入下一次循环
for(int i =1; i <=10; i++){if(i ==5)break;// i=5时跳出循环if(i ==3)continue;// i=3时跳过打印 cout << i <<" ";}// 输出:1 2 4

13.5 循环嵌套

// 打印乘法口诀表for(int i =1; i <=9; i++){for(int j =1; j <= i; j++){printf("%d*%d=%2d ", j, i, i*j);} cout << endl;}

14. 数组

数组是一组相同类型元素的集合,在内存中连续存储。

14.1 一维数组

数组创建

int arr[10];// 创建包含10个int的数组constint N =100;int a[N];// 使用常量定义大小

数组初始化

int arr1[5]={1,2,3,4,5};// 完全初始化int arr2[5]={1,2};// 不完全初始化,剩余为0int arr3[]={1,2,3,4,5};// 省略大小,编译器自动计算

数组下标

  • 下标从0开始
  • 最后一个元素的下标是n-1
  • 使用[]访问元素:arr[下标]

数组遍历

int arr[10]={1,2,3,4,5,6,7,8,9,10};// 方法1:for循环for(int i =0; i <10; i++){ cout << arr[i]<<" ";}// 方法2:范围for(C++11)for(int x : arr){ cout << x <<" ";}// 方法3:auto自动推导类型for(auto x : arr){ cout << x <<" ";}

数组和sizeof

int arr[10]; cout <<sizeof(arr);// 40(总字节数) cout <<sizeof(arr)/sizeof(arr[0]);// 10(元素个数)

14.2 二维数组

创建

int arr[3][5];// 3行5列的二维数组

初始化

int arr1[3][5]={1,2,3,4,5,2,3,4,5,6,3,4,5,6,7};int arr2[3][5]={{1,2},{3,4},{5,6}};// 按行初始化int arr3[][5]={1,2,3,4,5,6,7,8,9,10};// 可以省略行数,不能省略列数

访问和遍历

int arr[3][5]={...};for(int i =0; i <3; i++){for(int j =0; j <5; j++){ cout << arr[i][j]<<" ";} cout << endl;}

14.3 数组常用函数

memset - 设置数组内容(按字节设置):

#include<cstring>int arr[10];memset(arr,0,sizeof(arr));// 全部设为0(正确用法)// 注意:memset(arr, 1, sizeof(arr)) 不会将每个元素设为1!// 因为memset是按字节设置,每个字节设为1,int有4字节,值为0x01010101=16843009

memcpy - 拷贝数组

int a[10]={1,2,3,4,5,6,7,8,9,10};int b[10];memcpy(b, a,sizeof(a));// 将a的内容拷贝到b

14.4 竞赛技巧 - 数组大小

constint N =10010;int arr[N];// 通常开大一些,防止越界

全局数组的优势

  • 自动初始化为0
  • 空间更大(全局区 vs 栈区)
  • 避免传参麻烦

14.5 字符数组

初始化

char str1[10]="hello";// 字符串方式char str2[]="hello";// 自动分配大小,包含'\0'char str3[10]={'h','e','l','l','o','\0'};// 字符方式

字符串长度

#include<cstring>char str[]="hello"; cout <<sizeof(str);// 6(包含'\0') cout <<strlen(str);// 5(不包含'\0')

字符数组输入

// 无空格字符串char s[100]; cin >> s;// C++方式scanf("%s", s);// C方式// 有空格字符串char s[100];fgets(s,100,stdin);// 会读取换行符scanf("%[^\n]s", s);// 读取到换行前

字符串函数

#include<cstring>char s1[20]="hello";char s2[20]="world";strcpy(s1, s2);// 拷贝:s1变为"world"strcat(s1, s2);// 拼接:s1变为"helloworld"strcmp(s1, s2);// 比较:相等返回0,s1<s2返回负数,s1>s2返回正数

15. string字符串

string是C++提供的字符串类型,使用更加方便。

15.1 创建和初始化

#include<string> string s1;// 空字符串 string s2 ="hello";// 直接初始化 string s3("world");// 构造函数方式 string s4 = s2;// 拷贝初始化

15.2 输入输出

string s;// 无空格输入 cin >> s;// 有空格输入getline(cin, s);// 读取一行,包含空格getline(cin, s,'q');// 读取直到遇到'q'

15.3 常用操作

长度

string s ="hello"; cout << s.size();// 5 cout << s.length();// 5(效果相同)

访问元素

string s ="hello"; cout << s[0];// 'h' s[1]='a';// 修改为"hallo"

拼接

string s1 ="hello"; string s2 ="world"; string s3 = s1 + s2;// "helloworld" s1 += s2;// s1变为"helloworld" s1 +='!';// 追加字符

插入和删除

string s ="hello"; s.push_back('!');// 末尾添加字符:"hello!" s.pop_back();// 删除末尾字符:"hello" s.insert(2,"xxx");// 在位置2插入:"hexxxllo"

查找

string s ="hello world"; size_t pos = s.find("world");// 返回第一次出现的位置(6)if(pos != string::npos){ cout <<"找到了,位置:"<< pos;}

截取子串

string s ="hello world"; string s1 = s.substr(6);// 从位置6到结尾:"world" string s2 = s.substr(6,5);// 从位置6开始取5个字符:"world"

比较

string s1 ="abc"; string s2 ="abd";if(s1 < s2){// 按字典序比较 cout <<"s1小于s2";}

15.4 字符串和数字转换

#include<string>// 字符串转数字 string s ="123";int n =stoi(s);// 转intlong m =stol(s);// 转longdouble d =stod(s);// 转double// 数字转字符串int num =123; string str =to_string(num);// "123"

16. 函数

函数是将一段代码封装起来,实现特定功能。

16.1 函数定义

返回类型 函数名(参数列表){// 函数体return 返回值;// 如果返回类型不是void}// 示例:加法函数intAdd(int x,int y){return x + y;}

16.2 函数调用

intmain(){int a =10, b =20;int c =Add(a, b);// 调用函数 cout << c << endl;return0;}

16.3 形参和实参

  • 实参:调用函数时实际传递的值
  • 形参:函数定义中的参数,接收实参的值

重要:形参是实参的一份临时拷贝,修改形参不影响实参。

16.4 传值vs传引用

传值调用

voidSwap(int x,int y){int tmp = x; x = y; y = tmp;}// 调用后,实参不会改变

传引用调用(C++特有):

voidSwap(int& x,int& y){// 使用引用int tmp = x; x = y; y = tmp;}// 调用后,实参会改变

引用就是给变量起别名:

int a =10;int& ra = a;// ra是a的引用(别名) ra =20;// a变为20

引用传参的优势

  • 避免拷贝,提高效率
  • 可以在函数内修改实参

16.5 数组作为函数参数

voidprint_arr(int arr[],int size){for(int i =0; i < size; i++){ cout << arr[i]<<" ";}}intmain(){int arr[10]={1,2,3,4,5,6,7,8,9,10};print_arr(arr,10);// 数组传参return0;}

注意:数组传参时,形参和实参指向同一块内存,修改形参会影响实参。

16.6 函数重载

函数重载允许同一个函数名有不同的参数列表:

intAdd(int a,int b){return a + b;}doubleAdd(double a,double b){return a + b;}intmain(){ cout <<Add(1,2);// 调用int版本 cout <<Add(1.5,2.5);// 调用double版本return0;}

16.7 常用库函数

max/min

#include<algorithm>int a =10, b =20; cout <<max(a, b);// 20 cout <<min(a, b);// 10

swap

#include<utility>// 或 <algorithm>int a =10, b =20;swap(a, b);// 现在a=20, b=10

17. 递归

递归是函数调用自身的编程技巧。

17.1 递归的必要条件

  1. 存在限制条件(递归出口)
  2. 每次递归调用后越来越接近限制条件

17.2 阶乘 - 递归示例

intFact(int n){if(n ==0)// 递归出口return1;elsereturn n *Fact(n -1);// 递归调用}

17.3 递归执行过程

以Fact(3)为例:

  1. Fact(3)调用:3 * Fact(2)
  2. Fact(2)调用:2 * Fact(1)
  3. Fact(1)调用:1 * Fact(0)
  4. Fact(0)返回:1
  5. Fact(1)返回:1 * 1 = 1
  6. Fact(2)返回:2 * 1 = 2
  7. Fact(3)返回:3 * 2 = 6

17.4 递归vs迭代

递归的优点:代码简洁,逻辑清晰
递归的缺点:效率低(有函数调用开销),可能栈溢出

斐波那契数列 - 递归版本(效率低):

intFib(int n){if(n <=2)return1;returnFib(n-1)+Fib(n-2);}

斐波那契数列 - 迭代版本(效率高):

intFib(int n){int a =1, b =1, c =1;for(int i =3; i <= n; i++){ c = a + b; a = b; b = c;}return c;}

结论:能用迭代解决的问题尽量用迭代,递归适合解决天然具有递归结构的问题(如树的遍历)。

18. 位运算

位运算直接操作整数的二进制位,效率非常高。

18.1 二进制基础

进制转换

  • 10进制转2进制:除2取余,倒序排列
  • 2进制转10进制:按权展开

原码、反码、补码

  • 正数:原码=反码=补码
  • 负数:补码=反码+1(符号位不变)
  • 整数在内存中以补码形式存储

18.2 位运算符

运算符名称规则
<<左移左边丢弃,右边补0
>>右移算术右移(左边补符号位)
&按位与同为1才为1
|按位或有1则为1
^按位异或相同为0,不同为1
~按位取反0变1,1变0

18.3 位运算技巧

判断奇偶

if(n &1)// 奇数else// 偶数

获取第i位

intget_bit(int x,int i){return(x >> i)&1;}

将第i位置为1

x |=(1<< i);

将第i位置为0

x &=~(1<< i);

反转第i位

x ^=(1<< i);

去掉最右边的1

x &=(x -1);

这个操作常用于统计二进制中1的个数:

intcount_ones(int x){int cnt =0;while(x){ x &=(x -1); cnt++;}return cnt;}

保留最右边的1

int lowbit = x &(-x);

18.4 异或的巧妙应用

性质

  • a ^ a = 0
  • a ^ 0 = a
  • a ^ b ^ a = b

交换两个数

a = a ^ b; b = a ^ b; a = a ^ b;

找单身狗(数组中只出现一次的数):

intsingleNumber(int* nums,int n){int ans =0;for(int i =0; i < n; i++){ ans ^= nums[i];}return ans;}

19. 结构体

结构体可以将不同类型的数据组合成一个整体。

19.1 结构体定义

structStudent{ string name;int chinese;int math;int total;};// 注意分号

19.2 结构体变量创建

// 方式1:直接创建structStudent s1;// C风格(struct可省略) Student s2;// C++风格// 方式2:定义时创建structStudent{ string name;int score;} s1, s2;// 方式3:初始化 Student s ={"张三",90,95,185};

19.3 访问成员

Student s; s.name ="李四"; s.math =100; cin >> s.chinese; s.total = s.chinese + s.math;

19.4 结构体整体操作

Student s1 ={"张三",90,95,185}; Student s2 = s1;// 整体赋值(成员逐一拷贝)

19.5 结构体数组

Student stu[50];// 50个学生的数组// 遍历for(int i =0; i < n; i++){ cout << stu[i].name <<" "<< stu[i].total << endl;}

19.6 结构体成员函数

C++的结构体可以包含函数:

structStudent{ string name;int chinese;int math;voidcalc_total(){ total = chinese + math;}voidprint(){ cout << name <<": "<< total << endl;}int total;};

19.7 运算符重载

让结构体支持自定义的比较或运算:

structTime{int hours;int minutes;// 重载小于号,用于排序booloperator<(const Time& t)const{if(hours != t.hours)return hours < t.hours;return minutes < t.minutes;}};// 重载输出运算符 ostream&operator<<(ostream& os,const Time& t){ os << t.hours <<":"<< t.minutes;return os;}

20. sort排序

sort是C++标准库中最常用的排序函数。

20.1 基本用法

#include<algorithm>int arr[]={5,2,8,1,9};int n =sizeof(arr)/sizeof(arr[0]);sort(arr, arr + n);// 升序排序// 输出:1 2 5 8 9

20.2 自定义排序规则

使用比较函数

boolcmp(int a,int b){return a > b;// 降序}sort(arr, arr + n, cmp);

排序结构体

structStudent{ string name;int score;};boolcmp_by_score(Student a, Student b){return a.score > b.score;// 按成绩降序}sort(stu, stu + n, cmp_by_score);

多关键字排序

boolcmp(Student a, Student b){if(a.total != b.total)return a.total > b.total;// 先按总分降序elseif(a.chinese != b.chinese)return a.chinese > b.chinese;// 再按语文降序elsereturn a.id < b.id;// 最后按学号升序}

20.3 字符串排序

string s ="cba";sort(s.begin(), s.end());// s变为"abc"

21. 类(选学)

类是C++面向对象编程的核心,竞赛中了解基本用法即可。

21.1 类的定义

classStudent{public:// 公有成员,可以在类外访问voidinit(string n,int s){ name = n; score = s;}voidprint(){ cout << name <<": "<< score << endl;}private:// 私有成员,只能在类内访问 string name;int score;};

21.2 类的使用

intmain(){ Student stu; stu.init("张三",95); stu.print();// stu.name = "李四"; // 错误!name是私有的return0;}

21.3 struct和class的区别

  • struct的成员默认是public
  • class的成员默认是private
  • 其他方面基本相同

竞赛中常用struct来组织数据,用class来封装复杂对象。


总结

经过上下两篇的学习,我们已经掌握了C++竞赛所需的核心语法知识:

基础篇:开发环境、数据类型、输入输出、条件判断、循环结构
进阶篇:数组、字符串、函数、递归、位运算、结构体、排序

这些知识是参加算法竞赛的基石。熟练掌握后,就可以开始学习算法了,包括枚举、搜索、贪心、动态规划等核心算法。

记住:语法是工具,算法是灵魂。只有熟练掌握语法,才能更好地实现算法,在竞赛中取得好成绩。


【后续学习建议】

  1. 多做练习,巩固语法知识
  2. 学习常用STL容器(vector、set、map、stack、queue等)
  3. 开始接触基础算法:枚举、二分、贪心、搜索
  4. 刷题平台推荐:洛谷、AcWing、Codeforces

祝大家在蓝桥杯中取得好成绩!感谢各位大佬的观看!

Read more

2025年第十六届蓝桥杯省赛JavaB组真题回顾

2025年第十六届蓝桥杯省赛JavaB组真题回顾

第16届蓝桥杯省赛已经结束了,第一次参加也是坐牢了4个小时,现在还是来总结一下吧(先声明以下的解法,大家可以当作一种思路来看,解法不一定是正解,只是给大家提供一种能够正常想到的思路吧) 试题A:逃离高塔 本题其实没有什么难度,就是一个循环遍历即可,那么唯一需要注意的就是循环遍历的过程中,int是会爆的,这里需要用long来进行存储 public class Main{ public static void main(String[] args){ int ans=0;//记录最终答案 for(long i=1;i<=2025;i++){ long x=i*i*i; if(n%10==3){ ans++; } } System.out.println(ans); } } ​  最后进行的答案就是:

By Ne0inhk
【Java 开发日记】什么是线程池?它的工作原理?

【Java 开发日记】什么是线程池?它的工作原理?

目录 一、什么是线程池? 二、线程池的核心工作原理 核心组件 工作流程详解(结合上图) 补充:线程回收 三、Java中的线程池实现 (ThreadPoolExecutor) 核心构造函数 常见的任务队列 (workQueue) 内置的拒绝策略 四、通过 Executors 工具类创建的常见线程池 五、最佳实践与总结 一、什么是线程池? 核心思想: 线程池是一种基于“池化”思想来管理线程的工具。它预先创建好一定数量的线程,放入一个“池子”中,当有任务需要执行时,就从池子中取出一个空闲线程来执行任务,任务执行完毕后,线程并不被销毁,而是返回池中等待执行下一个任务。 为什么需要线程池? 在深入原理之前,我们先想想如果不使用线程池,我们如何处理多任务: // 原始方式:为每个任务创建一个新线程 for (int i = 0; i <

By Ne0inhk
【Java 基础编程】Java 常用类速查:包装类、String/StringBuilder、Math、日期类一篇搞定

【Java 基础编程】Java 常用类速查:包装类、String/StringBuilder、Math、日期类一篇搞定

常用类是 Java 开发中频繁使用的工具类,掌握这些类的使用方法和特点能够提高开发效率,编写更加规范的代码。 ⚡ 快速参考 * 包装类:将基本类型封装成对象,支持自动装箱和拆箱 * String 类:不可变字符串,使用 + 拼接会创建新对象 * StringBuffer:可变字符串,线程安全,适合多线程环境 * StringBuilder:可变字符串,线程不安全,性能更高,推荐使用 * Math 类:提供数学运算的静态方法 * 日期类:Date、Calendar、LocalDateTime(Java 8+) 📚 学习目标 1. 理解包装类的概念和自动装箱拆箱机制 2. 掌握 String 类的常用方法和不可变性 3. 理解 String、StringBuffer、StringBuilder 的区别 4. 掌握 Math 类的常用方法 5.

By Ne0inhk
飞算JavaAI的安装及其使用方法

飞算JavaAI的安装及其使用方法

标签#JavaAI 首先,我i们先去电脑端自带的浏览器下载IDEA 界面往下滑可以看到下载安装。 安装后软件会显示在桌面,如果没有安装在桌面快捷,可以在系统应用中查找。 启动IDEA,在顶部菜单栏进入 File -> Settings (Windows/Linux)或 IntelliJ IDEA -> Preferences (macOS),打开对话框。 在设置界面左侧选择 Plugins 选项,切换到插件市场。在顶部的搜索框中输入关键词“飞算”。 搜索”Calex-JavaAI“,将该插件安装到右侧使用栏。 在对话框内输入你想要生成代码的题目。这里我用”校园餐饮服务评价系统的设计与实现”为例,做出以下分析及实操过程。 一、需求分析与规划 (一)功能需求 此次开发的餐饮电商系统,对于用户而言,需要能够快速注册登录,维护个人信息,根据自身权限浏览、搜索菜品,下单支付,对已完成订单进行评价等操作;

By Ne0inhk