第二章 数据类型和运算符
┌────────────────────────────────────────────────────────────────┐ │ 这一章要讲的事,一张图看完 │ ├────────────────────────────────────────────────────────────────┤ │ 第二章 数据类型和运算符 │ │ │ │ │ ├── 1. C++ 基本数据类型 整型浮点字符布尔,各占多大地方 │ │ ├── 2. 常量和变量 认领内存的规矩,命名和初始化 │ │ ├── 3. 运算符 加减乘除到移位,外加优先级 │ │ ├── 4. 数据类型转换 隐式自动转,显式手动转,坑最多 │ │ └── 5. 小结 一张表收口,加练习和下一章预告 │ └────────────────────────────────────────────────────────────────┘老规矩,例子都自己敲一遍。这一章尤其别偷懒,类型和运算符的细节,看的时候都懂,一写就错,不敲一遍发现不了。
一、C++ 基本数据类型
┌──────────────────────────────────────────────────┐ │ C++ 类型的家谱 │ ├──────────────────────────────────────────────────┤ │ 一套类型一套脾气,各管各的 │ │ │ │ 整型 │ │ ├─ short 2 字节,小整数 │ │ ├─ int 4 字节,日常主力 │ │ ├─ long 4 或 8 字节,看平台 │ │ └─ long long 8 字节,大数专用 │ │ 每家整型都有带符号和不带符号两版 │ │ 不带符号的只放 0 和正数,范围翻倍 │ │ │ │ 浮点型 float、double、long double,管小数 │ │ 字符型 char,一个字节,存的是编号 │ │ 布尔型 bool,一个字节,只放 true 和 false │ └──────────────────────────────────────────────────┘1.1 类型是内存的图纸
内存是一条超长的字节带,一个字节 8 位,每个字节有自己的地址。同样的字节序列,按不同类型解释,读出来的东西完全不同。类型就是图纸,它告诉编译器这几字节按什么规矩摆、怎么读。
比如 0x01020304 这四字节,当成四个编号看是四个小数字,当成一个 int 看就是 16909060。声明类型,就是提前把图纸交给编译器,后面怎么摆怎么算全按它来。
┌────────────────────────────────────────────────────────┐ │ 一个 int 的四字节怎么摆 │ ├────────────────────────────────────────────────────────┤ │ 同一个数,字节顺序两样(0x01020304,就是 16909060) │ │ │ │ 小端,低字节放低地址 大端,高字节放低地址 │ │ │ │ 地址 0 04 地址 0 01 │ │ 地址 1 03 地址 1 02 │ │ 地址 2 02 地址 2 03 │ │ 地址 3 01 地址 3 04 │ │ │ │ x86 和主流 ARM 用这套 网络传输和部分老平台 │ │ │ │ 两种摆法读出来都是同一个数,自己电脑上不用操心 │ │ 跨机器传二进制才分大小端,那是网络编程的事 │ └────────────────────────────────────────────────────────┘int 的四字节怎么摆有大小端两种规矩。普通开发者一辈子感知不到这个差别,除非去写网络协议或者跟别的机器交换二进制文件,所以这页图看过就算了,不用记。
1.2 整型一家
整型管整数,按能放多大的数分四档,每一档都有带符号和不带符号两个版本。带符号的能放负数,是默认版本;不带符号的只放 0 和正数,范围翻倍。
| 类型 | 字节 | 能放的范围 |
|---|---|---|
| short | 2 | -32768 到 32767 |
| unsigned short | 2 | 0 到 65535 |
| int | 4 | -2147483648 到 2147483647 |
| unsigned int | 4 | 0 到 4294967295 |
| long | 4 或 8 | 看平台,Windows 上 4,Linux 上 8 |
| long long | 8 | -9223372036854775808 到 9223372036854775807 |
| unsigned long long | 8 | 0 到 18446744073709551615 |
日常用 int 就够。数大的场合,销量、库存、金额乘个几百倍就可能过 21 亿,上 long long。计数、编号、位运算这种不会出现负数的场景,用 unsigned 就对了。
有一条要注意,C++ 标准只规定了每种类型的最小范围,没规定精确字节数。long 在 Windows 上是 4 字节,在 Linux 上是 8 字节,同一份代码两边行为不一致。要精确控制宽度,后面章节有固定宽度类型,现在先知道这个坑。
1.3 浮点型
浮点型管小数,三兄弟按精度排。
| 类型 | 字节 | 有效数字 | 大致范围 |
|---|---|---|---|
| float | 4 | 约 7 位 | 1.2e-38 到 3.4e38 |
| double | 8 | 约 15 到 16 位 | 2.2e-308 到 1.8e308 |
| long double | 看平台 | 不低于 double | 看平台 |
写代码时 3.14 默认是 double,要 float 得加后缀,3.14f。多数场合用 double,精度够,速度也不慢。
浮点数有个著名陷阱。0.1 这个数,二进制里存不住精确值,存进去的是近似值,两个近似值加起来,误差就露出来了。
0.1 + 0.2 的结果是 0.30000000000000004所以比较浮点数别用 ==,要看两个数的差距够不够小。差值的绝对值小于 1e-6,就当它们相等,这是惯用写法。涉及钱的计算更别碰浮点,用整数存分,显示的时候再除以 100,一分钱都不许它飘。
1.4 字符型和布尔型
char 一个字节,存的是编号不是字本身。字符按 ASCII 编号入库,'A' 是 65,'a' 是 97,大小写相差 32,'0' 是 48。char 参与运算时按整数算,'A' + 1 等于 66,正好是 'B'。
常用的转义字符有这么几个。
| 转义符 | 含义 |
|---|---|
| \n | 换行 |
| \t | 制表符,按一下 Tab 那么宽 |
| \ | 反斜杠自己 |
| " | 双引号 |
| ' | 单引号 |
| \0 | 空字符,字符串的结尾标记 |
bool 一个字节,只放 true 和 false。C++ 里非零即真,0 为假,这个习惯后面到处都用。
1.5 一张表记住常见占用
每种类型占几个字节,不用背,写几行代码问出来。
#include <iostream> using namespace std; int main() { cout << "bool " << sizeof(bool) << " 字节" << endl; cout << "char " << sizeof(char) << " 字节" << endl; cout << "short " << sizeof(short) << " 字节" << endl; cout << "int " << sizeof(int) << " 字节" << endl; cout << "long " << sizeof(long) << " 字节" << endl; cout << "long long " << sizeof(long long) << " 字节" << endl; cout << "float " << sizeof(float) << " 字节" << endl; cout << "double " << sizeof(double) << " 字节" << endl; return 0; }64 位机器上跑出来是这样。
bool 1 字节 char 1 字节 short 2 字节 int 4 字节 long 4 字节 long long 8 字节 float 4 字节 double 8 字节64 位 Windows 和 64 位 Linux 的差别在 long,其他一样。自己的机器什么结果,敲一遍就知道,比信任何教程都强。
二、常量和变量
2.1 变量是认领下来的一块内存
变量就是在内存里认领一块地,认领的时候要说清三样,这块地多大、叫什么、先放什么。
┌─────────────────────────────────────────────────────────┐ │ 变量是认领下来的一块内存 │ ├─────────────────────────────────────────────────────────┤ │ 一条声明,三样东西 │ │ │ │ +----------+------------+------------+--------------+ │ │ |成分 |代码里 |例子 |管什么 | │ │ +----------+------------+------------+--------------+ │ │ |类型 |int |4 字节 |格子多大 | │ │ |名字 |score |贴标签 |代码怎么称呼它| │ │ |值 |90 |装内容 |随时能改 | │ │ +----------+------------+------------+--------------+ │ │ │ │ int score = 90; 这一行,三样全占齐 │ │ 没初始化的变量里是内存残留,读到什么全看运气 │ └─────────────────────────────────────────────────────────┘声明的时候不给初值,这块地里的数据是上一位房客留下的。同一个程序跑两遍,读到的数可能都不一样,这种 bug 查起来最费劲。好习惯只有一条,声明的时候就初始化。
初始化的写法有四种,效果等价。
int a = 5; // 传统写法 int b(5); // 构造函数写法 int c{5}; // 列表初始化,C++11 起 int d{}; // 列表初始化,值为 0推荐列表初始化那一对花括号。它多一道检查,窄化转换直接拦下。
int x{3.7}; // 编译报错,小数变整数不许悄悄发生 int y = 3.7; // 能过,y 变成 3,小数部分丢了同一行声明多个同类型变量也合法,int a = 1, b = 2;。别滥用,一行一个看得清楚。
2.2 命名规则
名字只能由字母、数字、下划线组成,数字不能打头,大小写敏感,不能撞关键字。
| 名字 | 行不行 | 原因 |
|---|---|---|
| score | 行 | 纯字母 |
| score2 | 行 | 数字不在开头 |
| _total | 行 | 下划线可以开头 |
| 2score | 不行 | 数字打头 |
| my-score | 不行 | 短横线不是下划线 |
| int | 不行 | 撞了关键字 |
| Score 和 score | 两个名字 | 大小写敏感 |
风格上建议两条。名字见名知意,totalPrice 比 tp 强一百倍,三个月后回来看,tp 是谁你根本想不起来。多个单词之间用下划线或者驼峰,选一种用到底,别混着来。
2.3 常量,认领了就不许改
常量的值定下来不许改,写法有两种。
#define MAX_SIZE 100 // 宏常量 const int maxSize = 100; // const 常量推荐 const。宏常量是预处理阶段的文本替换,编译器只看见 100,不知道它原来叫什么,出错了报错信息里连名字都不留。const 常量有类型、有名字,受编译器检查,还能进调试器看。
| #define | const | |
|---|---|---|
| 干活阶段 | 预处理,文本替换 | 编译期 |
| 有类型吗 | 没有 | 有 |
| 出错了 | 只看见数值,看不见名字 | 名字和类型都在报错里 |
| 能进调试器吗 | 不能 | 能 |
const 后面还有花样,const 指针、const 引用、const 成员函数,到指针和类那两章再展开。现在记住一句,新代码用 const,别用宏。
2.4 关键字,这些名字被占了
C++ 留了一批名字自己用,变量不能跟它们重名。常用的有这么些。
| 类别 | 关键字 |
|---|---|
| 类型相关 | int、double、float、char、bool、void、short、long |
| 类型修饰 | const、unsigned、signed、static、auto |
| 流程相关 | if、else、switch、case、default、for、while、do、break、continue、return |
| 真值与内存 | true、false、sizeof、new、delete、this |
| 结构和类 | struct、class、public、private、protected、enum、union |
| 其他 | using、namespace、typedef、try、catch、throw |
完整名单有九十多个,不用背。用到的时候编辑器会给它上个色,变色了就别当变量名。
三、运算符
3.1 算术运算符
| 运算符 | 作用 | 例子 |
|---|---|---|
| + | 加 | 3 + 2 得 5 |
| - | 减 | 3 - 2 得 1 |
| * | 乘 | 3 * 2 得 6 |
| / | 除 | 看两边类型,见下 |
| % | 取余 | 7 % 3 得 1,只认整数 |
除号是重灾区。两边都是整数,除出来还是整数,小数部分直接丢,不是四舍五入。
┌─────────────────────────────────────────────────────┐ │ 整数除法不要小数 │ ├─────────────────────────────────────────────────────┤ │ 同样的两个数,不同的下场 │ │ │ │ 7 / 2,两边都是整数 7.0 / 2,有个小数 │ │ │ │ │ │ v v │ │ 3,小数部分被丢掉 3.5,小数保住了 │ │ │ │ 算平均数、算比例、算百分比,先把一边转成 double │ └─────────────────────────────────────────────────────┘把开篇那个平均分程序写全,看得更清楚。
#include <iostream> using namespace std; int main() { int total = 285; int count = 3; cout << total / count << endl; // 95,碰巧整除了 cout << total / 4 << endl; // 71,71.25 被丢成 71 return 0; }取余号只认整数,3.5 % 2 直接编不过。除零更狠,整数除以 0 程序当场崩溃,浮点除以 0 得 inf,不报错但结果没法用。
3.2 赋值和复合赋值
等号是赋值,把右边的值装进左边的变量,不是数学里的相等。等号左边只能放一个变量,a = b = 3能写,从右边开始算,b 先得 3,再把 b 的值给 a。
复合赋值是懒人写法,效果和拆开一样。
| 写法 | 等价于 |
|---|---|
| a += 2 | a = a + 2 |
| a -= 2 | a = a - 2 |
| a *= 2 | a = a * 2 |
| a /= 2 | a = a / 2 |
| a %= 2 | a = a % 2 |
3.3 自增自减,++ 放前放后不一样
++ 让变量加一,-- 让变量减一,各有两种放法,差别只在嵌进表达式的时候露出来。
┌────────────────────────────────────────────────────┐ │ ++ 放前面和放后面 │ ├────────────────────────────────────────────────────┤ │ i 从 3 起步,两条路不一样 │ │ │ │ j = i++ j = ++i │ │ 先用旧值,再加一 先加一新,再用新值 │ │ │ │ │ │ v v │ │ j 得 3,i 变 4 j 得 4,i 变 4 │ │ │ │ 单独一行用没区别,嵌进表达式就差在这里 │ └────────────────────────────────────────────────────┘代码走一遍。
#include <iostream> using namespace std; int main() { int i = 3; int j = i++; // 先把 3 给 j,i 再加成 4 cout << j << " " << i << endl; // 3 4 int x = 3; int y = ++x; // x 先加成 4,再把 4 给 y cout << y << " " << x << endl; // 4 4 return 0; }建议只有一条,别把 ++ 塞进复杂表达式,cout << i++ + ++i这种代码除了炫技没有任何好处,行为还容易看错。
3.4 关系运算符
比大小和比相等,结果都是 bool,成立是 true,不成立是 false。
| 运算符 | 作用 |
|---|---|
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| == | 相等,两个等号 |
| != | 不相等 |
经典事故是把 == 写成 =。if (x = 5)是赋值,5 非零,条件恒为真,if 里永远执行。现代编译器会给警告,警告别当没看见。
浮点数之间别用 == 比,回 1.3 节,用差值小于一个小数来判断。
3.5 逻辑运算符和短路
| 运算符 | 作用 |
|---|---|
| && | 两边都真才真 |
| 两个竖线 | 有一边真就真 |
| ! | 取反,真变假,假变真 |
&& 和 两个竖线会抄近路。左边已经能定输赢,右边根本不看。
┌──────────────────────────────────────────────────────────┐ │ 逻辑运算会抄近路 │ ├──────────────────────────────────────────────────────────┤ │ && 碰到假就收工,|| 碰到真就收工 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ if (x != 0 && 10 / x > 1) │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 左边先算,x 是 0 的话整个式子直接假 │ │ 右边的除法压根不发生,顺手把除零也挡了 │ │ │ │ 判空的表达式要写在左边,越界访问放右边 │ │ 顺序写反了,右边先炸,左边白写 │ └──────────────────────────────────────────────────────────┘短路是标准规定的行为,不是哪个编译器的好心,可以放心用。写复合条件有个讲究,便宜又安全的放左边,贵又有风险的放右边。
3.6 位运算符
位运算直接在二进制位上动手,只认整型。
| 运算符 | 叫什么 | 例子 | 结果和规律 |
|---|---|---|---|
| & | 按位与 | 5 & 3 | 1,两位都是 1 才留 1 |
| 单竖线 | 按位或 | 5 单竖线 3 | 7,有一位是 1 就留 1 |
| ^ | 按位异或 | 5 ^ 3 | 6,相同为 0,不同为 1 |
| ~ | 按位取反 | ~5 | -6,0 变 1,1 变 0 |
| << | 左移 | 5 << 2 | 20,后面补 0 |
| >> | 右移 | 5 >> 1 | 2,前面补 0 |
左移就是往高位搬,每搬一位数值翻倍。
┌──────────────────────────────────────────────────────────┐ │ 左移右移在干什么 │ ├──────────────────────────────────────────────────────────┤ │ 1 往左搬三位,每搬一位翻一倍 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 起步 00000001 十进制 1 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 左移一位 00000010 十进制 2 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 左移两位 00000100 十进制 4 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ 左移三位 00001000 十进制 8 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 右移是反着搬,每搬一位除以 2,零头丢掉 │ │ 1 << 10 就是 1024,乘除 2 的幂用它最快 │ └──────────────────────────────────────────────────────────┘位运算的实用场合有两个。权限标志,一个 int 的 32 位当 32 个开关用,第 n 位是 1 表示有这个权限。判奇偶,x & 1是 1 就是奇数,是 0 就是偶数,比取余快。乘除 2 的幂图上画了,记住位移比乘法快就行。
两个注意。有符号数左移丢了高位,是未定义行为,别赌编译器。右移负数,填 0 还是填 1 看编译器,想要确定行为先转无符号。
3.7 三元运算符
三元运算符是压缩版的 if else,问号前面是条件,冒号两边是两个结果。
int max = (a > b) ? a : b; // a 大取 a,b 大取 b简单场合用着顺手,嵌套三元是灾难。a ? b : c ? d : e这种,看得人想砸键盘,老老实实写 if。
3.8 优先级,不确定就加括号
运算符有先后,全表在这儿,从高到低。
| 档位 | 运算符 | 一句话 |
|---|---|---|
| 第一档 | 括号 | 想先算的套起来 |
| 第二档 | 单目运算 | ++ -- ! ~ 正负号、强制转换、sizeof |
| 第三档 | 乘除取余 | * / % |
| 第四档 | 加减 | + - |
| 第五档 | 位移 | << >> |
| 第六档 | 比大小 | < <= > >= |
| 第七档 | 比相等 | == != |
| 第八档 | 按位与 | & |
| 第九档 | 按位异或 | ^ |
| 第十档 | 按位或 | 单竖线 |
| 第十一档 | 逻辑与 | && |
| 第十二档 | 逻辑或 | 两个竖线 |
| 第十三档 | 三元 | ? : |
| 第十四档 | 赋值 | = 和 += 那一族 |
| 第十五档 | 逗号 | 最低 |
这张表不用背,背了也会忘。记两条就够,不确定的地方加括号,括号永远最先算。位运算的优先级比普通人直觉低,a & b == c先算相等再按位与,想要按位与先算就套括号。
四、数据类型转换
4.1 隐式转换,编译器悄悄干活
类型之间会互相转,不用你开口的那种叫隐式转换。方向只有一个,往高了转。
┌──────────────────────────────────────────────────────────┐ │ 隐式转换的阶梯 │ ├──────────────────────────────────────────────────────────┤ │ 自动转换的方向,一路往高爬 │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ bool 只有真假两个值 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ char 一个字节,编号 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ short 两个字节 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ int 四个字节,日常主力 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ long 四到八个字节 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ long long 八个字节,大数 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ float 小数起步 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌────────────────────────────────────────────────────┐ │ │ │ double 小数主力 │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ 两边类型打架,低的自动升级成高的那个再算 │ │ int 和 double 相加,int 先变成 double │ └──────────────────────────────────────────────────────────┘规矩有两条。小的参与运算先提升,char 和 short 不管是加减还是打印,先升成 int 再上场。两边类型不一样,低的自动爬成高的,算完的结果按高的那个类型存。赋值的时候也转,double d = 3;里的 3 悄悄变成 3.0。
编译器做这些事不吭声,好处是省事,坏处是错了你不知道。
4.2 显式转换,自己开口要清楚
自己要求的转换叫显式转换,两种写法。
int total = 285; int count = 4; double avg1 = (double)total / count; // C 风格 double avg2 = static_cast<double>(total) / count; // C++ 风格两种效果一样,都得到 71.25。推荐 static_cast,理由和 2.3 节推荐 const 一样,它在代码里长得显眼,搜索能搜到,编译器能检查,出错了报错信息带类型名。C 风格那个括号混在代码里,肉眼难找。
C++ 还有 const_cast、reinterpret_cast、dynamic_cast 三种,各有各的场合,到指针和类那两章再见。现在记住,日常转换 static_cast 一把够用。
4.3 转换的坑,挨个排雷
转换是 bug 密度最高的地方,常见事故有这么几款。
| 事故 | 现场 | 原因 | 解法 |
|---|---|---|---|
| 平均数丢小数 | 285 除以 4 得 71 | 两个 int 相除 | 一边转 double |
| int 溢出 | 大数乘大数得负数 | 结果超过 21 亿 | 中间量用 long long |
| 无符号回绕 | unsigned 减到 0 再减 | 回绕是标准行为,不报错 | 边界处加判断 |
| 混合比较翻车 | -1 大于 1 | 有符号转无符号后成了巨大正数 | 别混着比 |
| 浮点丢精度 | float 存 16777217 变 16777216 | 有效数字不够 | 换 double |
| char 溢出 | char 装 200 | 超出一个字节 | 换类型 |
混合比较这款最反直觉,光看代码不信,跑一遍就服了。
#include <iostream> using namespace std; int main() { unsigned int u = 1; int i = -1; cout << (u > i) << endl; // 1,true,-1 居然大于 1 return 0; }有符号和无符号比大小,有符号的先被转成无符号,-1 转过去变成 4294967295,当然大于 1。规矩只有一条,比较的两边类型一致,不一致就先转成一样的。
4.4 转换不报错,这才最危险
语法错误编译器会拦,类型转换它基本不拦。该丢的小数丢了,该报的溢出没报,程序跑得欢,结果离谱,这种 bug 调试起来最耗人。
应对办法也简单,每一处转换心里有数。写除法前问一句,两边是不是都想要整数。比较大小时问一句,两边类型一样吗。存大数前问一句,这个类型装得下吗。三个问题问完,这一章的坑就躲掉大半。
五、小结
5.1 本章知识收口表
| 模块 | 你现在应该能做对的事 | 自测 |
|---|---|---|
| 基本类型 | 说清四大家庭和各自字节数 | □ 能说出 int 和 double 的字节数 |
| sizeof | 会用它验字节数 | □ 跑一遍 1.5 节的程序 |
| 变量常量 | 声明即初始化,常量用 const | □ 能写出列表初始化 |
| 运算符 | 算术关系逻辑位移都会用 | □ 能心算 5 & 3 和 5 << 2 |
| 优先级 | 知道括号最优先 | □ 能排出 1 + 2 * 3 的顺序 |
| 类型转换 | 隐式往高转,显式用 static_cast | □ 能修好平均分程序 |
┌─────────────────────────────────────────────────────────┐ │ 一章走完该带走的东西 │ ├─────────────────────────────────────────────────────────┤ │ 学完这一章,兜里该有这些 │ │ │ │ +--------------+------------------------------------+ │ │ |模块 |带走什么 | │ │ +--------------+------------------------------------+ │ │ |类型四家 |整型浮点字符布尔,字节数用 sizeof 验| │ │ |变量常量 |声明即初始化,const 胜过 #define | │ │ |运算符 |整数除法丢小数,位运算只认整数 | │ │ |类型转换 |隐式一路往高转,显式用 static_cast | │ │ +--------------+------------------------------------+ │ │ │ │ 哪一块心里没底,回去找对应小节,别急着往下翻 │ └─────────────────────────────────────────────────────────┘5.2 五句话记住本章
- 类型是图纸,字节数用 sizeof 现算,别背。
- 整数除法丢小数,要小数先把一边转成 double。
- 变量声明就初始化,常量用 const,别用宏。
- ++ 放前放后不一样,别塞进复杂表达式。
- 有符号和无符号别混着比,比就先转成一路的。
5.3 课后练习
- 打印 1.5 节那张 sizeof 表,在自己机器上跑一遍,和书上的数对一遍,long 是几字节。
- 算班级平均分。先用两个 int 相除,再把除数转成 double,对比两次结果,说清差别在哪。
- 输入一个大写字母,输出它的小写形式,提示,大小写编号相差 32。
- 用位运算判断输入的整数是奇数还是偶数,提示,看二进制最低那一位。
- 有 a、b 两个变量,不用第三个变量把两个值换过来。做不出来正常,第三章学完再回头看。
- 挑战题,输入一个 0 到 255 的整数,输出它的二进制写法,提示,从第 7 位开始一位位问过去。
附录|运算符速查卡
| 类别 | 成员 | 一句话提醒 |
|---|---|---|
| 算术 | + - * / % | 整数除法丢小数,% 只认整数 |
| 复合赋值 | += -= *= /= %= | 懒人写法,左右类型不变 |
| 自增自减 | ++ -- | 放前面先加,放后面先用 |
| 关系 | > < >= <= == != | == 是两个等号,写成一个就完蛋 |
| 逻辑 | && 两个竖线 ! | 会短路,判空的写左边 |
| 位运算 | & 单竖线 ^ ~ << >> | 只认整型,判奇偶用 x & 1 |
| 三元 | ? : | 简单场合用,嵌套是灾难 |
| 优先级 | 括号最高,逗号最低 | 不确定就加括号 |