读这一页之前,先知道读完要能做什么
- 说清
#include <bits/stdc++.h>和using namespace std;这两行是干嘛的 - 写出来
cin >> x读一个词、getline读一整行,且知道cin >>之后直接getline会读到空行 - 知道
auto是「类型编译器自己推」,以及size()是无符号数、0 − 1会绕回 - 用过
freopen把输入输出重定向到文件(并知道交评测前必须删掉)
这是什么
一句话:每个新文件前两行都是一样的,后面所有板块都默认你已经写了它们。
★ #include <bits/stdc++.h>:把 C++ 标准库一次全部带进来 —— 之后 vector、string、cout 都能直接用,不用一个个 include。
★ using namespace std;:标准库里的名字默认都带 std:: 前缀(std::cout)。有了这行可以直接写 cout —— 本书从头到尾都这么写。
★ auto:让编译器自己推类型。auto x = 1; 就是 int x = 1;;for (auto &[k, v] : m) 里两个名字的类型也是它推的。看不懂可以先当成「那种类型」。
★ s.size()、v.size() 返回的是无符号数 —— 装不下负数,0 − 1 会绕回一个天文数字。所以和 int 比大小时一律写 (int)v.size()。
★ 读入分两种:cin >> s 读一个词(空格、换行都截断);getline(cin, s) 读一整行。⚠ cin >> n 之后直接 getline 会把残留的换行当成「一行」读走 —— 见陷阱 ①。
★ 本地调试想让程序「从文件读、往文件写」,不用改任何读写代码,在 main 开头加两行 freopen 重定向就行 —— 见陷阱 ③ 和练习。
完整动作表
复杂度写的是这个动作自己的代价,不是整个程序的。「这一栏最容易错的地方」那一列是重点。
| 写法 | 干什么 | 代价 |
|---|---|---|
#include <bits/stdc++.h> | 把 C++ 标准库一次全部带进来 ★ 本书一律这样写,不用记一个个 #include | — |
using namespace std; | 之后写 cout、vector 不用再带 std:: 前缀 | — |
auto x = ...; | 类型由编译器自己推 ★ 第一次看到 auto 当「那种类型」读就行 | — |
cin >> s; | 读一个词:空格、换行都在那儿截断 ★ 读数、读没有空格的名字用它 | — |
getline(cin, s); | 读一整行:含空格,换行才截断 ⚠ 和 cin >> 混用时注意残留的换行(陷阱 ①) | — |
s.size(); | 字符个数(string)/ 元素个数(vector) ⚠ 返回无符号数:和 int 比写 (int)s.size() | O(1) |
freopen("in.txt", "r", stdin); | 把「读」重定向到文件 in.txt★ 之后 cin/scanf 都从它读,代码不用改 | — |
freopen("out.txt", "w", stdout); | 把「写」重定向到文件 out.txt★ 之后 cout/printf 都写进它 | — |
⭐ 这一节最容易错的地方(3 处)
这一节排在例题前面是故意的:读到一个坑,再去看正确的例子,记得住。 下面每一条都是「编译得过去、答案可能是错的」那种 —— 它们才是 OI 里真正扣分的地方。
① `cin >> n` 之后直接 `getline`,读到的是空行
cin >> n 读完那个数就停,它后面的换行还留在缓冲区里。
★ 所以紧接着那句 getline(cin, s) 读到的就是「换行之前」—— 一个空字符串。不报错,但你以为读进了一行正文。int n;
cin >> n;
cin.ignore(); // ★ 把残留的换行扔掉
string s;
getline(cin, s); // 这下读到的才是正文cin >> 和 getline 混着用时,中间补一句 cin.ignore();。② `0 - 1` 在无符号数里会绕回一个天文数字
size() 返回的是无符号数,无符号数装不下负数。
★ 于是 int n = v.size(); 之后 n - 1 若为 −1,拿它去 v[...] 或和别的量比,行为就别扭了 —— 编译器只给一句「signedness」警告。// 循环次数和长度打交道,一律先转 int:
for (int i = 0; i < (int)v.size(); i++) { ... }
// 判断「没元素」别写 v.size() - 1,直接写 v.empty()(int)s.size();判空用 empty(),别用 size() == 0 以外的花活。③ `freopen` 重定向之后,交到评测机上程序读不了你的文件
freopen("in.txt", "r", stdin); 会让程序去当前目录找 in.txt。
★ 本地方便,但交到洛谷 / 比赛的评测机上,那台机器上根本没有 in.txt —— 程序直接读不到输入、得 0 分。// 想留着本地调试的两行,就注释掉;交评测前务必删干净
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);freopen 是本地调试的临时手段:上机前删掉或注释掉。临时注释是常用做法 —— 下次本地调试再打开。本书哪一章真的用到它
⚠ 下表里的文件路径和那串 probe 是逐字验过的(check:docs 第 ⑳ 条)—— 改了那份代码这儿会红,正是要的。点章号直接去看那一页。
| 章 | 书里的哪一份代码 | 用它来干什么 |
|---|---|---|
| 第 1 章 | code/01-recursion-intro/gen.cpp | ★★ 第一章的程序就这两行开头 —— 本书所有代码都长这样 |
| 第 1 章 | code/01-recursion-intro/gen.cpp | ★★ 有了这行,正文里的 cout 才不用写成 std::cout |
例题(2 道)
每道都给全套:题面 → 样例 → 参考代码 → 一步步的讲解。先自己读题想一遍,再看代码。
例题 ① 读一个数,再读一整行
第一行一个整数 n。第二行一句话(可能带空格)。输出这句话和它的长度。
★ 这一题就是陷阱 ① 的现场:读完 n 之后能不能顺利读到那句话。
n。第二行一句话。输入
3 hello world
输出
hello world 长度:11
n 之后补 cin.ignore();,getline 才能拿到 hello world。// STL 专题 · C++ 上路 例题 —— 读一个数,再读一整行//// ★ cin >> n 之后直接 getline 会读到空行:n 后面的换行还留着。// 中间必须 cin.ignore() 把它扔掉。
#include <bits/stdc++.h>using namespace std;
int main() { ios::sync_with_stdio(false); cin.tie(nullptr);
int n; cin >> n; cin.ignore(); // ★ 扔掉残留的换行
string s; getline(cin, s);
cout << s << '\n'; cout << "长度:" << (int)s.size() << '\n'; // size() 无符号,打印时转 int 更直观 return 0;}点「运行 ▶」看结果
- 读数:
int n; cin >> n; - 扔掉残留的换行:
cin.ignore();—— 没有它,下一步读到的是空行。 - 读一行:
string s; getline(cin, s); - 输出:
cout << s << "\n" << s.size() << "\n";—— 长度直接是无符号的,要和 int 一起算再转(int)。
★★★ cin >> 之后要 getline,中间必须 cin.ignore();。
用到的写法:#include <bits/stdc++.h> using namespace std; cin >> n; cin.ignore(); getline(cin, s);
例题 ② 用 auto 遍历一个数组
读 n 个整数,用「一个名字挨个走一遍」的写法输出它们,每个前面标个序号。
n。第二行 n 个整数。输入
4 10 20 30 40
输出
0: 10 1: 20 2: 30 3: 40
auto 推出来的类型是 int&(因为加了 &,是引用,不用拷)。// STL 专题 · C++ 上路 例题 —— 用 auto 遍历一个数组//// ★ auto 是「类型编译器自己推」:auto x : a 里 auto 就是 int。// 改动原数组就写 auto &x : a。
#include <bits/stdc++.h>using namespace std;
int main() { ios::sync_with_stdio(false); cin.tie(nullptr);
int n; cin >> n; vector<int> a(n); for (int &x : a) cin >> x;
int i = 0; for (auto x : a) cout << i++ << ": " << x << '\n'; return 0;}点「运行 ▶」看结果
- 读进 vector:
vector<int> a(n); for (int &x : a) cin >> x; - auto 遍历:
int i = 0; for (auto x : a) cout << i++ << ": " << x << "\n"; - ★
auto x : a里auto就是int;想改动原数组就写auto &x : a。
★★ auto 只是把类型名省掉了 —— 推出来是什么,和手写那个类型等价。
练习(3 道)
只给题面、样例和一句提示,答案是折叠着的 —— 先自己写一版。
练习 ① 一整行里有几个词
读入一整行(可能有多个空格),输出其中有多少个词。
输入
the quick brown fox
输出
4
★ 用 stringstream 把整行当输入流,一个个 >> 读词:stringstream ss(s); string w; while (ss >> w) cnt++;。也可以数空格,但连续空格会数错 —— 前者不依赖分隔细节。
★★ 「一行里的词」先 getline 整行,再用 stringstream 一词词读。
练习 ② 字符串的长度和最后一个字符
读入一个字符串,输出它的长度、第一个字符和最后一个字符。
输入
hello
输出
5 h o
★ 长度是 (int)s.size();第一个字符 s[0],最后一个 s[(int)s.size() - 1]。⚠ s 为空时 s[0] 就越界了 —— 题目保证非空,真实场景先判。
★★ 下标从 0 到 size()-1;size() 是无符号的,下标运算前转 int。
练习 ③ 把读写换成文件:freopen 的用法
读 n 个整数,输出它们的和。这份代码用 freopen 之后,本地调试时输入就从 in.txt 读、答案写进 out.txt,读写代码一行不用改。
★ 交评测前那两行 freopen 必须删掉或注释掉(陷阱 ③)。
n。第二行 n 个整数。输入
4 3 1 4 1
输出
9
★ 在 main 最开头加 freopen("in.txt", "r", stdin); 和 freopen("out.txt", "w", stdout); —— 之后 cin 自动从 in.txt 读、cout 自动写进 out.txt。⚠ 文件路径要对:相对路径是「程序运行时的当前目录」,不是源文件的目录。
★★ freopen 改的是「数据从哪来、往哪去」,代码本身一个字都不用动。
用到的写法:freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); cin >> x; cout << s;
这是第一块 · 回 STL 专题目录 · 下一块:前置知识:比较器和「把函数当参数传」 →
⚠ 本页说的是 STL 怎么用。算法本身(Dijkstra、单调栈、状压……)在53 章正课里,而每一章末尾都会告诉你它用到了哪些 STL。