26春CS100期中复习
尚未完成 C部分待补充 细节待Review
C++ Part
Lec11-13 C++ Basics
Standard library
- Standard Library中的names都被placed in
std这个namespace, e.g.std::cin - 对C standard library的兼容: 改
#include <xxx.h>为#include <cxxx>
<iostream>
std::cin, std:cout
e.g. A+B Problem
1 |
|
Question: std::cin >> s会忽略leading whitespaces吗?
Answer: 会. 例如用户输入” abc”, 实际读到s == "abc"
Question: std::cin >> s会读取整行吗? 什么时候停止读取?
Answer: 不会, 一旦遇到空白即停止. 例如用户输入”Hello World”, 实际读到s == "Hello"
Question: 如果我既不想忽略leading whitespaces, 又不想读取整行, 怎么做?
Answer: 使用std::getline(std::cin, s) 它会一直读到换行符\n再停(consume it) , 但并不会存储\n
<string>
定义与初始化
1 | std::string str0 = "aaa"; //operator= overloading |
可以用+做拼接(concatenation), 至少一边是std::string, +是左结合
用a += b, 语义同a = a+b, 但省去了建构临时objecta+b, 拷贝a的资源浪费
直接用<,<=,>,>=,==,!=等符号即可做字典序(lexicographical)比较, 不用像C一样用strcmp
Member functions
.size().empty()
<vector>
动机: 一个”better dynamic array”, 自动管理内存, 提供一系列内置方法, 自动拷贝, 有默认空初始化
- 存储不同
<类型>成员的std::vector不是同一类型
Create a std::vector
回忆: constructor相关知识
1 | std::vector<int> v{2, 3, 5, 7}; // A vector of `int`s, |
Copy a std::vector
1 | std::vector<int> v2 = v; // `v2`` is a copy of `v` |
内置方法(类成员函数)
.size()
.empty()
.push_back()(加到末尾 回忆python list.append())
.pop_back() (删除末尾 回忆python list.pop())
.front()和.back() 返回首/尾位置的引用
.at(index) 比[index]更好的下标访问, 有边界检查, 越界会throw exception: std::out_of_range
References (左值)引用
概念理解: 把一个别名(alias)绑定到一个对象(object)上
syntax: ReferredType &reference_name = some_referred_to_object
行内声明多个同类型references时, &要写在每一个reference_name前
错误示范:
1 | int& x = ival, y = ival, z = ival; |
一个引用只能被一次性绑定到一个对象, 不可重复绑定, 但一个对象可以有多个引用
补充: * and &各种用途大汇总
Both symbols have many identities!
In a declaration like Type
*x = expr,*is a part of the pointer typeType *.*声明指针In a declaration like Type
&r = expr,&is a part of the reference typeType &.&声明引用In an expression like
*opndwhere there is only one operand,*is the dereference operator.*解引用In an expression like
&opndwhere there is only one operand,&is the address-of operator.&取地址In an expression like
a * bwhere there are two operands,*is the multiplication operator.*做乘法In an expression like
a & bwhere there are two operands, & is the bitwise-and operator.&二进制与
reference-to-const
动机: 三大优点如下
避免拷贝 Avoids copy.
可绑右值(注意这点与一般reference不同) Accepts temporaries and literals (rvalues).
避免错误修改应该只读的量 The const qualification prevents accidental modifications to it.
e.g.
1 | int count_lowercase(const std::string &str) { // `str` is a reference-to-`const` |
Range-based for loops
e.g. for (char c : s)
联想: 类似python中for c in s?
- 若要对
s进行修改, 需声明循环变量c为引用char &c :s
类型转换
字符串 and 数字(arithmetic numbers)
function(此处省略std::, 定义在<string>) |
explanation |
|---|---|
stoi()(string to int), stol()(string to long), stoll(string to long long) |
字符串–>有符号整数 |
stoul()(string to unsigned long), stoull()(string to unsigned long long) |
字符串–>无符号整数 |
stof()(string to float), stod()string to double, stold()(string to long double) |
字符串–>浮点数 |
to_string() |
整数/浮点数–>字符串 |
Explicit Casts
const_cast
去掉low-level constness(DANGEROUS)
注意⚠️: 从const_castform的non-const access path修改const变量(top-level-const)会UB, 非必要不用const_cast 这样的危险行为
1 | int ival = 42; |
reinterpret_cast
转换指针类型(DANGEROUS)
注意⚠️: 勿忘实际指向的对象还是原类型, 不能当成一般转换后类型的指针用, 非必要不用reinterpret_cast
static_cast
详见Lec19 类型转换部分
auto
动机: 声明变量时, 让编译器推断类型, 简化某些very long types, 或者我们不知道但编译器知道的特殊类型, 如对lambda expression
一些例子:
1 | auto x = 42; // `int` |
补充:decltype(expr)函数, 可以不执行expr(它可以是对另一个函数的调用)而推断返回类型
Function overloading
总结: 共用函数名, 具有不同参数类型, 调用时分别match
a simple example
1 | void fun(int); |
nullptr
在C++中建议用nullptr代替NULL作为空指针
nullptrhas a unique typestd::nullptr_t(defined in<cstddef>), which isneithervoid *nor an integer.
Lec14-16 Class Basics
成员变量与成员函数
this指针
member function作为object的方法, 隐式接受对应objectclassName *类型的指针this, 并将在函数体内对成员变量xxx的访问, 隐式转换为this->xxx //等价于(*this).xxx
access control
private成员,只能通过成员函数或friend函数访问public成员, 在程序任意处可访问
const member functions
位置: 参数列表(T param)后 function body {前
e.g.bool graduated(int year) const {...}
用于只访问不修改 成员变量 的 成员函数
函数内的this指针也自动带上了const成为const X *
Constructors 构造函数
名字同类名
构造函数没有返回值 没有返回类型
初始化列表 initializer list
The initializer list starts with
:, and contains initializers for each data member, separated by,. The initializers must be of the form(...)or{...}, not= ....
概括: 接在参数列表后, 冒号开头, 以成员变量名(初始化值)或成员变量名{初始化值}格式
e.g.
1 | Student(const std::string &name_, const std::string &id_) |
- 成员按照声明的顺序初始化, 并非按照initializer list
顺序不一致会发生什么?
If the initializers appear in an order different from the declaration order, the compiler will generate a warning.
Typical mistake:
entranceYearis initialized in terms ofid, butidis not initialized yet!
1
2
3
4
5
6
7
8 class Student {
std::string name;
int entranceYear; // !!!
std::string id;
public:
Student(const std::string &name_, const std::string &id_)
: name(name_), id(id_), entranceYear(std::stoi(id.substr(0, 4))) {}
};
Q: **(重要)**为什么不在constructor函数体内部用赋值初始化? 就像这样:
1 | class Student{ |
A: 在进入函数体之前, 由于没有写initializer list, 编译器会先将成员变量都做默认初始化, 可万一某个类型不能默认初始化呢? 这不就出错了吗
不能默认初始化/被赋值的类型们:
T &引用 不能初始化 不能被赋值const对象 不能被赋值- 被设计为拒绝默认初始化的
class
默认构造函数 Default Constructors
格式: 没有输入参数的Constructor 如Point2d() : x(0), y(0) {}
作用: 规定对象的默认初始化行为
如果没有任何自定义constructor, 编译器才会synthesize a default constructor
如果有自定义constructor, 还需要synthesized default constructor,使用className() = default
Copy Constructor& Copy-assignment operator
动机: 避免shallow copy(指向同一块内存)
| type | syntax | 适用 | 备注 |
|---|---|---|---|
| Copy Constructor | className(const className &other):xxx(yyy){....} |
拷贝初始化(copy-initialization)T s2=s1(declaration statement), T s2(s1), T s2{s1} |
/ |
| Copy-assignment operator | className &operator=(const className &other) |
赋值表达式s1 = s2(expression) |
注意self-assignment safe |
- 用或删synthesized one:
= default,=delete
The rule of three
要么自定义0个, 要么自定义3个
更完备的版本: 详见Lec17 The Rule of Five
- copy constructor
- copy-assignmnet constructor
- destructor
Destructors 析构函数
动机: 当一个object生命周期结束时, 需要释放掉对应内存资源
格式: ~ClassName() {...}
What’s more: 在析构函数中, 成员变量在函数体执行后再摧毁, 摧毁顺序和declare相反
Type alias members 类型别名成员
动机: A better way of declaring type aliases
与传统C相比较
1 | // C-style |
作为class member定义时, usage: className::TypeAliasName
All standard library containers (and std::string ) define the type alias member size_type as the return type of .size()
1 std::vector<int>::size_type j = v.size();
static members
static data members
- 理解为一种”global variable”
- 属于类本身, 不属于类的任何对象, 但可以通过对象用
.来访问 - 用
className::来调用(回忆 type alias members)
static member functions
- 同静态数据成员, 属于类本身, 不属于类的任何对象, 但可以通过对象用
.来访问, 但不会绑定到this指针
friend functions
动机: 如何在一个类外定义的非成员函数中访问类内private members呢?
syntax: 随便定义在class的哪里(但通常在首尾), 照抄函数定义在{//function body...}前的内容, 前面加friend关键字, 删掉参数名
即在类内声明(declare)这个函数. 回忆: 类似function prototype (*this is not covered in CS100)
e.g.
1 | void print(const Student &stu) { |
What’s more:
- 一个
class也可以是friend - 用
::可以在类外定义成员函数
Lec17 右值引用和移动
右值引用
动机:s=a+b时, 右值a+b会被拷贝给临时变量再赋值给s, 太慢了, 能否直接steal the contents
1 | int &&rr = 42 //'rr' is an rvalue reference |
class的移动函数
move assignment operator范例
1 | class Dynarray{ |
有了如上的move assignment operator后, 右值被移动,左值被拷贝
1 | a = concat(b, c); // calls move assignment operator, |
The Rule of Five
The Rule of Five: Define zero or five of them.
- copy constructor
- copy assignment operator
- move constructor
- move assignment operator
- destructor
std::move
动机: m_label = other.m_label;这会call copy assignment operator, 因为other.m_label是左值, 那如果我想要移动呢?
Defined in <utility>
std::move将左值转换为右值, 方便我们移动(call move assignment operator)
Copy Elision&NRVO
copy elision(拷贝省略)(since C++17): 以下代码不发生拷贝或移动, 直接将a+b的结果构造在s的内存上
1 | std::string foo(const std::string &a, const std::string &b) { |
NRVO=Named Return Value Optimization 理解为特殊的copy elision
例如
1 | Named Return Value Optimization, NRVO |
Lec18 智能指针
std::unique_ptr
规范构造方法 使用std::make_unique<Type>(args)
1 | auto p = std::make_unique<std::string>(5,'c'); // 管理字符串"ccccc" |
unique所有权, 只能move不能copy
1 | auto r = std::move(p) //正确, p变为null, 管理对象所有权转交给r |
错误示范❌
1 | auto q = p; //错误! 不允许copy 不要这样写! |
std::shared_ptr
规范构造方法 使用std::make_shared<Type>(args);
1 | auto p = std::make_shared<std::string>(10,'c'); |
拥有方法use_count(),返回reference counter计数,用途是通过追踪有多少个std::shared_pointer正共享资源,当计数归零时可释放资源
Lec19 Operator Overloading
运算符重载语法
举例如下
1 | bool operator<(const Rational &lhs, const Rational &rhs) {...} |
特殊例子1(重载标准输入输出)
1 | class Rational { |
注意要点
std::ostream类型匹配std::cout,std::istream类型匹配std::cin- 操作的应当是原来的输入输出流, 因此流对象
std::cout,std::istream应该以引用&方式传入和返回
特殊例子2(++与–的prefix与postfix)
1 | class Rational { |
类型转换
区分显式转换与隐式转换: 显式转换<–>目标类型U在转换表达式中显式写出
显式转换三种形式
| 表达式 | 解释 | 举例 |
|---|---|---|
✅ what_cast<U>(expr) |
C++ named casts | static_cast<int>(3.14)将3.14转换为int |
✅U(expr) |
类比构造函数使用(constructor call) | std::string("xx") 将const char[3]转换为std::strng |
| ❗不推荐 (U)expr | C-style 兼容但不推荐在C++中继续使用 | (int)3.14 |
类型转换运算符
在自定义class中定义了转换到double的运算符operator double() const {...},
此时可以自动发生隐式转换,如double dval = r;
- 记得加
const - 若要禁止隐式转换调用, 在返回之前加
explicit关键字,如explicit operator double() const {...}
Lec20&23 Iterators and Algorithms
迭代器基础
动机: Iterator是更generalized的”pointer”, 用来获取容器成员量
每个 container 都有对应的iterator,类型为 Container::iterator,实际使用时用 auto 让编译器自动推断即可。
1 | for (auto it = str.begin(); it!= str.end(); it++){...} |
普通指针也是iterator,例如数组Type a[N], 初始迭代器为a, 终止迭代器为a+N
在<iterator>中定义了std::begin和std::end函数, 统一了返回STL容器或数组begin/end iterator的接口
数组的delete[],std::vector的push_back(),pop_back()等方法会导致原先iterator的无效化(invalidation)
迭代器的分类
Forward Iterators 只能向前移动
Bidirection Iterator 可以双向移动
Random Access Itertator 可以任意移动(
it+n,it[n],…)std::vector, 指针是经典的随机访问迭代器std::sort必须接受Random Access Iterator
用迭代器范围初始化STL容器
1 | std::vector<char> v = {'a','b','c','d','e','f','g','h','i'}; |
STL algorithms 参数格式
接受pairs of iterators来表示范围
1 | int a[N]; |
STL algorithms 返回值格式
返回值通常用迭代器表示位置, 若要取值需*解引用
“找不到”通常返回end迭代器
附: if语句也可以在condition内补scope内初始化值 方便在expression中复用
if (init_expr; condition)
STL algorithms 注意事项
STL algorithms NEVER insert or delete elements in the containers!
传入的是迭代器, 所以永远不会修改容器长度
常用STL algorithms
定义在<algorithm>的
std::replace:替换区间内所有等于指定值的元素1
std::replace(vec.begin(), vec.end(), 0, 42);
std::sort:排序区间元素,可自定义比较1
std::sort(vec.begin(), vec.end(), cmp); //若第三个可选参数传一个函数`cmp`, 会用`cmp(x,y)`代替`x<y`来比较(作为“x 是否应该排在 y 前面”的判断)
std::nth_element将第n个元素放到假设该序列排序后的位置,但:- 左边元素都 ≤ 它
- 右边元素都 ≥ 它
- 左右两边不保证有序
1 | std::nth_element(begin, nth, end, cmp);//若第四个可选参数传一个函数`cmp`, 会用`cmp(x,y)`代替`x<y`来比较(作为“x 是否应该排在 y 前面”的判断) |
std::unique:把重复项扔到最后, 没有删除, 返回迭代器pos, 使得[begin, pos)部分无重复. 常配合 erase 删除多余元素
1 | auto it = std::unique(vec.begin(), vec.end()); |
std::partition:按条件划分区间,满足的放前面, 不满足的放后面, 返回分界位置(第一个不满足的)迭代器1
auto mid = std::partition(vec.begin(), vec.end(), [](int x){ return x <= 5; });
std::iota:按递增值填充区间1
std::iota(vec.begin(), vec.end(), 1);
std::for_each:对区间每个元素执行操作1
std::for_each(vec.begin(), vec.end(), [](int& x){ x *= 2; });
std::prev_permutation:生成上一个字典序排列1
bool ok = std::prev_permutation(vec.begin(), vec.end());
std::lexicographical_compare:按字典序比较两个序列1
bool less = std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
std::equal:判断两个序列是否相等1
2bool same = std::equal(a.begin(), a.end(), b.begin()); //
bool same = std::equal(a.begin(), a.end(), b.begin(), b.end()); //检查长度相等
定义在<numeric>的
accumulate(begin, end, initValue): 从[begin, end)求和, 再加到初始值initValue上.
accumulate(v.begin(), v.end(), 0) 返回v中的元素求和 .
inner_product(begin1, end1, begin2, initValue)求向量内积, 再加到初始值initValue上.
Predicates
含义: 如find_if(begin, end, pred)找到[begin, end)范围中的第一个满足pred(element)为真的值, pred是callable object, 可以是function, function object, 也可以用lambda表达式代替
Function Objects
定义: 将operator()重载了的struct对象
fo(arg1, arg2, ...)is equivalent to fo.operator()(arg1, arg2, ...)
Lambda expressions
动机: 简化代码, 一次性使用的函数不用单独定义, 用表达式取代
1 | [capture_list](params) -> return_type { function_body } |
- capture_list “捕获”列表, 从外部scope”捕获”并存到内部scope的量(对应: function object成员变量), 避免拷贝可以加
&直接取引用 - params: 参数, 对应一般函数接收参数 记得表明类型, 放在STL algorithms时会自动将[first, end)范围内每个迭代器传入
- function_body: 对应一般函数体, 无特殊要点
Sequence containers
std::string不是container
| containers | 解释 |
|---|---|
std::vector<T> |
动态连续数组 任意位置增减慢 |
std::deque<T> |
double-ended queue 双向 头尾快速增删 |
std::array<T,N> |
container版本的built-in arrayT[N] 支持STL container方法 不会转为pointer |
std::list<T> |
双向链表 数据不连续排放 任意位置快速增删 不可快速随机访问 |
std::forward_list<T> |
单向链表 数据不连续排放 |
不同数据组织形式 Interfaces汇总
连续存储:std::string,std::vector,std::array
不支持push_front,emplace_front,pop_fornt
链表结构:std::list<T>,std::forward_list<T>
不支持:operator[],at
construct
Container c(b,e)
- 标题: 26春CS100期中复习
- 作者: AlexWei
- 创建于 : 2026-05-23 19:40:00
- 更新于 : 2026-05-23 20:01:57
- 链接: https://www.alexwei.top/2026/05/23/CS100-Midterm-Review-26Spring/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。