C/C++ 入门:基础语法
学完 HelloWorld 之后,下一步把变量、类型、运算符、输入输出、分支和循环这条主线连起来。
📚 基本概念速读
| 名称 | 定义 | 省流 |
|---|---|---|
| 变量 | 有名字、可读写的一块数据 | 会变的值 |
| 常量 | 初始化后不应该再修改的值 | 固定的值 |
| 类型 | 规定数据怎么存、能做什么操作 | 数据的形状 |
| 表达式 | 由变量、常量、运算符组成,能算出一个值 | 一段计算 |
| 语句 | 程序执行的基本单位,通常以分号结尾 | 一步动作 |
| 作用域 | 名字能被访问的代码范围 | 名字的有效范围 |
| 控制流 | 程序语句的执行顺序 | 程序怎么走 |
🧩 基础语法总览
C++ 基础语法可以按“数据从哪里来、怎么计算、程序怎么走”来理解。
flowchart LR
A[变量与常量] --> B[基本类型]
B --> C[运算符]
C --> D[输入输出]
D --> E[分支结构]
E --> F[循环结构]
最小心智模型:
1 |
|
这里已经同时出现了变量、类型、初始化、关系运算、分支、输出和返回码。
🧱 变量与常量
变量定义
变量定义的一般形式:
1 | 类型 变量名 = 初始值; |
示例:
1 | int age = 18; |
int age = 18; 的意思是:创建一个名为 age
的整型变量,并把初始值设为 18。
初始化
初始化就是变量创建时给它一个确定的值。初学阶段建议:变量定义时尽量立刻初始化。
1 | int a = 10; // 推荐:有明确初始值 |
int a = 10; 和 int b{};
都是在初始化,但含义不完全一样。
| 写法 | 名称 | 含义 | 结果 |
|---|---|---|---|
int a = 10; |
复制初始化 | 用右边的 10 初始化 a |
a 的值是 10 |
int b{}; |
列表初始化/值初始化 | 没写具体值,用该类型的默认零值初始化 | b 的值是 0 |
int c; |
默认初始化 | 对局部基础类型来说,不会自动清零 | c 的值不确定 |
int a = 10; 适合你已经知道变量应该是什么值的情况:
1 | int score = 90; |
int b{};
适合你暂时还没有具体值,但希望它处于一个安全的初始状态:
1 | int sum{}; // 0 |
这种 {}
写法还有一个好处:它能阻止一些可能丢失信息的窄化转换。
1 | int x = 3.14; // 允许,但 x 会变成 3 |
所以初学阶段可以先记住:
| 场景 | 推荐写法 |
|---|---|
| 有明确初始值 | int a = 10; |
| 只是想先清零 | int b{}; |
| 局部基础类型 | 不要写 int c; 后直接使用 |
未初始化局部变量是 C/C++ 初学里非常常见的坑。
作用域
作用域决定一个名字在哪里可见。
1 |
|
花括号 {} 会形成一个新的块作用域。
const
const 表示这个变量初始化后不应该再被修改。
1 | const double PI = 3.1415926; |
如果后面写:
1 | // PI = 3.14; // 错误:const 变量不能被重新赋值 |
编译器会报错。初学阶段可以把 const
理解成“给不会变的值加一层保护”。
🔢 基本类型
整型
整型用来表示整数。
1 | int count = 10; |
10000000000LL 末尾的 LL
是整数后缀,表示这个整数字面量的类型是
long long。如果不写后缀,编译器会根据数值大小和规则推导类型;写上
LL 可以明确告诉编译器“这是一个长整型整数”。
常用选择:
| 类型 | 说明 | 常见用途 |
|---|---|---|
int |
常用整数类型 | 普通计数、下标、分数 |
long long |
更大范围整数 | 大数计数、算法题 |
unsigned int |
非负整数 | 位运算、底层接口较常见 |
注意:
unsigned不是“更大的 int”这么简单,它不表示负数,混用有时会产生反直觉结果。
浮点型
浮点型用来表示小数。
1 | float x = 1.5f; |
日常优先用 double。float
占用空间更小,但精度更低,常见于图形、深度学习、嵌入式等场景。
字面量后缀
代码里的 10、1.5、'A'
这种直接写出来的值叫
字面量。有些字面量可以加后缀,用来明确它的类型。
常见整数后缀:
| 后缀 | 含义 | 示例 |
|---|---|---|
L |
long |
100L |
LL |
long long |
10000000000LL |
U |
unsigned |
10U |
ULL |
unsigned long long |
100ULL |
常见浮点后缀:
| 后缀 | 含义 | 示例 |
|---|---|---|
f 或 F |
float |
1.5f |
| 无后缀 | double |
1.5 |
l 或 L |
long double |
1.5L |
所以:
1 | float a = 1.5f; // 1.5f 是 float |
初学阶段不用背全,只要记住两个常见规则:
| 写法 | 什么时候用 |
|---|---|
LL |
整数很大,或者明确要 long long |
f |
明确要 float,避免默认按 double 处理 |
字符
char
表示单个字符,字符字面量使用单引号。
1 | char ch = 'A'; |
注意区分:
1 | char a = 'A'; // 字符 |
布尔
bool 只有两个值:true 和
false。
1 | bool isReady = true; |
它常用于条件判断:
1 | if (isReady) { |
类型转换
类型转换就是把一种类型的值变成另一种类型的值。入门阶段先掌握三件事:隐式转换、显式转换、窄化转换。
隐式转换
隐式转换是编译器自动帮你转。
1 | int a = 10; |
int 转成 double 通常安全,因为整数
10 可以自然表示成小数 10.0。
常见隐式转换:
| 例子 | 含义 |
|---|---|
int -> double |
整数转小数 |
char -> int |
字符按编码值转整数 |
bool -> int |
false 转 0,true 转
1 |
显式转换
显式转换是你主动告诉编译器“我知道这里要转类型”。
1 | double x = 3.8; |
static_cast<int>(x) 会把 double 转成
int。小数部分会被直接截掉,不是四舍五入。
1 | double x = 3.8; |
初学阶段优先用
static_cast<目标类型>(值),不要急着用 C
风格强转:
1 | int a = static_cast<int>(3.8); // 推荐:意图更明确 |
窄化转换
窄化转换指“目标类型装不下原来的信息”,比如小数转整数、大范围整数转小范围整数。
1 | int a = 3.14; // a 变成 3,小数部分丢失 |
这和前面讲的 int b{}; 属于同一类 {}
初始化规则:列表初始化更严格,能帮你挡住一些容易出错的转换。
整数除法
整数除法是类型转换里最常见的坑:
1 | cout << 5 / 2 << endl; // 输出 2 |
如果两个操作数都是整数,/ 会先执行整数除法,结果已经是
2。就算你把结果赋给 double,也不会变回
2.5。
1 | double a = 5 / 2; // 2.0 |
判断规则很简单:
| 表达式 | 结果 |
|---|---|
5 / 2 |
整数除法,结果 2 |
5.0 / 2 |
浮点除法,结果 2.5 |
static_cast<double>(5) / 2 |
先把一个操作数转成 double,结果 2.5 |
🧮 运算符
算术运算符
| 运算符 | 作用 | 示例 |
|---|---|---|
+ |
加法 | a + b |
- |
减法 | a - b |
* |
乘法 | a * b |
/ |
除法 | a / b |
% |
取余 | a % b |
示例:
1 | int a = 7; |
% 只能用于整数,不能直接用于浮点数。
关系运算符
关系运算符的结果是 bool。
| 运算符 | 作用 |
|---|---|
== |
等于 |
!= |
不等于 |
> |
大于 |
< |
小于 |
>= |
大于等于 |
<= |
小于等于 |
1 | int score = 85; |
逻辑运算符
| 运算符 | 作用 | 示例 |
|---|---|---|
&& |
且 | a > 0 && a < 10 |
|| |
或 | a == 0 || a == 1 |
! |
非 | !ok |
1 | int age = 20; |
赋值运算符
赋值是把右边的值写入左边变量。
1 | int x = 10; |
常见复合赋值:
| 运算符 | 等价写法 |
|---|---|
+= |
x = x + value |
-= |
x = x - value |
*= |
x = x * value |
/= |
x = x / value |
%= |
x = x % value |
自增自减
1 | int i = 0; |
单独作为一条语句时,i++ 和 ++i
效果一样。放在复杂表达式里时有区别,初学阶段不建议写这种代码:
1 | int i = 0; |
🖥️ 输入输出
cout
cout 用于向标准输出写内容。
1 |
|
简单补充缓冲区的概念
cout
输出内容时,通常不是每写一个字符就立刻交给屏幕,而是先放进一块临时区域,这块临时区域就叫缓冲区。
这样做的原因是:直接和设备交互比较慢,先把内容攒起来,再一次性输出,效率更高。
可以粗略理解为:
1 | 程序里的 cout |
endl 表示换行并刷新缓冲区。普通换行也可以用
'\n':
1 | cout << "Hello\n"; |
所以:
| 写法 | 含义 | 是否主动刷新缓冲区 |
|---|---|---|
cout << '\n'; |
只输出换行 | 否 |
cout << endl; |
输出换行并刷新 | 是 |
日常大量输出时,优先用
'\n';需要立刻看到输出结果时,再用 endl。
cin
cin 用于从标准输入读取内容。
1 |
|
读取多个值:
1 | int a{}; |
cin 默认按空白字符分隔输入,空格、换行、Tab
都可以作为分隔。
格式化输出入门
格式化输出常用 <iomanip>。
1 |
|
这行代码对新手容易难懂,因为它把“输出内容”和“设置输出格式”写在了一起。
先把它拆开看:
1 | cout << fixed; |
cout
是一个输出流,可以理解成一条通往控制台的输出通道。
<<
是流插入运算符,意思是“把右边的东西送进左边的输出流”。所以:
1 | cout << pi; |
表示把变量 pi 的值送到 cout 里输出。
但 fixed 和 setprecision(2)
不是要显示出来的普通数据,而是格式操纵符。它们会修改
cout 后续输出数字的格式:
| 写法 | 作用 |
|---|---|
fixed |
使用固定小数位形式输出 |
setprecision(2) |
小数点后保留 2 位 |
所以这一整行可以读成:
先告诉
cout:接下来用固定小数位;再告诉它保留 2 位小数;然后输出pi;最后换行并刷新。
常见工具:
| 工具 | 作用 |
|---|---|
fixed |
使用定点小数形式输出 |
setprecision(n) |
控制精度 |
setw(n) |
设置输出宽度 |
🌿 分支结构
if/else
if/else 用于根据条件选择不同路径。
1 | int score = 75; |
switch
switch
适合处理一个整数或枚举值对应多个固定分支的场景。
1 | int day = 3; |
break 用来跳出
switch。如果漏写,程序会继续执行后面的
case,这叫 fallthrough。
条件表达式
条件表达式也叫三目运算符:
1 | 条件 ? 条件为真时的值 : 条件为假时的值 |
示例:
1 | int score = 80; |
适合简单选择,不适合塞进复杂逻辑。
🔁 循环结构
for
for 适合循环次数比较明确的场景。
1 | for (int i = 0; i < 5; i++) { |
while
while 适合循环次数不固定,但继续条件明确的场景。
1 | int n = 5; |
while 是先判断,再执行。
do while
do while 是先执行一次,再判断。
1 | int n = 0; |
即使条件一开始就是假,循环体也会至少执行一次。
break
break 用于提前结束整个循环。
1 | for (int i = 0; i < 10; i++) { |
输出:
1 | 0 |
continue
continue 用于跳过本轮循环剩余语句,进入下一轮。
1 | for (int i = 0; i < 5; i++) { |
输出:
1 | 0 |
⚠️ 常见误区
| 误区 | 正解 |
|---|---|
| 局部变量不初始化也能安全使用 | 未初始化局部变量的值不确定,先初始化 |
5 / 2 会得到 2.5 |
两个整数相除得到整数,结果是 2 |
= 和 == 可以混用 |
= 是赋值,== 是比较 |
cin 可以自动处理所有错误输入 |
输入类型不匹配时,cin 会进入失败状态 |
break 和 continue 一样 |
break 结束循环,continue 跳到下一轮 |
switch 的 break 可写可不写 |
不写可能继续执行后续 case |
✅ 总结
基础语法的核心不是记住每个符号,而是理解:数据用变量和类型表示,计算靠表达式和运算符,程序路径由分支和循环控制。
下一步可以继续学函数、数组、字符串和指针。它们会把“单段代码”组织成更完整的程序。
Happy Hacking! 🎉