C++ 编程语法

二、变量与数据类型

变量就像有名字的盒子,用来存储数据。不同类型的数据需要不同类型的"盒子",本章还将深入理解计算机底层如何表示数字。

什么是变量

变量是用来保存数据的内存空间,我们通过变量名来访问这块空间中的数据。你可以把它理解成一个有名字的盒子——盒子的名字就是变量名,盒子里装的东西就是变量的值。

声明一个变量的语法是:类型 变量名;

C++ · 变量声明
1int a; // 定义整型变量 a(用于存储整数)
2float b; // 定义浮点型变量 b(用于存储小数)
3char c; // 定义字符型变量 c(用于存储单个字符)
4bool flag; // 定义布尔型变量 flag(用于存储 true/false)

常见基础数据类型

C++ 中有多种基本数据类型,选择合适的类型既能节省内存,又能避免计算错误。先了解两个基本单位:

bit(比特)是计算机中最小的存储单位,只能存 0 或 1。
Byte(字节)
是可寻址的最小单位,1 Byte = 8 bit。
C++ 规定 char 恰好是 1 Byte,其他类型都是 char 的整数倍。

类型名 关键字 占用空间 存储范围 用途
字符型 char 1 B -128 ~ 127 单个字母 / 符号
短整型 short 2 B -32768 ~ 32767 节省内存的小整数
整型 int 4 B 约 ±21 亿 整数 最常用
长整型 long long 8 B 约 ±9.2 × 10¹⁸ 特别大的整数
浮点型 float 4 B ≈ ±3.4×10³⁸,有效数字 6~7 位 小数(精度低)慎用
双精度浮点型 double 8 B ≈ ±1.8×10³⁰⁸,有效数字 15~16 位 小数(精度高)
布尔型 bool 1 B true 或 false 判断真假
无符号整数 size_t 4 / 8 B 0 ~ 平台最大地址值 存储对象大小
空类型 void 无返回值函数
📌
平台差异说明:表中数值基于 GCC/MSVC 在 32/64 位 x86 平台上的典型实现。C++ 标准只规定了最小范围,不规定确切大小。sizeof 的结果以字节为单位,sizeof(char) 始终为 1。另外,aEb 为科学计数法,表示 a × 10b

sizeof() 查看内存大小

sizeof() 可以查看某个类型或变量占用了多少字节的内存,在调试和跨平台编程中很实用。

C++ · sizeof() 示例
1// 查看基本类型的大小
2cout << "char: " << sizeof(char) << " 字节" << endl; // 输出 1
3cout << "int: " << sizeof(int) << " 字节" << endl; // 输出 4
4cout << "float: " << sizeof(float) << " 字节" << endl; // 输出 4
5cout << "double: " << sizeof(double) << " 字节" << endl; // 输出 8
6
7// 查看变量的大小
8int num = 10;
9double pi = 3.14159;
10cout << sizeof(num) << " 字节" << endl; // 输出 4
11cout << sizeof(pi) << " 字节" << endl; // 输出 8
12
13// 查看表达式结果的类型大小(5 是 int,3.14 是 double → 提升为 double)
14cout << sizeof(5 + 3.14) << " 字节" << endl; // 输出 8

变量命名规则

给变量起名要遵守以下规则,否则程序无法编译:

💡
竞赛命名习惯:变量名尽量见名知义。循环计数器常用 ijk;临时变量用 tmptemp;计数用 cnt;结果用 ansres。避免用拼音或无意义的单个字母(循环变量除外)。

变量赋值与初始化

使用 = 可以给变量赋值。语法是:变量名 = 值;

也可以在定义的同时赋值,称为初始化。C++ 支持三种初始化写法:

C++ · 赋值与初始化
1// 先定义,再赋值
2int a, b;
3a = 5;
4b = 10.5; // b 是 int,10.5 会被截断为 10(小数部分丢失,不四舍五入)
5
6// 三种初始化写法
7int a2 = 5; // 拷贝初始化(最常见)
8double b2(3.14); // 直接初始化
9int c2{10}; // 列表初始化(C++11 起,推荐!可防止窄化转换)
⚠️
= 不是数学中的"等于":编程中 = 是赋值运算符,规则是从右向左——先计算右边的值,再把结果存入左边的变量。所以 a = a + 1 在数学上不成立,但在程序中表示"把 a 的当前值加 1,再存回 a",完全合法。

变量运算

C++ 支持以下算术运算符,按优先级从高到低排列:

优先级 运算符 含义 示例 结果
最高优先级
0 ( ) 提升优先级 (1+2) * 3 9
优先级 1 — 自增 / 自减
1 ++ 自增(加 1) int a=5; a++; a 变为 6
1 -- 自减(减 1) int a=5; a--; a 变为 4
优先级 2 — 乘 / 除 / 取余
2 * 5 * 3 15
2 / 5 / 2 2(整数截断!)
2 % 取余(模) 5 % 3 2
优先级 3 — 加 / 减
3 + 5 + 3 8
3 - 5 - 3 2
C++ · 运算示例
1int a = 10, b = 3;
2cout << a + b << endl; // 13
3cout << a - b << endl; // 7
4cout << a * b << endl; // 30
5cout << a / b << endl; // 3(整数除法,截去小数!)
6cout << a % b << endl; // 1(取余数)
7
8double c = 10.0 / 3;
9cout << c << endl; // 3.33333(浮点除法)
10
11a++; // 等同于 a = a + 1,a 变成 11
12b--; // 等同于 b = b - 1,b 变成 2
⚠️
整数除法陷阱:10 / 3 在 C++ 中结果是 3,不是 3.333!两个整数相除只保留整数部分。如果需要小数结果,至少要让其中一个数是浮点数,例如写成 10.0 / 3
🔍
前缀 vs 后缀:++a(前缀)是先加后用,a++(后缀)是先用后加。在单独的语句中两者效果相同,但在表达式中会有差异。例如 b = a++b = ++a 会给 b 赋不同的值。

数据类型转换

2.6.1 隐式类型转换(自动)

运算时,精度低的类型会自动向精度高的类型转换,规则如下:

char short int long long float double 精度由低到高,自动提升 →
C++ · 隐式转换
1int a = 3;
2double b = 1.5;
3double c = a + b; // a 自动提升为 double,c = 4.5 ✓
4
5int x = 7, y = 2;
6double z = x / y; // 先算 7/2 = 3(整除),再赋值,z = 3.0 ✗
⚠️
关键原则:隐式转换发生在运算时,不是赋值时。x / y 先以整数方式计算得 3,然后才把 3 转成 3.0 赋给 z。要得到 3.5,必须在做除法之前就完成类型转换。

2.6.2 强制类型转换(手动)

当自动转换不满足需求时,可以手动指定转换方式:

C++ · 强制转换
1int x = 7, y = 2;
2
3double r1 = (double)x / y; // C 风格强制转换,r1 = 3.5 ✓
4double r2 = double(x) / y; // C++ 函数式转换,r2 = 3.5 ✓
5double r3 = double(x / y); // ⚠️ 陷阱:先整除得 3,再转成 3.0
6
7// char 和 int 互转
8int code = int('A'); // code = 65
9char ch = char(code + 1); // ch = 'B'
💡
竞赛建议:竞赛中用 (type)value 的 C 风格转换简洁够用。在工程项目中,C++ 提供了四种更安全的命名转换:static_castdynamic_castconst_castreinterpret_cast,竞赛入门阶段了解即可。

ASCII 编码

ASCII(美国信息交换标准代码)是一种将字符映射为数字的编码系统,最初于 1963 年发布。标准 ASCII 定义了 128 个字符(0~127),包括控制字符和可显示字符。计算机底层只存储数字,字符本质上也是用整数来表示的。

常用 ASCII 值速查

SP
32
' ' 空格,最小可显示字符
0
48
'0'~'9' 对应 48~57
A
65
'A'~'Z' 对应 65~90
a
97
'a'~'z' 对应 97~122

三个实用技巧

C++ · ASCII 技巧
1// 技巧 1:大小写互转(差值为 32)
2char lower = char('A' + 32); // 'a'(大写转小写)
3char upper = char('a' - 32); // 'A'(小写转大写)
4
5// 技巧 2:数字字符 → 整数
6int n = '5' - '0'; // n = 5(字符减 '0' 得数值)
7
8// 技巧 3:整数 → 数字字符
9char ch = char(5 + '0'); // ch = '5'(数值加 '0' 得字符)

原码、反码与补码

计算机只认识 0 和 1,那它是如何表示负数的?科学家们为此设计了三种编码方案,依次改进,最终解决了这个问题。

符号位约定:最高位(最左边)表示正负,0 代表正数,1 代表负数,其余位存储数值。以 8 位(1 字节)为例:

符号位示例
10 0000101 → +5(符号位为 0,表示正数)
21 0000101 → -5(符号位为 1,表示负数)
1
原码
最直觉的写法:符号位表示正负,其余位直接写数字的二进制。
+5 → 0 0000101
-5 → 1 0000101
✗ 问题:加减法需要专门区分正负处理,电路复杂。
2
反码
规则:正数不变;负数符号位不变,其余位全部取反。
-5 原码:1 0000101
-5 反码:1 1111010
△ 问题:0 有两种表示(+0 和 -0),需额外处理。
3
补码 ✓
规则:正数不变;负数 = 反码 + 1。现代计算机真正使用的方案。
-5 反码:1 1111010
-5 补码:1 1111011
✓ -0 被消灭,多出的编码用来表示 -128!

验证:5 + (−5) 在三种编码下的结果

二进制加法演示
── 原码(错误)──────────────────
0 0000101 (+5)
+ 1 0000101 (-5)
──────────
1 0001010 = -10,完全不对!✗
── 反码(接近但有瑕疵)───────────
0 0000101 (+5 的反码)
+ 1 1111010 (-5 的反码)
──────────
1 1111111 = -0,还是不对 △
── 补码(正确!)────────────────
0 0000101 (+5 的补码)
+ 1 1111011 (-5 的补码)
──────────
1 0 0000000 最高位进位溢出,自动丢弃
0 0000000 = 0 完全正确!✓

三种编码对照表(8 位)

十进制 原码 反码 补码
+5 0000 0101 0000 0101 0000 0101
-5 1000 0101 1111 1010 1111 1011
+0 0000 0000 0000 0000 0000 0000
-0 1000 0000 1111 1111 (不存在!)
-128 无法表示 无法表示 1000 0000
-1 1000 0001 1111 1110 1111 1111
+127 0111 1111 0111 1111 0111 1111
📖
为什么 signed char 是 −128 到 127?补码消灭了 −0,空出来的编码 1000 0000 被用来表示 −128。8 位补码能表示 256 个数:−128~−1(128 个)加上 0~127(128 个),比原码多表示一个数。
📚
扩展阅读:C++20 标准正式强制要求有符号整数使用补码表示(此前是实现定义的)。补码不再是"可选方案",而是所有 C++ 平台的统一标准。理解三种编码的演进历史,有助于真正体会补码设计的精妙之处。