在编写程序时,我们会遇到各种各样的数据:比如年龄 20 是整数,身高 1.75 是小数,等级 'A' 是单个字符,而 “是否已登录” 则只有真和假两种状态。
在 C++ 中,所谓的 “数据类型”,说白了就是变量的 “值” 的类型。我们在定义变量时写出数据类型,是为了告诉编译器:这个数据属于哪一类,应该分配多大的内存空间、按照什么规则去保存和运算。
C++ 提供了丰富的数据类型,刚入门时小伙伴们完全没必要一口气全背下来。现阶段我们先重点掌握以下 4 种最常用的基础数据类型就可以了:
- 整数类型(int):用来表示没有小数部分的整数。
- 浮点类型(double):用来表示带有小数部分的数字。
- 字符类型(char):用来表示单个英文字符或符号。
- 布尔类型(bool):用来表示 “真” 或 “假” 两种状态。
C++ 基础数据类型
在日常编写基础程序时,int、double、char 和 bool 是出场率最高的 4 种基础数据类型,下面我们结合具体示例来看看它们的用法。
1. 整数类型(int)
在 C++ 中,整数类型也叫做 “整型”。其中 int 是英文单词 “integer(整数)” 的缩写,专门用来保存没有小数部分的数,包括正整数、0 和负整数。像平时常见的商品数量、考试分数、零下温度等整数数据,我们通常都优先使用 int。
示例 1:使用 int 类型
#include <iostream>
int main() {
int count = 12;
int temperature = -5;
std::cout << count << " " << temperature;
return 0;
}运行结果如下。
12 -5分析:
在这个例子中,我们使用 int 定义了两个整型变量:count 保存正整数 12,temperature 保存负整数 -5。像这样直接写在代码里的 12、-5 等具体数值,在编程中也叫做 “字面量”。
需要注意的是,int 能表示的整数范围并不是无限大的。在主流 64 位电脑上,int 通常能表示约 -21 亿到 +21 亿之间的整数,应付日常普通整数已经完全够用了。至于超出范围会发生什么,我们会在下面第二小节具体演示。
2. 浮点类型(double)
在 C++ 中,浮点数类型也叫做 “浮点型”,指的是带有小数部分的数字,比如身高 1.75、商品单价 19.8、圆周率 3.1415926 等。日常开发中最常用的小数类型是双精度浮点型(double)。
示例 2:使用 double 类型
#include <iostream>
int main() {
double height = 1.75;
double pi = 3.1415926;
std::cout << height << " " << pi;
return 0;
}运行结果如下。
1.75 3.14159分析:
这里我们定义了 height 和 pi 两个 double 变量来保存小数。细心的小伙伴可能会好奇:pi 赋的值明明是 3.1415926,为什么屏幕上只打印出了 3.14159 呢?
其实 pi 在内存中依然完整保存着 3.1415926,只是 std::cout 默认最多显示 6 位有效数字,并且像 3.0 这样小数部分为 0 的数会默认显示成 3。如果需要指定小数点后保留几位,可以配合输出格式化工具来实现。
另外要注意,千万不要把带有小数的数字误赋给 int 整型变量。由于 int 无法保存小数部分,小数点后面的 .75 会直接丢失,变量里最终只剩下整数 1:
int height = 1.75; // 小数部分丢失,结果变成 1在 C++ 的浮点类型家族里,除了 double 之外,还有单精度浮点型(float)和扩展精度浮点型(long double):
float speed = 3.5f; // 单精度,末尾常加 f
double height = 1.75; // 双精度(推荐)
long double distance = 100.0L; // 扩展精度,末尾常加 L代码里直接写出的小数字面量默认就是 double 类型,末尾加上后缀 f 或 L 则分别表示 float 或 long double。由于 double 约有 15 位有效数字精度,远高于 float 的 6~7 位,平时表示小数统一优先使用 double 即可。
注意 浮点数在计算机底层采用二进制近似保存,存在微小的精度误差。比如计算 0.1 + 0.2 时,底层结果可能是 0.30000000000000004,因此平时不要直接判断两个浮点数是否完全相等。
3. 字符类型(char)
在 C++ 中,char 是英文单词 “character(字符)” 的缩写,用来保存单个字符,比如一个英文字母 'A'、一个数字字符 '7' 或一个英文符号 '#'。书写字符字面量时,必须使用一对英文单引号括起来。
示例 3:使用 char 类型
#include <iostream>
int main() {
char grade = 'A';
char symbol = '#';
std::cout << grade << " " << symbol;
return 0;
}运行结果如下。
A #分析:
'A' 和 '#' 都是单个字符,并且用英文单引号括了起来。可能有些小伙伴会问:“数字字符 '7' 和整数 7 有什么区别呢?” 其实,不加引号的 7 是整数,可以直接参与加减乘除。而加了单引号的 '7' 只是代表字符符号,不能直接当成整数 7 去算数学题。
在使用 char 类型时,我们需要避开下面两种常见错误:
// 正确方式
char grade = 'A';
// 错误方式
char grade = "A"; // 不能使用双引号
char grade = 'AB'; // 只能保存单个字符在 C++ 中,单引号和双引号的含义完全不同:'A' 表示单个字符,而 "A" 表示字符串,两者不能混用。同时日常我们只使用 char 保存英文字母、数字字符和英文符号,不要把 '中' 这样的中文汉字放进 char 里,因为一个中文汉字占多个字节,单个 char 装不下。
这里还可以顺便了解一个常识:计算机内存只认识数字,所以每个英文字符在底层都对应一个固定的整数编号,叫做 “ASCII 码”。比如 'A' 对应 65,'a' 对应 97,'0' 对应 48,因此 char 在底层也算作一种特殊的整数类型。
4. 布尔类型(bool)
布尔是英文 “boolean” 的音译,是以英国数学家乔治·布尔(George Boole)的名字来命名的。在程序中,有些数据表示的不是 “具体有多少”,而是 “是不是” 或 “成不成立”,比如用户是否已登录、任务是否已完成、考试是否及格。
这类只有两种状态的数据,在 C++ 中就使用 bool 类型来表示。bool 类型的值只有 2 个:true 表示 “真”,false 表示 “假”,书写时字母必须全部小写。
示例 4:使用 bool 类型
#include <iostream>
int main() {
bool isLoggedIn = true;
bool isFinished = false;
std::cout << isLoggedIn << " " << isFinished;
return 0;
}运行结果如下。
1 0分析:
从运行结果可以看出,isLoggedIn 的值是 true,isFinished 的值是 false,但屏幕上输出的却是 1 和 0。这是因为使用 std::cout 直接输出 bool 变量时,C++ 默认用数字 1 表示 true,用数字 0 表示 false。
整数类型家族与数据溢出
我们在阅读其他 C++ 代码时,可能还会见到 short、long、long long 等类型名。既然 int 已经能保存整数了,为什么 C++ 还要提供这么多整数类型呢?
这主要是为了适应不同大小的数值范围需求。常见整数类型的区别如下表所示。
| 数据类型 | 常见大小 | 大致范围 | 使用建议 |
|---|---|---|---|
| short(短整型) | 2 个字节 | -32768 ~ 32767 | 范围较小,日常较少单独使用 |
| int(整型) | 4 个字节 | 约 -21 亿 ~ +21 亿 | 最常用,普通整数统一优先使用 |
| long(长整型) | 4 或 8 个字节 | 随系统平台变化 | 跨平台大小不固定,大整数推荐用 long long |
| long long(超长整型) | 8 个字节 | 约 -922 亿亿 ~ +922 亿亿 | 当整数可能超过 21 亿时使用 |
每种整数类型都有固定的取值上限。一旦存入的整数超出了该类型的最大范围,就会发生 “数据溢出”,算出意想不到的错误结果。我们先拿范围较小的 short 类型(最大值为 32767)来看一个例子。
示例 5:整数的数据溢出
#include <iostream>
int main() {
short num = 32767;
num = num + 1;
std::cout << num;
return 0;
}运行结果如下。
-32768分析:
short 类型的最大取值是 32767。当我们在 32767 的基础上再加 1 时,32768 超出了 short 能承受的上限,触发了数据溢出,结果直接绕回变成了负数 -32768。
对于整数溢出,程序在运行时通常不会给出任何报错提醒。因此,当遇到可能超过 21 亿的大整数,比如保存约 81 亿的全球总人口时,我们就不能再使用 int 了,而应该换用范围更大的 long long 类型。
示例 6:使用 long long 保存大整数
#include <iostream>
int main() {
long long population = 8100000000LL;
std::cout << population;
return 0;
}运行结果如下。
8100000000分析:
long long population = 8100000000LL; 定义了一个超长整型变量来保存 81 亿。数字末尾加上的后缀 LL 用来告诉编译器这是一个 long long 类型的整数字面量。这里虽然写成小写的 ll 也可以,但更推荐写大写的 LL,以免与数字 1 看混。
此外,整数类型还可以细分为有符号(signed)和无符号(unsigned)两类。平时直接写 int 或 long long 默认就是有符号整数,可以表示正数、0 和负数。如果在前面加上 unsigned(如 unsigned int),则只能保存 0 和正整数。
初学阶段大家只需要记住一条简单的选型原则:普通整数优先使用 int,超过 21 亿的大整数使用 long long。不要因为年龄、人数不会为负就刻意改成 unsigned int,因为无符号数在减法中一旦小于 0(如计算 0 - 1),会瞬间绕回变成几十亿的巨大正数而引发错误。
至于不同类型在当前电脑上具体占用多少个字节,可以使用 sizeof 运算符直接查出来,现阶段不需要死记硬背。
常见问题
1. 如果想保存一串文字,比如姓名或一句话,应该使用什么数据类型?
前面学习的 char 类型只能保存单个字符,比如 'A'。如果需要保存 "Jack" 或 "Hello, lvyenet!" 这样的一串文字,应该使用标准库提供的 std::string 字符串类型,并在代码开头引入 <string> 头文件。
