27.C++入门语法知识总结

27.总结


27.1 知识点

学习的主要内容

总结讲什么

为什么要讲练结合

如何培养良好的学习习惯

如何快速的提升编程能力


27.2 核心要点速览

输入输出操作

API/语法 作用 示例 注意
int main() 程序入口 int main() {} return 0; 多数实现可省略
#include <...> / #include "..." 引入头文件 #include <iostream> <> 多为系统库,"" 多为当前/自定义
std:: / using namespace std; 命名空间 std::coutcout coutcinstring 等在 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 字面小数默认 doublefloatf/F float f = 1.5f;
特殊 bool / char / string char 常配合 ASCII;string 表示字符串 string s = "hi";

选择建议

  • 整数常用 int,范围不够再考虑 long long 等。
  • 小数常用 double,需要 float 时加后缀 f
  • 判断用 bool;单字符用 char,文本用 string

声明:类型 名 = 初始值;先声明后使用,推荐声明时初始化。

数值后缀Llong/long doubleLLlong longUunsignedULunsigned longULLunsigned long longFfloat

获取类型内存大小

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)stolstollstoulstoull 字符串→整数类型 非法或越界会抛异常

异常捕获

避免运行时错误导致程序直接崩溃;常用在 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 仅一行语句时可省略 {}(不推荐复杂逻辑这样写)。switchcase 无独立作用域,要在某分支内声明变量请用 { } 包起来。

循环

语句 语法 执行顺序 特点
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 << endlcout << "\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/21)。

规避上:需要浮点结果时让参与运算的一方为浮点,例如 3 / 2.0;关键路径用显式转换、统一类型,边界处加注释或单测覆盖。

参考文章
  • 18.类型转换-隐式转换
  • 12.运算符-算术运算符

3. switchif-else 怎么选

题目

同样是多分支判断,什么时候用 switch,什么时候用 if-else

深入解析

switch 适合“单变量、离散常量”匹配,结构清晰,常见于菜单/状态机;if-else 更适合范围判断、复合条件表达式。
switch 要注意 break 贯穿和 case 作用域,避免变量定义跨分支出问题。

答题示例

离散常量匹配(如状态码、菜单项)适合 switch,结构清晰;范围判断、复合布尔条件适合 if-else

使用 switch 时要注意 breakcase 贯穿是否符合意图,以及在某个 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. 循环语句与控制关键字的工程化选择

题目

whiledo-whileforbreakcontinuegoto 在工程代码里通常如何选用?为什么一般不推荐 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

×

喜欢就点赞,疼爱就打赏