C++ 编程语法
变量就像有名字的盒子,用来存储数据。不同类型的数据需要不同类型的"盒子",本章还将深入理解计算机底层如何表示数字。
2.1
变量是用来保存数据的内存空间,我们通过变量名来访问这块空间中的数据。你可以把它理解成一个有名字的盒子——盒子的名字就是变量名,盒子里装的东西就是变量的值。
声明一个变量的语法是:类型 变量名;
| 1 | int a; // 定义整型变量 a(用于存储整数) |
| 2 | float b; // 定义浮点型变量 b(用于存储小数) |
| 3 | char c; // 定义字符型变量 c(用于存储单个字符) |
| 4 | bool flag; // 定义布尔型变量 flag(用于存储 true/false) |
2.2
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 | — | — | 无返回值函数 |
sizeof 的结果以字节为单位,sizeof(char) 始终为 1。另外,aEb 为科学计数法,表示 a × 10b。sizeof() 查看内存大小sizeof() 可以查看某个类型或变量占用了多少字节的内存,在调试和跨平台编程中很实用。
| 1 | // 查看基本类型的大小 |
| 2 | cout << "char: " << sizeof(char) << " 字节" << endl; // 输出 1 |
| 3 | cout << "int: " << sizeof(int) << " 字节" << endl; // 输出 4 |
| 4 | cout << "float: " << sizeof(float) << " 字节" << endl; // 输出 4 |
| 5 | cout << "double: " << sizeof(double) << " 字节" << endl; // 输出 8 |
| 6 | |
| 7 | // 查看变量的大小 |
| 8 | int num = 10; |
| 9 | double pi = 3.14159; |
| 10 | cout << sizeof(num) << " 字节" << endl; // 输出 4 |
| 11 | cout << sizeof(pi) << " 字节" << endl; // 输出 8 |
| 12 | |
| 13 | // 查看表达式结果的类型大小(5 是 int,3.14 是 double → 提升为 double) |
| 14 | cout << sizeof(5 + 3.14) << " 字节" << endl; // 输出 8 |
2.3
给变量起名要遵守以下规则,否则程序无法编译:
!、@、-)。
1abc 是非法的,但 abc1 合法。
int、for、while、return 等保留字都不能用作变量名。
Age 和 age 是两个完全不同的变量。
i、j、k;临时变量用 tmp、temp;计数用 cnt;结果用 ans、res。避免用拼音或无意义的单个字母(循环变量除外)。2.4
使用 = 可以给变量赋值。语法是:变量名 = 值;
也可以在定义的同时赋值,称为初始化。C++ 支持三种初始化写法:
| 1 | // 先定义,再赋值 |
| 2 | int a, b; |
| 3 | a = 5; |
| 4 | b = 10.5; // b 是 int,10.5 会被截断为 10(小数部分丢失,不四舍五入) |
| 5 | |
| 6 | // 三种初始化写法 |
| 7 | int a2 = 5; // 拷贝初始化(最常见) |
| 8 | double b2(3.14); // 直接初始化 |
| 9 | int c2{10}; // 列表初始化(C++11 起,推荐!可防止窄化转换) |
= 是赋值运算符,规则是从右向左——先计算右边的值,再把结果存入左边的变量。所以 a = a + 1 在数学上不成立,但在程序中表示"把 a 的当前值加 1,再存回 a",完全合法。2.5
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 |
| 1 | int a = 10, b = 3; |
| 2 | cout << a + b << endl; // 13 |
| 3 | cout << a - b << endl; // 7 |
| 4 | cout << a * b << endl; // 30 |
| 5 | cout << a / b << endl; // 3(整数除法,截去小数!) |
| 6 | cout << a % b << endl; // 1(取余数) |
| 7 | |
| 8 | double c = 10.0 / 3; |
| 9 | cout << c << endl; // 3.33333(浮点除法) |
| 10 | |
| 11 | a++; // 等同于 a = a + 1,a 变成 11 |
| 12 | b--; // 等同于 b = b - 1,b 变成 2 |
10 / 3 在 C++ 中结果是 3,不是 3.333!两个整数相除只保留整数部分。如果需要小数结果,至少要让其中一个数是浮点数,例如写成 10.0 / 3。++a(前缀)是先加后用,a++(后缀)是先用后加。在单独的语句中两者效果相同,但在表达式中会有差异。例如 b = a++ 和 b = ++a 会给 b 赋不同的值。2.6
运算时,精度低的类型会自动向精度高的类型转换,规则如下:
| 1 | int a = 3; |
| 2 | double b = 1.5; |
| 3 | double c = a + b; // a 自动提升为 double,c = 4.5 ✓ |
| 4 | |
| 5 | int x = 7, y = 2; |
| 6 | double z = x / y; // 先算 7/2 = 3(整除),再赋值,z = 3.0 ✗ |
x / y 先以整数方式计算得 3,然后才把 3 转成 3.0 赋给 z。要得到 3.5,必须在做除法之前就完成类型转换。当自动转换不满足需求时,可以手动指定转换方式:
| 1 | int x = 7, y = 2; |
| 2 | |
| 3 | double r1 = (double)x / y; // C 风格强制转换,r1 = 3.5 ✓ |
| 4 | double r2 = double(x) / y; // C++ 函数式转换,r2 = 3.5 ✓ |
| 5 | double r3 = double(x / y); // ⚠️ 陷阱:先整除得 3,再转成 3.0 |
| 6 | |
| 7 | // char 和 int 互转 |
| 8 | int code = int('A'); // code = 65 |
| 9 | char ch = char(code + 1); // ch = 'B' |
(type)value 的 C 风格转换简洁够用。在工程项目中,C++ 提供了四种更安全的命名转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,竞赛入门阶段了解即可。2.7
ASCII(美国信息交换标准代码)是一种将字符映射为数字的编码系统,最初于 1963 年发布。标准 ASCII 定义了 128 个字符(0~127),包括控制字符和可显示字符。计算机底层只存储数字,字符本质上也是用整数来表示的。
| 1 | // 技巧 1:大小写互转(差值为 32) |
| 2 | char lower = char('A' + 32); // 'a'(大写转小写) |
| 3 | char upper = char('a' - 32); // 'A'(小写转大写) |
| 4 | |
| 5 | // 技巧 2:数字字符 → 整数 |
| 6 | int n = '5' - '0'; // n = 5(字符减 '0' 得数值) |
| 7 | |
| 8 | // 技巧 3:整数 → 数字字符 |
| 9 | char ch = char(5 + '0'); // ch = '5'(数值加 '0' 得字符) |
2.8
计算机只认识 0 和 1,那它是如何表示负数的?科学家们为此设计了三种编码方案,依次改进,最终解决了这个问题。
符号位约定:最高位(最左边)表示正负,0 代表正数,1 代表负数,其余位存储数值。以 8 位(1 字节)为例:
| 1 | 0 0000101 → +5(符号位为 0,表示正数) |
| 2 | 1 0000101 → -5(符号位为 1,表示负数) |
| ── 原码(错误)────────────────── | |
| 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 完全正确!✓ |
| 十进制 | 原码 | 反码 | 补码 |
|---|---|---|---|
| +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 |
1000 0000 被用来表示 −128。8 位补码能表示 256 个数:−128~−1(128 个)加上 0~127(128 个),比原码多表示一个数。