| 
                             
                              | 
                                   
                                    | 编辑推荐: |   
                                    | 本文来自于csdn,本文主要介绍了C 
                                      语言 4 大数据类型,其最初的目的就是为了能够让程序更加充分的利用稀缺的内存空间,希望对您的学习有所帮助。 |  |   C 语言的数据类型  数据类型,即数据对象的类型,是编程语言的基石,自编程语言发明以来,数据类型就已经存在。  在硬件行业严格遵守摩尔定律发展了多年后的今天,开发者得以享受充足内存资源,同时,数据类型也被赋予了更深厚的含义:  1.确定数据对象占用的内存空间大小  2.确定数据对象的数值范围  3.规定数据对象所能进行的操作(行为)  EXAMPLE:基本整型数据对象占用 4 Bytes(32 Bits) 
                            的内存空间, 数值范围是 0x0~0xFFFF FFFF,可以进行求余运算。   NOTE:需要注意的是,类型数据对象所占用的内存空间和数值范围,除了取决于 
                            C 语言本身的常规定义之外,还可能会受到编译器的影响。  C 语言 4 大数据类型:  1.基本数据类型  2.派生数据类型  3.指针类型  4.空类型 
 常量与变量  C/C++ 中,数据具有 “常量/变量” 两种表现形式。首先来看,何为常量?何为变量?  常量:指的是在程序运行过程中其数据值不可更改的量。e.g.  整型常量:即整数  浮点型常量:又称为实型常量,即小数,可使用小数或指数形式来表示  字符型常量:即符号,用单引号括起来的一个字符,具有一般字符和转义字符两种类型  字符串常量:即用双引号括起来的多个字符组成的字符序列  符号常量:即对常量进行命名,所以字符常量即是常量名,使用 const 
                            或 #define 来定义  变量:表示一个具有名字的,具有特定属性的存储空间。在程序运行过程中该存储空间内的数据值可以被改变。变量具有下列三个要素:  1.变量名  2.数据类型  3.数据值  基本数据类型  基本数据类型清单,如下图: 
 EXAMPLE: 创建一个基本整型变量 
                             
                              | // 声明定义并初始化一个「有符号」基本整型变量 
                                aInt ,初始化为 1 int aInt = 1;
 // 声明定义并初始化一个「无符号」基本整型变量 uaInt ,初始化为 1unsigned int uaInt = 1;
 |   无符号数据类型与有符号数据类型的区别:  占用相同的内存空间,但表示数值范围不同  有符号和无符号仅可用于修饰整型或字符型数据对象  EXAMPLE:若 unsigned char 和 signed 
                            char 都占用 1 Byte 的内存空间。signed char 的数值范围为 -128~127,而 
                            unsigned char 的数据范围为 0~255。这是因为有符号数据类型数据的最高位被用作为符号位,而无符号的数据类型数据最高位被用作为数据位。  派生数据类型  数组  定义:具有相同数据类型,并且按照一定顺序排列的一组变量的集合。  特征:  有序性:数组元素之间具有固定的先后顺序  可索引:通过数组名和下标可以唯一地确定数组中的元素  创建一维数组的语法格式: 
                             
                              | // 其中 [] 为下标运算符 数据类型 数组名[常量表达式]
 |   EXAMPLE: 
                             
                              | // 例:创建 1 维数组: int aArray[5] = {1, 2, 3, 4, 5};
 |   NOTE:  [常量表达式] 不可为变量,C/C++ 不允许对数组的长度做动态定义  的作用:  数组名除了作为数组辨识名称(display_name)之外,也表示了该数组存储空间的首地址,即数组名本身就是数组的内存入口地址  一次只能使用数组中的单个元素,而不能一次使用整个数组 
                             
                              | // 正确用法:一次只能使用数组中的单个元素。 // 将 aArray 的数据复制到 bArray 中。
 int aArray[5] = {1, 2, 3, 4, 5};
 int bArray[5] = {0};
 for(int i = 0; i < 5; i++)
 {
 bArray[i] = aArray[i];
 }
 // 错误用法:
 int aArray[5] = {1, 2, 3, 4, 5};
 int bArray[5] = {0};
 bArray = aArray; //不可给整个数组赋值
 |   NOTE:需要注意的是,使用数组时,需要主动的对数组变量进行边界检查。C/C++ 
                            在编译时并没有缺省的边界检查动作,所以在程序运行过程,当数组下标索引值越界时,并不会立即触发错误,存在潜在的逻辑异常风险。 
                             
                              | // 如下例所示,aArray[i*j] 
                                在程序进行过程中,下标会超出其数组大小。 // 但是在编译和运行过程中,并不会报错,因此必须由编程人员对此边界进行处理!
 int main(void)
 {
 int i, j;
 int aArray[5] = {1, 2, 3, 4, 5};
 for (i = 0; i < 5; i++)
 {
 for (j = 0; j < 5; j++)
 {
 aArray[i * 5 + j] = i * 5 + j;
 printf("aArray[%d]=%d\r\n", i * 5 + 
                                j, aArray[i * 5 + j]);
 }
 }
 return 0;
 }
 // 上错误示例可改为:
 // 当然像示例中的简单数组越界在编程过程中是十分容易避免的,但对于复杂度高的问题,必须是要增加边界检查的。
 int main(void)
 {
 int i, j, idx;
 int aArray[5] = {1, 2, 3, 4, 5};
 for (i = 0; i < 5; i++)
 {
 for (j = 0; j < 5; j++)
 {
 idx = i * 5 + j;
 if (idx > sizeof(aArray) / sizeof(int))
 {
 printf("Err: idx over range!\r\nMax idx = 
                                %d,idx=%d\r\n", sizeof(aArray) / sizeof(int), 
                                idx);
 return 0;
 }
 aArray[idx ] = idx ;
 printf("aArray[%d]=%d\r\n", idx , aArray[idx]);
 }
 }
 return 0;
 }
 |  
 结构体  定义:由一系列具有相同或不同数据类型的变量构成的集合。  自定义结构体数据类型语法格式: 
                             
                              | // struct 关键字用于定义结构体数据类型 struct 结构体名称
 {
 数据类型 成员名1;
 数据类型 成员名2;
 ...
 数据类型 成员名N;
 };
 |   EXAMPLE: 
                             
                              | // 定义一个 student 
                                结构体类型 // 此时只是声明定义了一个结构体类型,并非实际创建了一个结构体类型变量
 struct student
 {
 int num;
 char name[20];
 float score;
 }
 |   创建结构体类型变量的 3 种方式:  直接创建:在声明定义结构体类型的同时创建结构体变量 
                             
                              | // 例:在定义了 student 
                                结构体类型的同时, // 也创建了 zhao, wang, li 三个 student 型的结构体变量。
 struct student
 {
 int num;
 char name[20];
 float score;
 }zhao, wang, li;
 |   间接创建:先声明定义结构体类型,再另外创建结构体变量 
                             
                              | // 声明定义 struct student
 {
 int num;
 char name[20];
 float score;
 };
 // C++ 中,struct 关键字可省略,而 C 中,struct 关键字不可省略
 struct student zhao, wang, li;
 |   无名创建:当使用直接创建方式时,可以省略结构体类型名,所以称为无名创建 
                             
                              | // 注意,由于省略了结构体类型名,因而以后不能再用该结构类型创建其他不同的变量 struct
 {
 int num;
 char name[20];
 float score;
 }zhao, wang, li;
 |   访问结构体成员: 
                             
                              | // 句点符号 "." 
                                作为成员运算符,用于访问一个结构体变量中的某个成员 // 结构体变量名.成员名
 zhang.name
 |   联合体  定义:联合体,又称为共用体,可使用几个不同类型的变量共同使用同一段内存空间。  自定义联合体类型的格式: 
                             
                              | union 联合体类型名 {
 数据类型 成员名1;
 数据类型 成员名2;
 ...
 数据类型 成员名n;
 };
 |   EXAMPLE: 
                             
                              | // 创建联合体类型 SizeUnion union SizeUnion
 {
 char a8;
 int b32;
 long int c64;
 };
 |   创建 SizeUnion 联合体变量 TransDatas:  访问联合体的变量成员的语法格式: 
                             
                              | 联合体成员.成员名 // 
                                联合体变量 联合体成员->成员名 // 指向联合体类型的指针变量
 |   EXAMPLE:声明定义联合体类型 SizeUnion ,创建联合体类型 
                            SizeUnion 的变量 TransDatas,然后对 TransDatas 联合体的成员进行赋值 
                             
                              | union SizeUnion {
 char a8;
 short int b16;
 int c32;
 };
 SizeUnion TransDatas;
 int main(void)
 {
 TransDatas.c32 = 0x90987654;
 printf("Part1: Set TransDatas.c32 = 0x90987654\r\n");
 printf("TransDatas.c32 = 0x%x\r\n", 
                                TransDatas.c32);
 printf("TransDatas.b16 = 0x%x\r\n", 
                                TransDatas.b16);
 printf("TransDatas.a8 = 0x%x\r\n\r\n", 
                                TransDatas.a8);
 TransDatas.b16 = 0x1111;
 printf("Part2: Set TransDatas.b16 = 0x1111\r\n");
 printf("TransDatas.c32 = 0x%x\r\n", 
                                TransDatas.c32);
 printf("TransDatas.b16 = 0x%x\r\n", 
                                TransDatas.b16);
 printf("TransDatas.a8 = 0x%x\r\n\r\n", 
                                TransDatas.a8);
 TransDatas.a8 = 0x22;
 printf("Part3: Set TransDatas.a8 = 0x22\r\n");
 printf("TransDatas.c32 = 0x%x\r\n", 
                                TransDatas.c32);
 printf("TransDatas.b16 = 0x%x\r\n", 
                                TransDatas.b16);
 printf("TransDatas.a8 = 0x%x\r\n\r\n", 
                                TransDatas.a8);
 return 0;
 }
 |   输出结果: 
 NOTE:  联合体变量包含的成员都占用同一块内存空间。各成员使用同一个起始地址。但在某个瞬间,只能有一个成员生效,即内存空间同一时间只会存放一个成员的数据值。  联合体变量中的一个成员被赋值后,原有变量成员的数据就会被冲掉。若连续为各个成员进行赋值,那么只有最后一个被赋值的成员的数据值有效。  联合体变量不能作为函数参数,函数也不能返回联合体类型,但指向联合体变量的指针变量可以作为函数参数,函数也可以返回联合体类型指针变量。  枚举类型  定义:一个整型常量的集合,列举出可被访问的值的范围,所谓 “枚举” 
                            就是把可能出现的值一一列举出来。  自定义枚举类型语法格式: 
                             
                              | // enum 关键字用于定义枚举类型 enum 枚举类型名
 {
 枚举元素1[=整型常量1],
 枚举元素2[=整型常量2],
 ...
 枚举元素n[=整型常量n]
 };
 |   创建枚举类型变量的语法格式:  EXAMPLE: 
                             
                              | // 创建枚举类型 Statusenum enum Statusenum
 {
 A_Status = 1,
 B_Status = 2,
 C_Status,
 D_Status,
 E_Status,
 };
 int main(void)
 {
 Statusenum Status; // 创建枚举类型变量 Status
 Status = A_Status;
 printf("Status = %d, A_Status = %d\r\n", 
                                Status, A_Status);
 Status = B_Status;
 printf("Status = %d, B_Status = %d\r\n", 
                                Status, B_Status);
 Status = C_Status;
 printf("Status = %d, C_Status = %d\r\n", 
                                Status, C_Status);
 Status = D_Status;
 printf("Status = %d, D_Status = %d\r\n", 
                                Status, D_Status);
 Status = E_Status;
 printf("Status = %d, E_Status = %d\r\n", 
                                Status, E_Status);
 return 0;
 }
 |   输出结果: 
 NOTE:  枚举类型定义中的每个枚举元素代表一个整型数值。若自定义枚举类型的同时无赋值行为,则由编译系统会按照定义的顺序为其分配 
                            0, 1, 2, … 的数据值;反之,则以赋予的数值为准  枚举元素必须为常量,在枚举定义之外,均不能对枚举元素进行赋值操作  各枚举元素不能重名,枚举元素名也不能为程序中其他关键字或变量名  指针类型  定义:  指针:一个变量的地址  指针变量:一个存放其他变量地址的变量  创建一个指针变量的语法格式:  EXAMPLE: 
                             
                              | char *p; // 星号 "*" 表示,其后面的名字是一个指针变量名。即:p 为指针变量名。
 // char 表示,该指针变量 p 的数据类型为字符型。
 |   引入了指针之后,C/C++ 中就有了两种访问变量数据值的方式:  1.通过变量名来直接访问  2.通过内存地址块的指针来间接访问  3.指针运算相关的运算符有以下两种:  取地址运算符 “&”:获取变量所占用的存储空间的地址,为单目运算符(只有一个操作数)。  取值运算符 “*”:也称指针运算符,获取指针变量所指向的存储空间内的数据值。取值运算符的操作数只能是一个指针变量。  EXAMPLE 1:: 
                             
                              | // 创建整型指针变量 
                                p int *p;
 // 创建整型变量 a,并初始化数据只为 2
 int a = 2; // 假定变量 a 的存储地址为 0x8000
 //获取整型变量 a 的存储地址,并将该地址赋值给指针变量 p。
 p = &a;
 // 结果为:指针变量 p 存储了变量 a 的地址,即 0x8000。
 // 之后就可以根据需要,通过 *p 的形式来间接访问变量 a 的数据值 2 了
 |   EXAMPLE 2: 
                             
                              | int main(void) {
 // 创建 int 类型的变量 a , 并对其进行初始化赋值为 2;
 int a = 2;
 // 创建 int 类型的指针变量 p ,并将其初始化,指向变量 a 的内存地址
 int *p = &a;
 // 输出变量 a 的地址
 printf("a's Address = 0x%x.\r\n", &a);
 // 输出变量 a 的值
 printf("a = 0x%x.\r\n", a);
 // 输出指针变量 p 的地址
 printf("p's Address = 0x%x\r\n", &p);
 // 输出指针变量 p 的值
 printf("p = 0x%x\r\n", p);
 // 输出指针变量 p 所指向的内存单元的值
 printf("*p = 0x%x\r\n", *p);
 // 输出指针变量 p 指向的内存单元数据的存放地址,即变量 a 的地址
 printf("&(*p) = 0x%x\r\n", &(*p));
 // 输出变量 a 的内存地址指向的数据值,即变量 a 的值
 printf("*(&a) = 0x%x\r\n", *(&a));
 return 0;
 }
 // p,表示指针变量,指向存储空间的地址
 // *p,指针变量 p 所指向的存储空间的数据值
 // &p,指针变量 p 所占用的存储空间的地址
 |   输出结果: 
 NOTE:通过上述例子,可见取值运算和取地址运算互为逆运算。  空类型  定义:表示一种未知的类型,不能表示一个真实的变量。  作用:  限定函数返回的数据类型  限定函数参数的数据类型  EXAMPLE: 
                             
                              | void n; // 错误,不能表示真实的变量。 void nFunction(void); // 正确。
 void xFunction(char n); // 正确。
 |   空类型指针(void *):表示未知类型的指针,可以指向任意类型变量。 |