2.1数据类型
基础定义:数据类型是编程语言用来区分和分类不同种类的数据的一种方式。在计算机中就有许多的数据信息,诸如图像、字符,声音,视频等。那么计算机在处理这些数据时,不同的数据类型类型由不同的处理方式,以及存储方式。同样在编程语言当中,每种数据类型定义了数据结构的存储方式,以及可以对该数据执行的操作。
在C语言中,数据类型是用来定义变量可以存储哪些类型的数据以及这些数据占用多少内存空间的。以下是C语言中一些常见数据类型的介绍:
2.1.1基本数据类型
1. 整型 (Integers)
- `int`: 基本整型,通常占用4个字节(32位系统)或2个字节(16位系统),范围取决于系统和编译器。
- `short`: 短整型,通常占用2个字节。
- `long`: 长整型,通常占用4个字节(32位系统)或更多(64位系统)。
- `unsigned int`: 无符号整型,可以存储非负整数,范围是正整数。
2. 浮点型 (Floating-Point)
- `float`: 单精度浮点型,占用4个字节,有效数字约6-7位。
- `double`: 双精度浮点型,占用8个字节,有效数字约15-16位。
- `long double`: 扩展精度浮点型,占用的空间和精度依赖于编译器,通常比`double`类型更大。
3. 字符型 (Character)
- `char`: 字符型,占用1个字节,用于存储单个字符(ASCII码)。
2.1.2构造数据类型
1. 数组 (Arrays)
- 用于存储相同类型的数据集合,如 `int arr[10];` 表示一个可以存储10个整数的数组。
2. 结构体 (Structures)
- 允许你将不同类型的数据组合成一个单一的数据类型,如:
```c
struct Student {
char name[50];
int age;
float score;
};
```
3. 联合体 (Unions)
- 类似于结构体,但所有成员共享同一块内存区域,如:
```c
union Data {
int i;
float f;
char str[4];
};
```
4. 枚举 (Enumerations)
- 允许你为整型常量定义一组命名的值,如:
```c
enum Color {
RED,
GREEN,
BLUE
};
```
2.1.3指针类型
- `*var`: 指针变量,存储变量地址,如 `int *ptr;` 表示一个指向整数的指针。
2.1.4位字段 (Bit Fields)
- 可以在结构体中定义,用于精确控制内存的位分配,如:
```c
struct BitField {
unsigned int flag : 1;
unsigned int value : 4;
};
```
2.1.5存储类说明符
- `static`: 用于限制变量的作用域或函数的可见性。
- `extern`: 用于声明变量或函数是在其他地方定义的。
- `auto`: 通常用于局部变量,默认情况下所有局部变量都是`auto`类型。
- `register`: 建议编译器将变量存储在寄存器中,但实际上现代编译器通常忽略这个关键字。
2.1.6类型限定符
- `const`: 定义常量,一旦初始化后,其值不能被修改。
- `volatile`: 告诉编译器该变量可能会在程序的控制之外被修改,如硬件设备。
这些涵盖了C语言中的基本数据类型和一些构造数据类型,以及它们的特点和用法。在编写C语言程序时,选择合适的数据类型对于内存管理和程序性能至关重要。
2.1.7进制与进制转换
2.1.7.1进制
进制时一种计数机制,它可以使用有限的数字符号代表所有的数值。“X”进制表示某一位置上的数在运算时逢“X”进一位。例如十进制基数为10,数码由0~9组成,计数机制时“逢十进一”。在计算机中,对于任何一个数,除了十进制外,还常用二进制、八进制和十六进制表示。
2.1.7.1二进制
二进制由0和1两个数码组成,计数机制是“逢二进一”。例如使用二进制表示十进制数2时,个位上的数字为2,逢二进一应将第2位上的数字置为1,此时个位上的数字减去2变为0,即(10)。
2.1.7.2八进制
八进制由0~7八个数码组成,计数机制是“逢八进一”。在C语言中为数字添加前缀数字0,以表示八进制数。例如使用八进制表示十进制数8时,逢八进一,应将第2位上的数字置为1,个位上的数字是8-8=0,因此表示为010.同理,使用八进制表示十进制数17时,因为17=2*8+1,应将第二位上的数字置为2,个位上的数字是17-2*8=1,因此表示为021。
2.1.7.3十六进制
十六进制由0~9,A~F(或a~f,分别对应十进制的10~15)共16个数码组成,计数机制是“逢十六进一”。在C语言中为数字添加前缀数字0和字母X(或x)以表示十六进制数。例如使用十六进制表示十进制数16时,逢十六进一,应将第二位上的数字置为1,此时个位上的数字是16-16=0,因此表示为0x10。同理,使用十六进制表示十进制数45时,因为45=2*16+13,应将第二位上的数字置为2,个位上的数字是45-2*16=13,对应的十六进制数是D,因此表示为0x2D.
十进制数0~15与二进制数、八进制数、十六进制数,的对应关系表如下:
十进制数 | 二进制数 | 八进制数 | 十六进制数 |
0 | 0000 | 0 | 0 |
1 | 0001 | 1 | 1 |
2 | 0010 | 2 | 2 |
3 | 0011 | 3 | 3 |
4 | 0100 | 4 | 4 |
5 | 0101 | 5 | 5 |
6 | 0110 | 6 | 6 |
7 | 0111 | 7 | 7 |
8 | 1000 | 10 | 8 |
9 | 1001 | 11 | 9 |
10 | 1010 | 12 | A |
11 | 1011 | 13 | B |
12 | 1100 | 14 | C |
13 | 1101 | 15 | D |
14 | 1110 | 16 | E |
15 | 1111 | 17 | F |
2.1.8进制转换
在计算机中,不管用哪种进制形式来表示数据,数据本身是不会发生变化的。因此,不同的进制的数据是可以转换的。
进制间的转换是计算机科学和数学中的一个基本技能,尤其是在处理数字系统和编程时。以下是二进制、八进制、十进制和十六进制之间转换的基本方法:
2.1.8.1N进制转十进制
方法:数码乘以位权之和
数码:组成进制的数字
位权:整数部分从右向左每个数字对应的位权分别为0、1、2、3...
小数部分从左向右每个数字对应的位权分别为-1、-2、-3...
示例:
### 二进制 `11010011.101` 转换为十进制:
分位权:-整数部分从右向左二进制数 `11010011`对应的位权分别为:
1 1 0 1 0 0 1 1
| | | | | | | |
7 6 5 4 3 2 1 0
小数部分对应的位权分别为:
1 0 1
| | |
-1 -2 -3
位权乘以数码:
整数部分:1*2^0=1、1*2^1=2、0*2^2=0、0*2^3=0、1*2^4=16、0*2^5=0、1*2^6=64、1*2^7=128
小数部分:1*2^(-1)=0.5、0*2^(-2)=0、1*2(-3)=0.125
求和:1+2+0+0+16+0+64+128+0.5+0+0.125=211.625
所以二进制`11010011.101`对应的十进制数为211.625
### 八进制`654.28`转十进制
分位权:-整数部分从右向左八进制数`654`对应的位权分别为:
6 5 4
| | |
2 1 0
小数部分对应的位权分别为:
2 8
| |
-1 -2
位权乘以数码:
整数部分:4*8^0=4、5*8^1=40、6*8^2=384
小数部分:2*8^(-1)=0.25、8*8^(-2)=0.125
求和:4+40+384+0.25+0.125=428.375
所以八进制数`654`对应的十进制数为428.375
### 十六进制`32D`转十进制数(因十六进制小数所涉及的位数太多,这里不做示范,如遇到,同理)
分位权:-从右向左十六进制数`32D`对应的位权为:(在这里D所表示的数字为13)
3 2 13
| | |
2 1 0
位权乘以数码:13*16^0=13、2*16^1=32、3*16^2=768
求和:13+32+768=813
所以十六进制数`32D`对应的十进制数为813
2.1.8.2十进制转N进制
方法:整数部分除以N反向取余,小数部分乘以N正向取整
示例:
将十进制数50.2转换为二进制数,分为整数部分和小数部分的转换。
首先,我们转换整数部分50,然后转换小数部分0.2。
### 整数部分(50)转换为二进制:
1. 除以2:将50除以2,得到商25余0。
2. 记录余数:当前余数是0。
3. 更新数值:将原来的除数25作为新的数值。
4. 重复步骤:继续将新的数值25除以2,得到商12余1。
5. 继续记录余数:当前余数是1。
6. 继续更新数值:将原来的除数12作为新的数值。
7. 继续重复步骤:按照上述步骤,继续进行除法和记录余数,直到商为0。
按照这个过程,我们可以得到以下的除法和余数序列:
```
50 / 2 = 25 ... 余数 0
25 / 2 = 12 ... 余数 1
12 / 2 = 6 ... 余数 0
6 / 2 = 3 ... 余数 0
3 / 2 = 1 ... 余数 1
1 / 2 = 0 ... 余数 1
```
2. 逆序排列余数:将余数逆序排列,得到二进制表示。
整数部分50的二进制表示为:`110010`
### 小数部分(0.2)转换为二进制:
1. 乘以2:将0.2乘以2,得到0.4。
2. 取整数部分:取乘法结果的整数部分,这里是0。
3. 记录小数部分:将乘法结果的小数部分保留下来,继续下一步乘法。
4. 重复步骤:继续将小数部分乘以2,并重复上述步骤,直到得到0或达到所需的精度。
按照这个过程,我们可以得到以下的乘法和整数部分序列:
```
0.2 * 2 = 0.4 ... 整数部分 0
0.4 * 2 = 0.8 ... 整数部分 0
0.8 * 2 = 1.6 ... 整数部分 1
0.6 * 2 = 1.2 ... 整数部分 1
0.2 * 2 = 0.4 ... 整数部分 0
```
2. 组合整数部分:将得到的整数部分组合起来,形成二进制小数。
小数部分0.2的二进制表示为:`0011`(这里我们只取了前几位以形成近似值)
### 综合结果:
将整数部分和小数部分的二进制表示组合起来,得到十进制数50.2的二进制表示:
`110010.0011`
这就是十进制数50.2转换为二进制的结果。请注意,由于二进制和十进制之间的转换可能会有无限循环或无法精确表示的情况,所以这里的二进制表示是一个近似值。
将十进制数50.2转换为八进制数
1. 将整数部分转换为八进制:通过不断地将十进制的整数部分除以8,并记录余数,然后将这些余数反向排列,得到八进制的整数部分。
2. 将小数部分转换为八进制:将十进制的小数部分乘以8,取整数部分作为八进制小数的第一位,然后用剩下的小数部分(去掉已经取过的整数部分)继续乘以8,重复此过程,直到达到所需的精度或者小数部分变为0。
现在,让我们将十进制数50.2转换为八进制数。
### 整数部分(50)转换为八进制:
1. 50 ÷ 8 = 6 余 2
2. 6 ÷ 8 = 0 余 6
将余数反向排列,我们得到八进制整数部分为:62。
### 小数部分(0.2)转换为八进制:
1. 0.2 * 8 = 1.6,取整数部分1,小数部分为0.6。
2. 0.6 * 8 = 4.8,取整数部分4,小数部分为0.8。
3. 0.8 * 8 = 6.4,取整数部分6,小数部分为0.4。
4. 0.4 * 8 = 3.2,取整数部分3,小数部分为0.2(此时已经回到了起始值,可以停止计算或者继续取值直到达到精度要求)。
将这些整数部分排列起来,我们得到八进制小数部分为:14(这里我们只取了前几位作为近似值)。
综合整数部分和小数部分,十进制数50.2转换为八进制数为:62.14。请注意,这里的小数部分是一个近似值,因为八进制和十进制之间的转换可能会导致无限循环或者无法精确表示的情况。
将十进制数 50.2 转换为十六进制,我们需要分别处理整数部分和小数部分。
### 整数部分(50)转换为十六进制:
1. 50 除以 16 等于 3 余 2,所以最低位(右边)是 2。
2. 然后我们用商 3 除以 16,得到 0 余 3,所以下一位是 3。
3. 由于商已经为 0,我们停止计算。
所以,整数部分 50 的十六进制表示为 32。
### 小数部分(0.2)转换为十六进制:
十六进制使用基数 16,所以我们需要将小数部分乘以 16 的幂,直到得到一个整数或者达到一定的精度要求。
1. 0.2 乘以 16 等于 3.2,取整数部分 3 作为结果的第一位,同时将 0.2 保留下来继续计算。
2. 0.2 乘以 16 等于 3.2,再次取整数部分 3 作为结果的下一位。
由于小数部分继续乘以 16 仍然是 0.2,我们可以继续这个过程,但由于这将是一个无限循环的小数,我们通常会在达到一定的精度后停止计算。在这个例子中,我们可以将 0.2 近似为 0.3(因为 0.3 乘以 16 等于 4.8,取整数部分 4),但这会使得结果有轻微的偏差。
所以,小数部分 0.2 的近似十六进制表示为 0.3(或者更精确地说,是 0.4,取决于所需的精度)。
### 综合起来:
十进制数 50.2 的十六进制表示大约为 32.3(或者更精确地说,是 32.4,取决于小数部分的精度要求)。
这就是十进制数 50.2 转换为十六进制的过程和结果。