
简介这是一份面向C初学者与在校学生的标准库函数速查资料聚焦于日常编程中最常用的函数调用方式与头文件归属帮助读者摆脱频繁搜索、记忆混乱的困扰适合课程学习、课后练习与笔试面试前的快速复习。资源为单个PDF文档压缩包约93KB篇幅紧凑便于打印或存于手机随时翻阅。内容按数学函数、字符串处理函数、其他常用函数以及键盘与文件输入输出四大板块组织逐一列出函数原型、功能说明与返回值含义例如绝对值、三角函数、指数对数、幂与平方根等数学运算memcpy、memset、strcpy、strcat、strcmp、strstr等字符串拷贝、连接、比较与搜索操作以及abort、exit终止程序、atof、atoi、atol字符串转数值、rand与srand随机数、system调用等实用接口同时补充cin、cout与文件流打开关闭等常见用法。目前已有984人学习下载适合作为案头工具表在编码时对照查阅函数签名与参数减少语法与语义误用带来的调试成本。1. 从 cin/cout 到 sortC 标准库函数到底该按什么顺序学很多人写了两年代码遇到「把 vector 排序后去重」第一反应还是双层循环而不是std::sort加std::unique。标准库函数不是学完语法再补的选修课它决定了你写出来的是「带类的 C」还是真正的 C。这个标题指向的东西本质是一张常用标准库函数的地图algorithm里的排序与查找、string里的子串与类型转换、iostream里的流 I/O 与格式化以及用现成函数替掉手写循环的落地写法。适合刚学完语法、能编译但写不快的人也适合写了几年业务、想把工具链补齐的人。下面按「用得上」的优先级排每个函数都给调用形式、参数含义以及出错时该看哪一行。2.algorithm里最常用的几个函数sort、lower_bound 与比较器写法2.1 sort 引入库与三种调用形式问「c sort 引入库」的人多数是被#include algorithm漏写报的sort was not declared in this scope卡过。sort、stable_sort、lower_bound、max_element全部声明在algorithmaccumulate、gcd、iota在numericgreaterint这种函数对象在functional。三个头文件经常一起出现记混了就会出现「明明写了 sort 却编译不过」。#include algorithm // sort / stable_sort / lower_bound / unique #include functional // greaterint / lessint #include vector #include iostream int main() { std::vectorint v{5, 2, 9, 1, 5, 6}; // 形式一默认升序元素需支持 operator std::sort(v.begin(), v.end()); // 形式二传入比较器改成降序 std::sort(v.begin(), v.end(), [](int a, int b) { return a b; }); // 形式三只排区间 [begin, begin3)用于 Top-K std::sort(v.begin(), v.begin() 3, std::greaterint()); for (int x : v) std::cout x ; return 0; }调用形式里的first、last是左闭右开区间sort(v.begin(), v.end())排全部元素sort(v.begin(), v.begin()k)只排前 k 个。比较器comp必须满足严格弱序返回true表示第一个参数应排在第二个之前。常见错误是写成return a b;相等元素互相「小于」某些实现会直接越界访问内存表现为随机崩溃而不是编译错误。函数关键参数稳定性平均复杂度典型用途sortfirst, last, comp不稳定O(N log N)通用排序stable_sortfirst, last, comp稳定O(N log²N)多关键字保序partial_sortfirst, middle, last不稳定O(N log K)Top-Knth_elementfirst, nth, last不稳定O(N)求第 K 大stable_sort只在「相等元素的原始顺序有意义」时才用比如先按分数排、再按班级排希望同班学生保持录入顺序。普通场景用sort就够硬上stable_sort白白吃内存。2.2 lower_bound 与 binary_search查找前必须先有序二分查找在 STL 里有两个入口std::binary_search只回答「在不在」返回boolstd::lower_bound返回第一个不小于目标值的迭代器upper_bound返回第一个大于目标值的迭代器。要拿下标、要统计出现次数、要找插入位置都得用lower_boundbinary_search拿不到位置信息。#include algorithm #include vector #include iostream int main() { std::vectorint v{1, 2, 4, 4, 4, 7, 9}; // 必须先有序 // 找第一个 4 的位置 auto lo std::lower_bound(v.begin(), v.end(), 4); // 找第一个 4 的位置 auto hi std::upper_bound(v.begin(), v.end(), 4); std::cout first 4 at (lo - v.begin()) \n; // 2 std::cout count of 4 (hi - lo) \n; // 3 std::cout found: std::binary_search(v.begin(), v.end(), 4) \n; return 0; }迭代器相减得到的是ptrdiff_t直接赋给int会有窄化警告输出或存下标时显式转一下。另一种常见误用是在无序容器或无序数组上调用结果不报错但结果随机——二分族函数不做有序性检查这一点和find不同。2.3 自定义比较器结构体、多关键字与回调函数排序结构体时C11 之后写 lambda 最省事也支持把比较逻辑抽成独立函数或函数对象。多关键字排序把主键、次键依次写进返回表达式注意每个键的方向要单独控制。#include algorithm #include vector #include string struct Student { std::string name; int score; int id; }; int main() { std::vectorStudent s{{Li, 90, 3}, {Wang, 90, 1}, {Zhao, 85, 2}}; std::sort(s.begin(), s.end(), [](const Student a, const Student b) { if (a.score ! b.score) return a.score b.score; // 分数降序 return a.id b.id; // 同分按 id 升序 }); return 0; }参数用const Student而不是值传递避免每次比较都拷贝字符串。比较器内部只做纯比较不要打印日志或修改全局变量sort调用比较器的次数是 O(N log N) 级别任何副作用都会被放大成难以复现的问题。2.4 顺手替代循环的几个一行函数std::max_element/min_element直接返回迭代器比手写遍历少四行std::count/count_if做条件统计std::accumulate的第三个参数是初值类型决定了结果类型写0会把long long求和截断成int这是很隐蔽的一类溢出。std::all_of/any_of在判断「是否全部满足」时比手写flag变量清晰得多。提示accumulate的初值写成0LL或0.0来固定累加类型尤其是求和范围超过 2^31 的时候。3.string与容器类函数字符串数组初始化与字符串转数组3.1 string 的构造、substr、find 与 replacestd::string是标准库里使用频率仅次于流对象的类型。substr(pos, len)的len省略时取到末尾find找不到时返回std::string::npos它是一个极大无符号值用int接会变成 -1判断时统一写if (s.find(t) ! std::string::npos)。replace(pos, len, str)的len是「被替换掉的原串长度」不是新串长度参数写反会得到意料之外的结果。#include string #include iostream int main() { std::string s hello world; std::cout s.substr(6) \n; // world std::cout s.substr(0, 5) \n; // hello size_t p s.find(world); if (p ! std::string::npos) { s.replace(p, 5, C); // 从 p 起删 5 个字符插入 C } std::cout s \n; // hello C return 0; }3.2 字符串数组初始化的几种写法与内存差异「c字符串数组初始化」的答案取决于你要的是「可修改的字符缓冲」还是「一组字符串」。前者用char[]后者用std::string[]或std::vectorstd::string两者的拷贝、比较、长度语义完全不同。写法类型长度获取可否修改越界风险char s[] abc;字符数组strlen(s)可无\0时读越界char s[10] {};定长缓冲strlen(s)可写入不能超 9 字节const char* a[] {x,y};指针数组各自strlen指针不可改指向字面量std::string a[] {x,y};对象数组.size()可无std::vectorstd::string v{x};动态容器.size()可无char s[] abc;会自动补一个\0长度是 4 而不是 3char s[3] abc;在 C 里是编译错误因为放不下结尾的\0。用std::string数组时sizeof(a)/sizeof(a[0])求元素个数依然成立但它算的是对象个数不是字符总数。3.3 字符串转数组与字符串转数字的三条路#include string #include vector #include sstream #include iostream int main() { // 路线一单个数字带异常与位置信息 std::string num 123abc; size_t pos 0; int a std::stoi(num, pos); // a 123, pos 3 std::cout a pos \n; // 路线二按分隔符切成一串子串 std::string csv 10,20,30; std::vectorstd::string parts; std::stringstream ss(csv); std::string item; while (std::getline(ss, item, ,)) parts.push_back(item); // 路线三转成字符数组交给 C 接口 std::string s hello; std::vectorchar buf(s.begin(), s.end()); buf.push_back(\0); // 需要 C 字符串时补结尾 std::cout buf.data() \n; return 0; }stoi/stol/stod在 C11 之后可用参数不对会抛std::invalid_argument或std::out_of_range用try/catch包住比atoi安全——atoi遇到非法输入返回 0无法区分「输入是 0」和「输入是垃圾」。第二个参数pos是出参回传解析停止的位置配合它可以做「解析剩余部分」。3.4 vector 的 size 与 capacity 不要混用size()是当前元素个数capacity()是不重新分配内存时能容纳的元素上限。reserve(n)改的是 capacityresize(n)改的是 size 并默认构造新元素。循环里频繁push_back触发扩容会反复搬移元素已知规模时先reserve一次是常见优化。clear()只把 size 置 0capacity 不变想真正释放用shrink_to_fit()或与空 vector 交换。注意v[i]不做越界检查v.at(i)越界会抛std::out_of_range。调试期用at压测后再换回[]。4.iostream流 I/O同步关闭、整行读取与格式化输出4.1 关闭同步与 tie 绑定提升输入速度默认情况下cin/cout与 C 的stdio保持同步每次读写都要走一层额外协调。数据量大时执行std::ios::sync_with_stdio(false);断开同步再执行std::cin.tie(nullptr);解除cin与cout的绑定能明显提速。两行放在main开头且此后不能混用printf与cout否则输出顺序会乱。#include iostream int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); long long sum 0, x; while (std::cin x) sum x; std::cout sum \n; return 0; }while (std::cin x)依赖流对象到bool的转换读到 EOF 或类型不匹配时流进入失败状态循环退出。如果中途读入非法字符需要std::cin.clear()清状态再std::cin.ignore(...)丢弃残留否则后续读取会立刻再次失败形成死循环。4.2 getline 与 cin 混用时的换行残留cin x读到数字就停把换行符留在缓冲区紧接着getline(cin, line)会读到一个空串。这是「c流i/o」里出现频率最高的坑。#include iostream #include string int main() { int n; std::cin n; // 输入 3 之后回车仍在缓冲区 std::cin.ignore(1, \n); // 丢掉那个换行 for (int i 0; i n; i) { std::string line; std::getline(std::cin, line); // 现在能取到完整一行 std::cout i : line \n; } return 0; }ignore(n, delim)最多丢弃 n 个字符遇到delim提前结束。要更稳妥可以写std::cin.ignore(std::numeric_limitsstd::streamsize::max(), \n);需要包含limits。getline的第三个参数是分隔符默认\n换成,就能直接做 CSV 行内切分。4.3 setprecision、fixed 与 setw 的格式化浮点输出默认保留 6 位有效数字3.14159265会变成3.14159看着像精度丢了。std::fixed切到定点表示std::setprecision(n)在fixed下表示小数点后 n 位。#include iostream #include iomanip // fixed / setprecision / setw / setfill int main() { double pi 3.14159265358979; std::cout pi \n; // 3.14159 std::cout std::fixed std::setprecision(4) pi \n; // 3.1416 std::cout std::setw(8) std::setfill(0) 42 \n; // 00000042 std::cout std::defaultfloat std::setprecision(6); // 恢复默认 return 0; }setw只作用于紧接着的下一个输出项setprecision、fixed、setfill是持续生效的流状态改完记得恢复。做表格对齐用setw做金额用fixedsetprecision(2)做科学计算切到std::scientific。4.4 stringstream 做解析与拼接std::stringstream把「字符串」和「流」接在一起能复用、和getline的全部能力。解析一行name 25 88.5这种混合格式尤其方便拼接多个不同类型的值也不用反复to_string。#include sstream #include string #include iostream int main() { std::string line Tom 25 88.5; std::stringstream ss(line); std::string name; int age; double score; if (ss name age score) { std::cout name age score \n; } std::ostringstream out; out name : age; std::cout out.str() \n; // Tom:25 return 0; }判断ss ...的返回值能识别格式不符解析完想重复使用同一个流对象需要调ss.clear()清状态、ss.str()清内容两步缺一不可。提示频繁创建stringstream对象有构造开销循环里做大批量解析时把流对象提到循环外用clear()和str()复位。5. 用标准库函数替掉手写循环二分、快速幂与质数判断的落地5.1 二分查找lower_bound 与手写二分的边界对照手写二分卡在while (l r)还是while (l r)、mid要不要加一是「c 二分查找」最常见的讨论。有序数组上求「第一个满足条件的位置」直接用lower_bound加比较器更省事也少一类死循环风险。#include algorithm #include vector // 求最小的 x 使 x*x target用 lower_bound 表达 int first_ge_square(int target) { std::vectorint v; for (int i 1; i 100000; i) v.push_back(i); auto it std::lower_bound(v.begin(), v.end(), target, [](int x, int t) { return 1LL * x * x t; }); return (it v.end()) ? -1 : *it; }比较器写成「当前元素是否仍小于目标」lower_bound就会停在第一个不满足该条件的位置等价于手写二分的右边界。注意比较器里用1LL * x * x防止int溢出这是二分题里另一类高频错误。5.2 快速幂与 std::pow 的取舍std::pow走浮点pow(2, 60)由于double只有 53 位有效位结果会丢精度取模场景下更不能用它。整数快速幂必须手写配合long long和取模。场景选择原因浮点开方、连续幂std::pow/std::sqrt硬件指令快精度足够整数大指数手写快速幂避免浮点精度丢失带模幂手写快速幂 取模pow无法取模long long qpow(long long a, long long e, long long mod) { long long r 1 % mod; a % mod; while (e) { if (e 1) r r * a % mod; // 指数当前位为 1累乘 a a * a % mod; // 底数平方 e 1; // 指数右移一位 } return r; }5.3 质数判断的优化写法试除到sqrt(n)是基础版本「判断质数c优化」的下一步是只试除 6 的倍数两侧。大于 3 的质数一定形如6k±1每轮循环跳 6比较次数降到约三分之一。#include cmath bool is_prime(long long n) { if (n 2) return false; if (n % 2 0) return n 2; if (n % 3 0) return n 3; for (long long i 5; i n / i; i 6) { if (n % i 0 || n % (i 2) 0) return false; } return true; }循环条件写成i n / i而不是i * i n避免i * i在接近long long上限时溢出。这个版本判定单个int范围质数足够快要判一批数就换埃氏筛或线性筛。5.4 编译验证与报错定位写完这些函数用g -stdc17 -Wall -Wextra -O2 main.cpp -o main编一遍-Wall -Wextra能抓住未使用变量、有符号无符号比较、窄化转换这类问题-fsanitizeaddress,undefined能把越界访问和 UB 直接定位到行号比看崩溃现场快很多。在 VS Code 里做「vscode配置c/c环境」时c_cpp_properties.json的includePath决定补全和跳转tasks.json决定实际编译参数两处不同步就会出现「编辑器标红但编译通过」。遇到undefined reference优先查链接顺序和是否漏了-l参数遇到xxx was not declared先查对应头文件这是定位标准库问题最快的两条路径。本文还有配套的精品资源点击获取