蓝桥杯C++梳理(1):从入门到数组

你好,这是我对最近学习的C++知识和易错点的简单总结

写题思路小技巧 📝

先梳理步骤、模拟情境,能大幅减少后续思考时间。

  1. 先把题目整体框架捋出来:需要给哪些变量赋值、有几层循环、核心判断条件是什么;
  2. 用一串数字 / 字符模拟执行情境,比如先写 "i=0 时执行 XX,i=1 时执行 XX";
  3. 把步骤简单写下来,后续写代码时直接对照,能少走很多弯路。

一、C++ 入门 🚀

1. 头文件与命名空间

一句话理解

C++ 入门最容易漏写正确的头文件,或忘记加命名空间导致 cin/cout 用不了。

深入

刚开始写代码时,经常犯两个基础错:

  • 头文件漏加:比如用 cin/cout 要加**<iostream>**,用 abs 函数要加<cstdlib>,漏了就会报错;
  • 命名空间:using namespace std;
补充✨✨✨
  • 核心头文件对应场景:
    • 输入输出(cin/cout)→ <iostream>
    • 数学函数(abs/fabs/round)→ <cmath>
    • 字符串函数(memset/strcpy)→ <cstring>
    • 标准库函数(abs/exit)→ <cstdlib>
    • 字符判断(islower/tolower)→ <cctype>

2. cin/cout 使用易错点

一句话理解

cin 用 >>、cout 用 <<,换行 / 空格要手动加,空格不会自动出现。

  • 易错点 1:cout 打换行要加endl(或\n),比如cout << 123 << endl;,忘加就不会换行;
  • 易错点 2:cout 打印空格必须手动写" ",比如想打 "1 2 3",要写cout << 1 << " " << 2 << " " << 3;,不然会变成 "123"。

3. 全局变量 vs 局部变量

竞赛里用全局变量,省事儿还不容易出问题。

4. 进制与科学计数法

  1. 八进制以 0 开头、16 进制以 0x 开头
  2. 科学计数法用 E 表示 10 的次方,且结果是浮点型
  • 进制写法:
    • 八进制:012 → 对应十进制的 10;
    • 16 进制:0X1A → 对应十进制的 26;
  • 科学计数法:
    • 3.14E2 = 3.14×10² = 314.0(不管 E 前是整数还是小数,结果都是浮点型);
    • 5E-3 = 5×10⁻³ = 0.005。
补充

16 进制的 X 大小写都可以(0x1A/0X1A),但习惯上写小写更常见。

5. #define 定义常量

#define 是直接替换文本,不用加分号,也不关注数据类型。

深入

#define 的用法超简单:#define 名字 内容,比如:

  • #define PI 3.14159 → 代码里所有 PI 都会被替换成 3.14159;
  • 易错点:末尾不要加分号!如果写#define PI 3.14;,替换后会变成3.14;,分号也会加进去

6. const 定义常量

const 定义常量要加类型和分号,比 #define 更严谨,常量名习惯大写。

深入

const 的语法是:const 类型 常量名 = 值;,比如:

  • const double PI = 3.14159; → 必须加 double 类型,末尾加分号;
  • 和 #define 的区别:
    1. const 前面没有 #,#define 必须加 #;
    2. const 要指定类型,#define 只做文本替换;
    3. const 末尾加分号,#define 不加。
补充

⚠️ (不管 #define 还是 const 定义)习惯写成大写(比如 PI、MAX_NUM),普通变量名小写

7. 类型选择

整型用 long long、浮点型用 double,新手这么写基本不会出错。

深入
  • 整型:题目经常 "挖坑",int 范围不够(大概 ±2×10⁹),用 long long(范围 ±9×10¹⁸)最靠谱,写的时候可以省略 int,直接写long long a;
  • 浮点型:float 精度不够,直接写 double 就好,我做题从没因为用 double 出过错;
  • 简化 long long:用 typedef 缩写,比如typedef long long ll;,之后直接写ll a;就可以。

8. 浮点数转换

整数转浮点型要么加小数点,要么强制类型转换,避免整数除法的坑。

深入
  • 整数转浮点型:
    • 直接加小数点:6/4是整数除法(结果 1),6.0/4就是浮点除法(结果 1.5);
    • 强制转换:两个都是变量时,(double)a / b(把 a 转成 double,再和 b 相除);
  • ⚠️易错点:强制转换要加括号,比如(double)(a + b)才是把 a+b 的结果转成浮点型,不是(double)a + b。这个真的错过

9. 取模运算符(%)

取模得余数,结果的正负号由第一个数决定。

深入
  • 核心:a % b = a 除以 b 的余数;
  • 正负规则:
    • 5 % -2 = 1(第一个数 5 是正,结果正);
    • -5 % 2 = -1(第一个数 - 5 是负,结果负);
    • 5 % 2 = 1,-5 % -2 = -1。
补充

取模的两个数必须是整型,不能对浮点型用 %(比如3.14%2会报错)。

10. = 和 ==

一个等号是赋值,两个等号是判断相等,if / 循环里千万别写混。

深入
  • a = 5:把 5 赋值给变量 a,不管 a 原来的值是啥;
  • a == 5:判断 a 的值是不是等于 5,返回 true/false;
  • 易错点:if 里写if(a = 5)不会报错,但逻辑错了(永远为真),新手超容易犯这个错。

二、件判断与循环 🔄

1. 悬空 else

else 永远和最近的 if 匹配,写代码加 {} 能避免逻辑混乱。

解决办法:不管代码多短,都给 if/else 加 {},比如:

2. printf 格式化输出

printf 打百分号要写 %%,打指定小数位数用 %.nf,n 是位数。

深入
  • 打百分号:printf("%.2f%%", 3.14); → 输出 "3.14%";
  • 打小数位数
    • printf("%.2f", 3.1415); → 输出 "3.14"(保留 2 位);
    • printf("%.1f", 2.99); → 输出 "3.0"(保留 1 位,自动四舍五入)。

3. printf/scanf 占位符规则

  • printf 的 % f 适配 float/double,
  • scanf 的 % lf 只给 double 用,% f 给 float 用。

4. 绝对值函数

  1. 整数绝对值用 abs(头文件 cstdlib),
  2. 浮点型用 fabs(头文件 cmath),

返回值和输入类型一致。牛

深入
  • abs:针对 int/long long,比如abs(-5)=5,abs(5LL)=5LL;
  • fabs:针对 float/double,比如fabs(-3.14)=3.14,fabs(2.5)=2.5;
  • 特点:输入啥类型,返回啥类型,比如给 abs 传 long long,返回也是 long long。

5. 条件操作符(三目运算符)

三目运算符是简化版 if,格式:条件?真执行:假执行

深入
  • 语法:条件 ? 表达式1 : 表达式2
  • 逻辑:条件为真,执行表达式 1;条件为假,执行表达式 2;
  • 例子:int max = a > b ? a : b; → 等价于 if (a>b) max=a; else max=b;
注意

复杂逻辑(比如多句代码)还是用 if 更清晰。

6. switch-case-break-default 语句

switch 的完整结构:

复制代码
switch (变量) {
    case 常量1:
        代码1;
        break; // 执行完case1就退出
    case 常量2:
        代码2;
        break;
    default: // 所有case都不匹配时执行
        代码3;
        break;
}
  • 易错点:漏写 break 会 "穿透",比如 case 1 没 break,执行完 case1 会继续执行 case2;
  • default 可选,但建议加,处理意外情况。

三、数组与字符串 📚

1. 数组下标

数组第一个元素下标是 0,第 N 个元素下标是 N-1!

⚠️ 数组越界是新手高频错误,编译时可能不报错,但运行时会出问题。

2. 范围 for

范围 for 能遍历数组,但不能改元素内容

深入
  • 语法:for (类型 变量名 : 数组名) { 代码 }
  • 原理:创建一个临时变量,把数组元素逐个赋值给它
  • 易错点:冒号(:)容易漏写,漏了直接报错。
补充

想改数组元素,要加引用:for (int &e : arr),此时 e 是数组元素的别名,改 e 就是改数组。

3. auto

auto 让系统自动推导变量类型,用在范围 for 里超方便。

深入
  • 核心:auto 不用手动写类型,系统根据赋值自动判断,比如:

    复制代码
    auto a = 5; // 推导为int
    auto b = 3.14; // 推导为double
    auto c = 'a'; // 推导为char
  • 常用场景:范围 for 里简化代码,比如for (auto e : arr),不用管 arr 是 int 还是 double 数组;

  • 好处:懒得想变量类型时用 auto,省时间还不容易错。

4. memset

memset 按字节设值,头文件 cstring,只适合把数组设为 0

深入
  • 语法:memset(数组名, 要设的值, 总字节数)
  • 原理:按字节赋值,int 占 4 字节,设为 1 的话每个字节是 1,最终值是 0x01010101=16843009,不是 1;
  • 正确用法:只设 0,比如memset(arr, 0, sizeof(arr))(sizeof (arr) 自动算总字节数)。

5. memcpy

memcpy 按字节拷贝数组,头文件 cstring,++最后一个参数是总字节数++。

深入
  • 语法:memcpy(目标数组, 源数组, 总字节数)

  • 和 memset 的相似点:第一个参数是要改的数组地址,最后一个是总字节数;

  • 易错点:拷贝 int 数组时,总字节数不是元素个数,而是元素个数×sizeof(int),比如memcpy(arr1, arr2, 10*sizeof(int))(拷贝 10 个 int 元素)。

    #include <cstring>
    int main() {
    int arr1[5] = {1,2,3,4,5};
    int arr2[5];
    memcpy(arr2, arr1, sizeof(arr1)); // 把arr1拷贝到arr2
    for (auto e : arr2) {
    cout << e << " "; // 输出1 2 3 4 5
    }
    return 0;
    }

6. 数组创建技巧

  • 防越界:要存 n 个元素,就创建n+10个元素的数组,靠谱
  • 全局数组:在 main 函数外创建数组,内存空间更大,不会因为数组太大崩溃

7. 四舍五入

round 是银行家取整,新手用 "+0.5 强制转 int" 更靠谱

  • round 函数(头文件 cmath ):银行家舍入(四舍六入,0.5 取偶数),比如round(3.5)=4round(2.5)=2
  • 新手方法:(int)(num + 0.5),比如(int)(3.5+0.5)=4(int)(2.4+0.5)=2,逻辑简单还不容易错。

8. 比较改变前后:创建两个数组

想把数组排序后和原数组对比:

  • 错:只创建一个数组,排序后原数据没了,没法对比;
  • 对:创建 arr(原数组)和 arr_copy(拷贝数组),排序 arr_copy,用 arr 和 arr_copy 对比。

9. cin/cout 读写字符数组

cin/cout 只能直接读写字符数组,不能直接读写整型 / 浮点型数组

10. 输入带空格的字符串

cin/scanf 读不了带空格的字符串,用 fgets / 升级版 scanf/getchar

深入
方法 语法 特点
fgets fgets(arr, sizeof(arr), stdin); 头文件 cstdio,保留 \n,自动加 \0,安全
升级版 scanf scanf("%[^\n]s", arr); 读至回车,自动加 \0,不能读空格开头
getchar while ((ch=getchar())!='\n') {arr[i++]=ch;} 边读边处理,灵活,需手动初始化数组为 0
代码示例(getchar 边读边统计)
cpp 复制代码
#include <cstdio>
int main() {
    char str[1100] = {0}; // 初始化全0
    int nums[26] = {0}; // 统计小写字母次数
    int i = 0;
    char ch;
    while ((ch = getchar()) != '\n') { // 读至回车
        nums[ch - 'a']++; // 统计字母次数
        str[i++] = ch;
    }
    return 0;
}

11. strcpy 与 strcat

**只针对字符串:**strcpy 拷贝字符串、strcat 追加字符串,都只要两个参数,头文件 cstring。

深入
  • strcpy:strcpy(目标字符数组, 源字符串),把源字符串拷贝到目标数组,自动加 \0;
  • strcat:strcat(目标字符数组, 追加字符串),把追加字符串加到目标数组末尾;
  • 和 memcpy 的区别:
    • strcpy/strcat 只针对字符串,不用传字节数;
    • memcpy 针对任意数组,要****传字节数。

12. 字符串打印

% c 按 ASCII 打印、% s 打印双引号内容,小写减空格(32)等于大写。

深入

核心规则:

  • % c:把数字 / 字符按 ASCII 码解析,比如%c打印 97→'a',打印 'a'-32→'A';
  • % s:只能打印字符串(双引号 / 字符数组),不能打印数字(比如printf("%s",97)报错);
  • 大小写转换小写字母 ASCII 码 - 32(空格的 ASCII 码)= 大写字母
代码示例
cpp 复制代码
    printf("%c", 97);//%c会把数字识别为ASCII码值,找到对应的字符
	printf("%c", 'a');//单括号字符也是ASCII码值
	//printf("%c", a);//报错:a相当于是个变量
	//cout << a;//报错:a相当于是个变量
	cout << 'a';//字符
	//cout << 'a' - 32;得到的是97-32=65,是个数字
	cout << 'a' - ' ';//同上
	
	//空格的码值是32

	printf("%c", 'a' - ' ');//得到的是A

	printf("\n");

	//printf("%s", 97);//错误

	printf("%s", "assss aa");//%s能打印双引号中的所有内容

13. islower 与 tolower

islower 判断小写字母、tolower 转小写,头文件 cctype。

深入
  • islower:islower(ch),ch 是小写字母返回非 0,否则返回 0;
  • tolower:tolower(ch),把大写字母转小写,小写 / 非字母不变;
  • ++对应函数:isupper(判断大写)、toupper(转大写)++。

14. 循环条件易错点(\0 vs \n)

  • fgets 读的字符串用!= '\n',
  • scanf%[^\n] s 用!= '\0',
  • getchar 要初始化数组为 0,用!= '\0'。
深入

不同输入方式的字符串结束符:

  • fgets:读入的字符串末尾是\n+\0,循环遍历用arr[i] != '\n'
  • scanf ("%[^\n] s"):末尾只有\0,循环遍历用arr[i] != '\0'
  • getchar:手动读入,需先把数组初始化为 0,循环遍历用arr[i] != '\0'

⚠️ 忘记区分结束符会导致循环多执行 / 少执行,比如 fgets 读的字符串用!= '\0' 会把\n也当成有效字符。


相关推荐
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章26-图像拼接
图像处理·人工智能·opencv·算法·计算机视觉
wanderist.1 小时前
算法模板-01trie数
c++·算法
PingdiGuo_guo1 小时前
C++指针(一)
开发语言·c++
天若有情6732 小时前
IoC不止Spring!求同vs存异,两种反向IoC的核心逻辑
java·c++·后端·算法·spring·架构·ioc
tankeven2 小时前
HJ103 Redraiment的走法
c++·算法
瓦特what?2 小时前
平 滑 排 序
c++·算法·排序算法
醒过来摸鱼2 小时前
合并区间问题
算法
Trouvaille ~3 小时前
【动态规划篇】专题(二):路径问题——在网格图中的决策艺术
c++·算法·leetcode·青少年编程·动态规划
货拉拉技术3 小时前
文本大模型评测实践
人工智能·深度学习·算法