C++ 学习笔记
完整整理版· 含原理解析 / 易错对比 / 速查表
涵盖:数据类型· 函数与作用域 · 容器 · 字符串 · 二叉树 · 排序 · 类结构
一、数据类型与字符串
1.1 string 与 char 的区别
C++ 中有两套字符串机制:C 风格的 char 数组,以及 C++ 标准库的 string 类。两者都能存储字符串,但在使用便捷性和功能上差异显著。
对比项 | string | char 数组 |
定义字符串 | string name = "张三"; | char name[] = "张三"; |
结构体赋值 | p.name = "张三"; // 直接赋值 | strcpy(p.name, "张三"); // 必须用函数 |
仅定义单字符 | string s = "A"; // 仍是字符串 | char c = 'A'; // 单字符,注意单引号 |
不用数组定义 | 可存任意长度字符串 | char c; 只能存1个字符! |
拼接 | str1 + str2 直接拼接 | 需用 strcat(),麻烦 |
获取长度 | s.size() 或 s.length() | strlen(),不含 \0 |
推荐程度 | ✅ 日常首选 | ⚠️ 仅在需要 C 接口时用 |
��提示日常编写 C++ 优先使用 string。char 数组主要出现在需要与 C 库函数(如 strcmp、strcpy)交互的场景,或函数返回值要求 char* 时。 |
1.2 数组的初始化与有效长度
C++ 数组在定义时如果不显式初始化,内存中残留的是上一次使用的随机值(垃圾数据)。不同初始化方式的行为如下:
几种初始化方式
// ① 未初始化 → 垃圾数据,访问 data[0] 得到随机值 int data[5]; // ② 全零初始化 → 所有元素置 0 int data[30] = {0}; // ③ char 数组字符串初始化 char data[30] = {"张三"}; // 结果:前4字节存 UTF-8 编码的"张三",其余 26 字节全是 '\0' // ④ 部分初始化 → 未指定的元素自动置 0 int arr[5] = {1, 2}; // arr = {1, 2, 0, 0, 0} |
sizeof 只能得到总长度,无法得到有效长度
对于 char 数组,sizeof(data) / sizeof(char)返回的是数组总分配长度(如 30),而不是实际字符串长度。要获取有效字符数,需手动遍历到 '\0'为止:
| char data[30] = {"张三"}; char* p = data; while (*p != '\0') { p++; } int len = p - data; // 有效字符字节数(UTF-8下"张三"= 6字节) // string 则非常简单: string s = "张三"; s.size(); // 直接返回字节数(UTF-8下=6) |
⚠️ 注意 sizeof 是编译期运算符,只知道数组分配了多少空间,不知道里面存了多少有意义的内容。string.size() 才是真正的字符串长度。 |
1.3 动态数组(new / delete)
C++ 标准规定数组大小必须是编译期常量,因此 int data[n](n 是运行时变量)在标准 C++ 中不合法(部分编译器作为扩展支持,但不可移植)。正确做法是用 new 在堆上动态分配:
| int n; cin >> n; // ❌ 不标准(变长数组,VLA),不建议 // int data[n]; // ✅ 标准做法:在堆上动态分配 int* data = new int[n]; // data 是首地址指针 // data[i] 等价于 *(data + i),访问第 i+1 个元素 data[0] = 10; data[n-1] = 99; // 用完必须释放,否则内存泄漏! delete[] data; // 注意:数组用 delete[],单个对象用 delete |
��说明new 在堆(Heap)上分配内存,生命周期由程序员手动管理;局部变量在栈(Stack)上,函数返回自动释放。用 new 分配的内存必须配对 delete/delete[] 释放。 |
1.4 字符(char)与字符串(string)的运算差异
这是一个高频出错点。C++ 中字符和字符串是完全不同的类型,运算符的含义也完全不同。
类型 | 定界符 | + 的含义 | - 的含义 |
char(字符) | 单引号'A' | 整数相加(ASCII值) | ASCII 差值(有意义) |
string(字符串) | 双引号"AB" | 字符串拼接 | 地址差值(无意义) |
| // 字符运算(本质是整数运算) 'A' + 1 // = 66,即 'B' 的 ASCII 码 '9' - '0' // = 9,将字符数字转为整数数字的常用技巧 'z' - 'a' // = 25,字母间距 // 字符串运算 string s1 = "Hello"; string s2 = "World"; string s3 = s1 + s2; // = "HelloWorld" // ⚠️ 陷阱:字面量字符串不能直接相加 // string s = "Hello" + "World"; // ❌ 编译错误!两个都是 const char* string s = string("Hello") + "World"; // ✅ |
⚠️ 注意 遍历字符串时 s[i] 得到的是 char,判断时必须用单引号:if(s[i] == '.') 而非 if(s[i] == ".")。类型不匹配会导致编译错误或隐式转换问题。 |