27.总结
27.1 知识点

学习的主要内容

总结讲什么

为什么要讲练结合

如何培养良好的学习习惯

如何快速的提升编程能力

27.2 核心要点速览
输入输出操作
| API/语法 | 作用 | 示例 | 注意 |
|---|---|---|---|
int main() |
程序入口 | int main() {} |
return 0; 多数实现可省略 |
#include <...> / #include "..." |
引入头文件 | #include <iostream> |
<> 多为系统库,"" 多为当前/自定义 |
std:: / using namespace std; |
命名空间 | std::cout 或 cout |
cout、cin、string 等在 std 中 |
cout << |
输出 | cout << "Hi" << endl; |
可链式输出 |
cin >> |
输入 | cin >> x; |
按空白分隔;一次读到空白或回车为止 |
endl / \n |
换行 | cout << '\n'; |
endl 换行并刷新缓冲区;\n 仅换行 |
注释
单行 //,多行 /* ... */。
代码分组
用 #pragma region / #pragma endregion 折叠代码块,便于阅读长文件。
#pragma region 分组名
int a = 1;
#pragma endregion
注意:仅编辑器辅助,不改变编译后的程序逻辑。
基础变量类型
| 分类 | 类型 | 要点 | 示例 |
|---|---|---|---|
| 有符号整型 | short / int / long / long long |
long 在 Windows 常与 int 同宽,部分平台可能为 8 字节 |
long l = 10L; |
| 无符号整型 | unsigned 系列 |
仅非负;与有符号混用易踩坑 | unsigned u = 1U; |
| 浮点 | float / double / long double |
字面小数默认 double;float 需 f/F |
float f = 1.5f; |
| 特殊 | bool / char / string |
char 常配合 ASCII;string 表示字符串 |
string s = "hi"; |
选择建议:
- 整数常用
int,范围不够再考虑long long等。 - 小数常用
double,需要float时加后缀f。 - 判断用
bool;单字符用char,文本用string。
声明:类型 名 = 初始值;,先声明后使用,推荐声明时初始化。
数值后缀:L→long/long double,LL→long long,U→unsigned,UL→unsigned long,ULL→unsigned long long,F→float。
获取类型内存大小
sizeof(类型或变量) 得到占用字节数;1 byte = 8 bit。
cout << sizeof(int) << endl;
cout << sizeof(string) << endl;
注意:sizeof(string) 是对象本体大小(常含指针/长度/容量等元数据),不是字符个数;某环境下可能约 40 byte。long 等与平台相关,以本机 sizeof 为准。
进制与编码
| 项 | 要点 | 示例 |
|---|---|---|
| 本质 | 数据在内存中以二进制表示与处理 | — |
| 字面量 | 八进制 0…,十六进制 0x…,二进制(C++11)0b/0B |
077→63,0x3C7→967 |
| 转换 | 八/十六进制 ↔ 十进制:按位权展开,或除基取余倒序 | — |
| 十六进制用途 | 内存地址、颜色 RGB、部分文件/网络、汇编中常见 | — |
原码、反码、补码
| 概念 | 要点 |
|---|---|
| 原码 | 符号位 + 数值位;存在 +0/-0 问题,整数存储不用原码。 |
| 反码 | 负数:符号位不变,数值位取反(求补码的中间形式)。 |
| 补码 | 负数:反码 + 1;正数补码同原码。统一加减、只有一个 0;short 中最高位为 1 的特殊模式表示 -32768。 |
变量命名规则
必须遵守:
- 同作用域不重名;不以数字开头;不用关键字;除
_外不用特殊符号。
建议规范:驼峰、帕斯卡、下划线、匈牙利(如 n/str 前缀)、用途前缀(g_/s_/m_)、前缀下划线。
| 命名法 | 格式 | 用途 | 示例 |
|---|---|---|---|
| 驼峰 | 首词小写,其后词首字母大写 | 变量、函数 | userName |
| 帕斯卡 | 每个词首字母大写 | 类型名等 | MyClass |
| 下划线 | 词间 _ |
变量、函数 | my_name |
注意:C++ 区分大小写;标识符建议有意义;不推荐用汉字命名。
常量
值不可变,用 const 声明,必须在声明时初始化。
const double PI = 3.1415926;
// PI = 3.14; // 错误,不能修改
什么时候用:数学常数、固定配置、不变业务常量等。
转义字符
以 \ 开头表示特殊含义。
| 转义符 | 效果 | 示例 |
|---|---|---|
\" |
双引号 | "say \"hi\"" |
\n |
换行 | "a\nb" |
\\ |
反斜杠 | "C:\\data" |
\0 |
空字符 | 输出可能为空 |
\t |
制表符 | "a\tb" |
\b |
退格 | 了解即可 |
\a |
警报音 | 了解即可 |
取消转义:原始字符串 R"(内容)",内容中 \ 不按转义处理。
运算符
算术运算符
| 运算符 | 作用 | 示例 | 结果 |
|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
- |
减法 | 5 - 3 |
2 |
* |
乘法 | 5 * 3 |
15 |
/ |
除法 | 5 / 2 |
2(整数截断) |
% |
取余 | 5 % 2 |
1 |
复合运算符:+=、-=、*=、/=、%=(只做一种运算,不能混写如 */=)。
自增自减:++i 先加后用,i++ 先用后加。
注意:整数相除只保留整数部分;要得到小数需 3 / 2.0 这类写法。混合运算时表达式向较高精度提升,接收结果的变量类型要能容纳精度。
关系运算符
> < >= <= == !=,结果为 bool(打印常为 0/1)。
注意:不能写 1 < a < 4 表示区间,应写成 a > 1 && a < 4。不同类型会提升后比较;有符号与无符号混用易出反直觉结果。
逻辑运算符
| 运算符 | 作用 | 规则 | 短路 |
|---|---|---|---|
&& |
逻辑与 | 全真才真 | 左假则右不执行 |
|| |
逻辑或 | 一真即真 | 左真则右不执行 |
! |
逻辑非 | 取反 | 无 |
可与非 0 数值混用(非 0 视为真)。
位运算符
对整数按二进制逐位运算:&、|、^、~、<<、>>。
注意:cout << 中的 << 是输出,不是左移;与位移、逻辑运算混用时拿不准就加括号(如 cout << (false || true))。
三目运算符
条件 ? 真值 : 假值;两分支类型需能统一。未选中的分支不会执行。两侧若为变量,整体可作左值赋值。
字符串拼接
| 方法 | 语法 | 说明 |
|---|---|---|
+ / += |
str + "a"、str += 'c' |
可与 char 拼接 |
append |
str.append("x") |
方法形式 |
注意:不能与数值直接拼接,需 to_string 等先转字符串。避免 str += c1 + c2:两 char 可能先按整数相加再拼接,结果易错。
类型转换
隐式转换(自动)
赋值或运算时编译器自动转换:低到高相对安全,高到低易截断/溢出。string 与数值无可靠隐式互转。算术向更大类型提升;若先写 3/2 再赋给浮点,可能仍是整数除法结果。
显式转换(强制)
| 方法 | 语法 | 说明 | 注意 |
|---|---|---|---|
| 括号强转 | (int)4.9 |
强制类型 | 丢小数、可能溢出 |
to_string |
to_string(123) |
数值→字符串 | 需 #include <string>;char 常得到 ASCII 码数字串 |
stoi 等 |
stoi(s)、stol、stoll、stoul、stoull |
字符串→整数类型 | 非法或越界会抛异常 |
异常捕获
避免运行时错误导致程序直接崩溃;常用在 stoi 等可能失败的调用外。
try {
int n = stoi(input);
} catch (const std::exception&) {
cout << "输入不是合法数字" << endl;
}
try/catch 结构本身末尾不写分号;块内语句照常写分号。
流程控制
条件分支
| 语句 | 语法 | 特点 |
|---|---|---|
if |
if (条件) { } |
单分支 |
if-else |
if () { } else { } |
二选一 |
if-else if-else |
多段 else if |
多分支 |
switch |
switch (变量) { case 常量: break; } |
与常量整型比较;字符串、浮点不可用;default 可选;可多 case 贯穿共用一段 |
if 仅一行语句时可省略 {}(不推荐复杂逻辑这样写)。switch 里 case 无独立作用域,要在某分支内声明变量请用 { } 包起来。
循环
| 语句 | 语法 | 执行顺序 | 特点 |
|---|---|---|---|
while |
while (条件) { } |
先判断→再执行 | 可能一次都不执行 |
do-while |
do { } while (条件); |
先执行→再判断 | 至少执行一次;末尾分号必写 |
for |
for (初始化; 条件; 增量) { } |
初始化→判断→体→增量 | 适合次数明确;可 for (;;) 等特殊写法 |
循环控制:
break:跳出当前循环,或结束switch当前分支。continue:跳过本轮剩余,回到循环条件。switch内的break只跳出switch,不跳出外层循环。
goto(了解)
跳转到标签;不推荐日常使用。不能跳过变量定义跳到其后使用;标签勿用关键字。
#include <iostream>
using namespace std;
int main() {
int i = 0;
start:
if (i >= 3) {
goto end; // 条件满足时跳到 end 标签
}
cout << "i = " << i << endl;
++i;
goto start; // 回到 start 标签
end:
cout << "结束" << endl;
return 0;
}
27.3 面试题精选
基础题
1. C++ 基础类型和 sizeof
题目
说说 C++ 里常见基础类型的字节数和差异,long 为什么在不同机器上可能不一样?
深入解析
这题考查你对类型系统和平台差异的理解。
本系列给出的核心是:short 通常 2 字节,int 通常 4 字节,long 可能是 4/8 字节,long long 通常 8 字节;float/double 分别对应不同精度。
面试里不要死背所有范围,重点说清楚两点:
- 字节数和范围要靠
sizeof与平台验证。 long的实现与编译器/平台 ABI 相关,不是语言强制固定值。
答题示例
C++ 只规定类型的相对大小关系,不保证各平台字节数完全一致。常见情况是
int多为 4 字节、long long多为 8 字节,而long在 32/64 位环境下可能是 4 或 8 字节。实际以本机
sizeof为准;跨平台代码宜使用固定宽度类型(如<cstdint>)或明确文档化的布局,避免对long等类型做隐式假设。
参考文章
- 5.变量
- 6.变量的本质
2. endl 和 \n 的区别
题目
cout << endl 和 cout << "\n" 都能换行,它们有什么区别?什么时候选哪个?
深入解析
两者都会换行,但 endl 还会刷新输出缓冲区,\n 只插入换行符。
频繁输出时,endl 可能带来额外开销;普通日志或刷题场景一般优先 \n,只有需要立刻刷新输出时再用 endl。
答题示例
\n只插入换行;endl在换行之外还会刷新输出缓冲区。大量输出、性能敏感时通常用
\n;需要立刻把缓冲内容刷到终端(交互提示、调试即时可见)时用endl。
参考文章
- 4.第一个应用程序
- 11.转义字符
3. 前置 ++i 和后置 i++
题目
前置和后置自增有什么语义区别?为什么很多代码风格建议在循环中优先前置?
深入解析
前置 ++i:先自增再参与表达式;后置 i++:先用旧值再自增。
在基础类型里差别通常不大,但语义上前置更直接;在自定义迭代器里后置可能涉及临时对象,代价更高。
答题示例
语义上:
++i先自增再把新值参与运算;i++先把旧值参与运算再自增。不需要用到自增前旧值时,更常见写法是
++i,语义更直;在自定义类型上后置自增往往多一次临时对象,代价更高。
参考文章
- 12.运算符-算术运算符
进阶题
1. 补码为什么能统一加减法
题目
为什么计算机最终选择补码存有符号整数?它相比原码/反码解决了什么问题?
深入解析
补码有两个关键价值:
- 消除了
+0和-0的二义性。 - 让减法可以转成加法,硬件实现更统一。
例如5 + (-5),在补码体系下直接按位加法即可得到 0(溢出位丢弃)。
答题示例
补码让有符号整数的加减可以用同一套加法电路完成,硬件实现统一。
相比原码,补码避免了
+0与-0两种零的歧义;负数用「反码加一」编码后,减法可转为与正数相同的加法处理。
参考文章
- 8.反码和补码
2. 隐式转换有哪些高频坑
题目
实际开发中隐式转换最容易踩哪些坑?如何规避?
深入解析
本系列重点坑位:
- 大范围到小范围转换导致截断或溢出。
- 有符号和无符号混用引发结果反直觉。
- 整数除法截断,例如
3 / 2 == 1。
规避方式:显式转换、统一类型、关键表达式写注释或拆中间变量。
答题示例
常见坑有三类:大范围到小范围的窄化(丢精度或溢出)、有符号与无符号混用、整数除法截断(如
3/2为1)。规避上:需要浮点结果时让参与运算的一方为浮点,例如
3 / 2.0;关键路径用显式转换、统一类型,边界处加注释或单测覆盖。
参考文章
- 18.类型转换-隐式转换
- 12.运算符-算术运算符
3. switch 和 if-else 怎么选
题目
同样是多分支判断,什么时候用 switch,什么时候用 if-else?
深入解析
switch 适合“单变量、离散常量”匹配,结构清晰,常见于菜单/状态机;if-else 更适合范围判断、复合条件表达式。switch 要注意 break 贯穿和 case 作用域,避免变量定义跨分支出问题。
答题示例
离散常量匹配(如状态码、菜单项)适合
switch,结构清晰;范围判断、复合布尔条件适合if-else。使用
switch时要注意break与 case 贯穿是否符合意图,以及在某个case内声明变量时用{ }限制作用域,避免跨分支引用问题。
参考文章
- 21.条件分支语句-if
- 22.条件分支语句-switch
深度题
1. 字符串转数字的异常处理策略
题目
stoi 这类接口转换失败会抛异常。业务里通常如何设计这类输入处理?
深入解析
核心不是“会写 try-catch”,而是要有完整兜底链路:
- 在转换前做基础校验(空串、非法字符)。
- 转换时用
try-catch捕获std::exception。 - 转换失败给用户可理解提示,不让程序崩溃。
- 保证失败分支有默认行为(重试、回退、继续交互)。
try {
int age = stoi(input);
cout << "年龄:" << age << endl;
} catch (const std::exception&) {
cout << "输入格式错误,请输入整数" << endl;
}
答题示例
典型做法是 前置校验 +
try-catch兜底:先去掉空串、明显非法字符等,再调用stoi;失败则捕获std::exception(或更具体类型),给出统一提示、默认值或重试,避免进程直接崩溃。这样非法输入被挡在业务逻辑外,后续流程只处理已验证的数据。
参考文章
- 19.类型转换-显式转换
- 20.异常捕获
2. 循环语句与控制关键字的工程化选择
题目
while、do-while、for、break、continue、goto 在工程代码里通常如何选用?为什么一般不推荐 goto?
深入解析
选择原则:
- 已知次数优先
for;未知次数且前置条件判断优先while;至少执行一次用do-while。 break用于提前结束,continue用于过滤当前轮。goto会破坏结构化流程,增加控制流复杂度,还可能踩“跳过变量定义”等编译限制。
工程代码更强调可读性和可维护性,优先结构化控制流。
答题示例
次数明确用
for;先判再执行用while;至少执行一轮再判条件用do-while。
break结束当前循环或跳出switch分支;continue跳过本轮剩余语句。goto会破坏结构化控制流、难以静态阅读,还可能违反“不能跳过变量初始化”等规则,故现代风格优先用循环与函数拆分替代。
参考文章
- 23.循环语句-while
- 24.循环语句-dowhile
- 25.循环语句-for
- 26.循环语句-goto
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com