c++笔记

c++笔记
lch1 | # ASCII码表 |
开平方
sqrt(数字)
需包含数学库:#include <cmath>
参考链接:C++ cmath库
格式化输出
在C语言中,使用 printf函数可以格式化输出浮点数,保留指定的小数位数。如果要保留两位小数,可以使用 %.2f格式说明符。
1 |
|
注意事项
printf函数中的%.2f表示输出的浮点数将保留两位小数。- 如果小数部分第三位数字大于或等于5,则会进行四舍五入。
示例代码
1 |
|
一维数组
1 | int main() |
快速排序
1 |
|
二维数组
1 | int a[2][3] = {0}; // 对全部元素初始化为0 |
输出
1 |
|
字符数组
在初始化时可以直接将整个字符串初始化给字符数组。但是不能用 =赋值语句字符串赋值给字符数组。(声明时 =为初始化,其他时候为赋值)
1 |
|
字符数组和字符串的主要区别在于是否使用了字符串结束标志 \0。字符数组中的元素可以是任意字符,并不要求最后一个元素是 \0。但是,当字符数组被用作字符串时,就必须以 \0结尾。
字符数组输入
1 |
|
cin >> str[i];// 输入单个字符时会忽略空格和换行符scanf("%c", &str[i]);// 输入单个字符时不会忽略空格和换行符str[i] = getchar();// 输入单个字符时不会忽略空格和换行符
字符数组 cin 和 cout
第一种
1 |
|
第二种
1 |
|
对两个程序都输入 I love c++
cin >> str;// 输入字符串时读取到空格或换行符为止cin.getline(str, 100);// 输入100个字符或遇到换行符为止cin.getline(str, 100, 'a');// 输入100个字符或遇到指定字符(‘a’)为止(换行符不会停止输入)
因此左侧程序输出 I,右侧程序输出 I love c++。
字符串相关函数
(此处内容缺失)
字符串
1 |
|
函数定义
1 | 返回类型 函数名(参数表){ |
cin 和 cout 优化
1 | // cin和cout优化 |
快读
1 |
|
1 | # 快写 |
原理
这是一个用于输出整数的递归函数,其核心思想是通过不断分解数字,从高位到低位依次输出字符。下面分步骤解析其原理:
处理负数
如果输入x小于 0,先输出一个负号'-',然后将x取反转为正数。这样后续只需处理正数部分。递归分离高位数字
如果x大于 9(即至少两位数),则递归调用write(x / 10)。x / 10会去掉当前数字的最低位(例如123 / 10 = 12),递归继续处理剩下的高位。- 递归会一直深入到最高位(当数字变成个位数时停止递归)。
输出当前位
递归返回后,执行putchar(x % 10 + '0')。x % 10取出当前数字的最低位(例如123 % 10 = 3)。- 加上字符
'0'将其转换为对应的数字字符(如3 + '0'得到'3')。 - 由于递归是“先递归、后输出”,所以输出的顺序正好是从最高位到最低位。
举例说明:以 write(123) 为例
- 第一次调用:
x=123,x>9,递归调用write(12)- 第二次调用:
x=12,x>9,递归调用write(1)- 第三次调用:
x=1,x≤9,不继续递归,直接执行putchar(1%10+'0')→ 输出'1',返回
- 第三次调用:
- 第二次调用继续:执行
putchar(12%10+'0')→ 输出'2',返回
- 第二次调用:
- 第一次调用继续:执行
putchar(123%10+'0')→ 输出'3',结束
最终输出"123"。
如果输入负数如 write(-456):
- 先输出
'-',x变为456,然后按正数逻辑输出"456",最终得到"-456"。
该函数巧妙地利用递归实现了数字的逐位输出,避免了使用循环或字符串转换,且能正确处理负号。
inline 关键字
inline 是 C 和 C++ 中的一个关键字,它的核心含义是建议编译器将函数体在调用点“展开”,以避免函数调用的开销。
然而,在现代编译器和语言标准中,inline 的实际作用已经从“优化建议”演变为解决“单一定义规则”的链接问题。
1. 历史作用:优化建议
在早期的 C/C++ 中,函数调用是有开销的(压栈、跳转、返回等)。使用 inline 相当于告诉编译器:
“这个函数很小,被调用的很频繁,请直接把代码复制到调用处,别走 call 指令。”
但这只是建议,编译器有权忽略它(例如递归函数或函数体过大时,编译器会无视 inline,依然按普通函数处理)。
2. 现代核心作用:解决链接冲突
这是目前 inline 最重要的意义。C++ 遵循 ODR。
- 普通函数:如果在头文件中定义,被多个
.cpp文件包含,链接时会出现“重复定义”错误。 inline函数:允许在头文件中定义。编译器会将该函数标记为“弱符号”。链接器在合并目标文件时,如果发现多个相同的inline函数定义,会保留一份,丢弃其他的,从而避免报错。
因此,inline 的主要用途现在变成了:
允许将函数的定义放在头文件中,供多个源文件包含使用。
3. 典型使用场景
场景一:定义在类内部的成员函数
在 C++ 中,在类内部直接定义的成员函数,默认就是 inline 的。
1 | class MyClass { |
场景二:定义在头文件中的全局函数或静态成员
如果你需要在头文件中写一个通用函数,必须加上 inline,否则包含该头文件的多个 .cpp 文件就会链接失败。
1 | // utils.h |
场景三:模板函数
注意: C++ 中的模板函数(如 template <typename T> void foo() {})默认具有类似 inline 的链接属性。因此,模板通常不需要显式加 inline(除非你希望强制展开或特化版本)。
4. inline 与编译器优化(现代视角)
在今天的编译器(GCC、Clang、MSVC)开启优化(如 -O2)时:
- 编译器会忽略你的
inline建议。它有一套复杂的成本模型,决定哪些函数内联,哪些不内联。 - 即使你没写
inline,编译器也可能自动内联(如非常简单的函数)。
5. 常见误区
| 误解 | 真相 |
|---|---|
inline 能强制内联 |
不能。它只是建议。强制内联通常使用编译器扩展,如 __attribute__((always_inline)) (GCC) 或 __forceinline (MSVC)。 |
inline 能让代码更快 |
不一定。内联会增加二进制文件大小。如果滥用,会导致指令缓存命中率下降,反而变慢。 |
inline 函数不能递归 |
可以递归,但编译器通常不会内联递归函数(除非在编译时能展开的尾递归)。 |
inline 影响调试 |
是的。开启内联后,调试时可能无法在函数内部设置断点,或变量看不全。Debug 模式通常禁用内联。 |
6. C++17 的 inline 变量
C++17 扩展了 inline 的能力,允许定义内联变量。这对于头文件中定义全局变量非常有用,解决了静态成员变量需要在 .cpp 文件单独定义的繁琐问题。
传统方式:
1 | // .h |
C++17 方式:
1 | class MyClass { |
总结
当你使用 inline 时,可以这样理解:
- 在链接层面:告诉编译器“这个函数可能在多个编译单元中出现,请允许它们在头文件中定义,并在链接时去重”。
- 在优化层面:把决定权交给编译器,它通常会根据优化级别和函数大小来决定是否真正展开。
超级快读
1 | const int maxn = 1e6; |
1 |



