Skip to content

L1-04 数据类型

一个变量要有名字,我们前文已经提到过了,那么我们要想给一个变量申请一部分空间首先要告诉计算机我们要装的东西是什么。就好像我们找妈妈要一个容器装东西,我们必须实现告诉妈妈要装的是什么,是液体,还是固体还是气体,这样妈妈就会给我们找到合适的容器来装。这所谓“液体”,”固体”的物体性质我们迁移到程序变量的性质上,就是数据类型。

我们在之前的变量部分,一直在使用 int 这个类型,作为讲解的示例,除了 intC++ 还有很多种类型可以使用,我们挑选一部分常用的进行介绍。

常见数据类型

单选题

下面关于整型变量声明正确的是(  )。

A. float n;

B. int n;

C. char n;

D. double n;

  • 题解

    选择 B

    类型名称
    布尔型bool
    字符型char
    整型int
    浮点型float
    双精度浮点型double
    无类型void

bool类型

bool类型,只有 truefalse 2 个值。但 bool 会占用 1 个字节的空间。

c++
1. bool flag = true;

char类型

char 类型常用来存储字符。可以存储 0−255 之间的一个数。

c++
1. char n = 'a';

整数类型

int 类型常用来存储整数, 21474836482147483647 之间的整数。 2147483647=2311

可以推算出,存储 21474836482147483647 需要 32bit ,也就是 4 字节的空间。

c++
1. int n = 30000;

浮点类型

单选题

下面数据类型中用于定义小数的是(  )。

A. int

B. double

C. string

D. char

  • 题解

    int   定义整数   存整数 double  定义浮点数  存小数 string   定义字符串  存字符串 char  定义字符    存单个字符 因此选double

double 类型也被称为双精度,可以用来存储小数,占用空间 64bit 。关于 double 存储精度的问题,我们会在以后讲解。

c++
1. double n = 1.001;

字符串类型

string 也是一种常用类型,我们经常用到的 "Hello World!" 就是字符串类型,更多内容我们会在后面讲解。

c++
1. string n = "Hello World!";

数据类型所占空间

单选题

intfloat 类型的数据分别占用 4 和 4 个字节。

A. 正确

B. 错误

  • 题解

    A intfloat 类型的数据分别占用 4 和 4 个字节。

我们所有开辟的变量都会占用系统的内存空间,所谓内存空间我们可以看作“一大片空地”,那么每一个变量因为其类型不同,所占空地的大小也就不同。如果我们不加节制地开变量,那么就会造成“内存溢出”,也就是大片空地装不下了的情况。为了避免这种情况发生,我们更应当熟知各种类型的变量”占地面积“也就是上表中”所占字节“哪一项的值。

类型占用空间数据范围
bool1 个字节0到1
char1 个字节-128 到 127 或者 0 到 255
unsigned char1 个字节0 到 255
signed char1 个字节-128 到 127
int4 个字节-2147483648 到 2147483647
unsigned int4 个字节0 到 4294967295
signed int4 个字节-2147483648 到 2147483647
short int2 个字节-32768 到 32767
unsigned short int2 个字节0 到 65,535
signed short int2 个字节-32768 到 32767
long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
signed long int8 个字节-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
unsigned long int8 个字节0 到 18,446,744,073,709,551,615
float4 个字节精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字)
double8 个字节双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字)
long double16 个字节长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。

单选题

一个 string 类型的变量占用多少空间呢?

A. 1字节

B. 8字节

C. 不确定,要看字符串中保存的内容

D. 不占用任何空间

  • 题解

    选C、一个 string 类型的变量占用空间要看字符串中保存的内容

空间大小解释

换算关系
1字节8 bit
1KB1024 字节
1MB1024 KB
1GB1024 MB
1TB1024 GB

不同的变量类型,在内存中占用的空间不同,具体可以通过系统提供的 sizeof() 来获取某个类型占用空间的大小。

c++
1. cout << "float:" << sizeof(float);
2. cout << "int:" << sizeof(int);

空间大小与数据范围

在上面的类型介绍中,我们看到,一个 char 类型的变量,占用空间是 1 个字节 = 8 bit 。每个 bit 可以表示 0 或 1 两种状态。那么 8 bit 所能表示的信息,共有 28=256 种。所以 char 的数据范围是 0−255 共 256 个不同的编码。

同理 int 占用空间为 4 个字节 = 32 bit ,因此可以表示 232 不同的信息,所以 int 的数据范围是 2312311 。为什么会有减一呢?因为需要保存 0,从 21474836482147483647 正好有 232 个数。

2147483648 大约是 2×109。这也是很多题目,将数据范围限制在 109(1e9) 的原因。

2147483648 看起来是个很大的数字,但在实际运算中,尤其是乘法运算中,很容易超出 int 的数据范围。例如:

c++
1. int a = 100000, b = 110000, c;
2. c = a * b;

用来保存乘法结果的 c 也是 int 类型,而最终的计算结果超出了 int ,这时得出的结果就是错误的。解决这个问题,就需要使用数据范围更大的类型 long long

c++
1. long long a = 100000, b = 110000, c;
2. c = a * b;

这样才能得到正确的计算结果。

整形溢出漏洞

1996 年阿丽亚娜 5 型运载火箭在发射 37 秒后解体并爆炸,事后技术人员及专家分析故障原因,最终发现是由于整数溢出造成的 。

整数溢出会让程序的运行结果出现错误,有时甚至会成为系统的 Bug,有时会成为被攻击的漏洞。

整数溢出的原理是:计算机中整数变量有上下界,如果在算术运算中出现越界,即超出整数类型的最大表示范围,数字便会如表盘上的时针从 12 到 1 一般,由一个极大值变为一个极小值或直接归零。此类越界的情形在传统的软件程序中很常见。

当这个 Bug 进入了交易系统,会形成一个漏洞,在区块链的智能合约中,整形溢出漏洞导致了美链 BEC 价值归零 。

整数溢出漏洞,可造成超额铸币、超额购币、随意铸币、高卖低收、下溢增持等严重危害。我们来看一下其中的原理:

在特定条件下,通过调用合约中有漏洞的发币函数制造下溢,从而实现对自身账户余额的任意增加。

c++
void transfer(int from, int to) {
    balances[from] -= 2000 * 1e8;
    balances[to] += 2000 * 1e8;
}

漏洞攻击效果: from 执行了一个正常向某个地址进行发币的操作,实际已经暗中将自身账户的余额修改为了一个极大的数。

漏洞原理: transfer() 函数的本意是从 fromto 转账一定数额的币 ,并从 from 账户减少对应数量的币。

减少操作为 balances[from]=2000108 ,运算的结果将被存到 balances[from] 中,是一个无符号整数类型。当 from 余额本身少于 2000108 时,减法计算结果为负值,解释为无符号整数即一个极大值。

强制类型转换

强制类型转换也称显示转换,是把变量从一种类型转换为另一种数据类型。例如,如果您想存储一个 long long 类型的值到一个简单的整型中,您需要把 long long 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,如下所示:

c++
long long n = 15555;
double u = 14.5;
int m = (int)n;
int v = (int)u;

注意,类型转换可能会导致部分数据的丢失。例如:

c++
int n = 258;
char v = (char)n; //v = 2

因为 char 只能保存 0−255 之间的数,将一个大于 255 的数付给一个 char 类型的变量,会自动忽略高位,得到 258/256 后的余数。

我们再来回顾一下之前的一段程序:

c++
int a = 100000, b = 110000, c;
c = a * b;

在之前的学习中我们知道,这段程序计算得到的结果是错误的,因为数据范围超过了 int 所能存储的数据范围。

所以我们对程序做了如下改进:

c++
long long  c;
int a = 100000, b = 110000;
c = a * b;

然而这样得到的计算结果仍然是错误的,这时因为两个整数相乘,默认得到的结果也是整数,所以实际执行过程,是先用 int 的方式,计算出 a∗b,再将得到的 int 结果,赋值给 long long 的 c。所以仍然是一个错误的结果。正确的方式应该是:

c++
long long  c;
int a = 100000, b = 110000;
c = (long long)a * b;

我们先强制将 a 转换为 long long ,这样再同 b 进行乘法计算时,也会将 b 自动转为 long long ,之后的计算结果自然也是 long long 。这样就能得到正确的计算结果了。

其中对于 b 的转换,叫做隐式转换,与强制类型转换(显式转换)相对应。

单选题

运行下面这段程序,将会输出 3600000000()?

c++
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n = 60000;
    int m = n * n;
    cout << m;
    return 0;
}

A. 对

B. 错

  • 题解

    错误

    1、因为你的n是int型的,n*n也int类型它超出了int的范围,所以溢出,就变成负数,因此是错的。 2、若把int 改为long long 则是对的

typedef

您可以使用 typedef 为一个已有的类型取一个新的名字。有些类型写起来比较长,我们可以自己来定义,给他起一个较短的名字:

c++
typedef 原来的名字 新名字;

例如:我们可以为 long long 起一个新名字 ll ,下面两段程序执行效果是一样的。

c++
long long n = 10;
c++
typedef long long ll;
ll n = 10;

但是请记住,使用 ll 一定在 typedef 之后,以下程序运行就会报错。

c++
1. ll n = 10;
2. typedef long long ll;

常量

常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。

常量可以是任何的基本数据类型,可分为整型数字、浮点数字、字符、字符串和布尔值。

常量就像是常规的变量,只不过常量的值在定义后不能进行修改。

c++
const int  LENGTH = 10;
const int  WIDTH  = 5;

我们可以使用常量来为变量赋值。

代码练习

课堂练习:启蒙练习-圆的面积

圆是世界上最完美的图形,我们求圆的面积笔算很复杂,用计算器又要每次都输入公式,也不便利,不妨写一个程序来计算圆的面积吧!

圆面积 S 的计算公式为: S=r×r×PI

其中 r 为圆的半径,读入一个浮点数r(带小数点的数),表示圆的半径,取 PI3.14159,输出一个小数表示圆的面积。

输入格式

输入一个浮点数r(带小数点的数)

输出格式

输出一个小数,表示圆的面积

输入样例

c++
1.0

输出样例

c++
3.14159

参考答案

c++
#include <bits/stdc++.h>
using namespace std;
int main() {
  double pi = 3.14159;
  double r;
  cin >> r;
  cout << r * r * pi << endl;
  return 0;
}

题解

分析: PI 为 3.14159 提前给出,应当开常量储存。而读入的浮点数 r ,应该用 double 类型的变量储存。本题主要考察读入输出流的使用以及变量定义的使用方法。

课堂练习:n的平方

已知一个正整数n,请你求出n的平方。

输入格式

输入一个数n。

输出格式

输出n的平方。

输入样例

4

输出样例

16

数据范围

对于100%的数据,1≤n≤10^9;

参考答案

c++
#include <bits/stdc++.h>
using namespace std;
int main() {
  long long n;
  cin >> n;
  cout << n * n << endl;
  return 0;
}

题解

分析: 由于 n 的范围达到了 109 ,当 n>60000 时, n 的平方已经超过了 231 。因此 int 无法保存这么大的数,需要使用 long long 类型来处理数据。