Appearance
L1-04 数据类型
一个变量要有名字,我们前文已经提到过了,那么我们要想给一个变量申请一部分空间首先要告诉计算机我们要装的东西是什么。就好像我们找妈妈要一个容器装东西,我们必须实现告诉妈妈要装的是什么,是液体,还是固体还是气体,这样妈妈就会给我们找到合适的容器来装。这所谓“液体”,”固体”的物体性质我们迁移到程序变量的性质上,就是数据类型。
我们在之前的变量部分,一直在使用 int
这个类型,作为讲解的示例,除了 int
, C++
还有很多种类型可以使用,我们挑选一部分常用的进行介绍。
常见数据类型
单选题
下面关于整型变量声明正确的是( )。
A. float n;
B. int n;
C. char n;
D. double n;
题解
选择 B
类型名称 布尔型 bool 字符型 char 整型 int 浮点型 float 双精度浮点型 double 无类型 void
bool类型
bool
类型,只有 true
、false
2 个值。但 bool
会占用
c++
1. bool flag = true;
char类型
char 类型常用来存储字符。可以存储 0−255 之间的一个数。
c++
1. char n = 'a';
整数类型
int
类型常用来存储整数,
可以推算出,存储
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!";
数据类型所占空间
单选题
int
和 float
类型的数据分别占用 4 和 4 个字节。
A. 正确
B. 错误
题解
A
int
和float
类型的数据分别占用 4 和 4 个字节。
我们所有开辟的变量都会占用系统的内存空间,所谓内存空间我们可以看作“一大片空地”,那么每一个变量因为其类型不同,所占空地的大小也就不同。如果我们不加节制地开变量,那么就会造成“内存溢出”,也就是大片空地装不下了的情况。为了避免这种情况发生,我们更应当熟知各种类型的变量”占地面积“也就是上表中”所占字节“哪一项的值。
类型 | 占用空间 | 数据范围 |
---|---|---|
bool | 1 个字节 | 0到1 |
char | 1 个字节 | -128 到 127 或者 0 到 255 |
unsigned char | 1 个字节 | 0 到 255 |
signed char | 1 个字节 | -128 到 127 |
int | 4 个字节 | -2147483648 到 2147483647 |
unsigned int | 4 个字节 | 0 到 4294967295 |
signed int | 4 个字节 | -2147483648 到 2147483647 |
short int | 2 个字节 | -32768 到 32767 |
unsigned short int | 2 个字节 | 0 到 65,535 |
signed short int | 2 个字节 | -32768 到 32767 |
long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
signed long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long int | 8 个字节 | 0 到 18,446,744,073,709,551,615 |
float | 4 个字节 | 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字) |
double | 8 个字节 | 双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字) |
long double | 16 个字节 | 长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。 |
单选题
一个 string
类型的变量占用多少空间呢?
A. 1字节
B. 8字节
C. 不确定,要看字符串中保存的内容
D. 不占用任何空间
题解
选C、一个
string
类型的变量占用空间要看字符串中保存的内容
空间大小解释
换算关系 | |
---|---|
1字节 | 8 bit |
1KB | 1024 字节 |
1MB | 1024 KB |
1GB | 1024 MB |
1TB | 1024 GB |
不同的变量类型,在内存中占用的空间不同,具体可以通过系统提供的 sizeof()
来获取某个类型占用空间的大小。
c++
1. cout << "float:" << sizeof(float);
2. cout << "int:" << sizeof(int);
空间大小与数据范围
在上面的类型介绍中,我们看到,一个 char
类型的变量,占用空间是 1 个字节 = 8 bit 。每个 bit 可以表示 0 或 1 两种状态。那么 8 bit 所能表示的信息,共有
同理 int
占用空间为 4 个字节 = 32 bit ,因此可以表示 int
的数据范围是
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;
}
漏洞攻击效果:
漏洞原理:
减少操作为
强制类型转换
强制类型转换也称显示转换,是把变量从一种类型转换为另一种数据类型。例如,如果您想存储一个 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;
我们可以使用常量来为变量赋值。
代码练习
课堂练习:启蒙练习-圆的面积
圆是世界上最完美的图形,我们求圆的面积笔算很复杂,用计算器又要每次都输入公式,也不便利,不妨写一个程序来计算圆的面积吧!
圆面积
其中
输入格式
输入一个浮点数
输出格式
输出一个小数,表示圆的面积
输入样例
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 的范围达到了 int
无法保存这么大的数,需要使用 long long 类型来处理数据。