自定义的数据类型
1. 结构体
-
结构体的定义
struct 结构体名 { 数据类型 成员名1; 数据类型 成员名2; ... };
- 结构成员中可以为结构体类型;
- 结构体成员可以为联合体类型;
- 结构体成员也可以是基本数据类型;
注意:结构体在定义时不分配内存,只有用它定义结构体变量是才分配内存。
-
结构体变量的声明、初始化及使用规则
-
先声明结构体类型,再定义结构体变量。形式为:
struct 结构体名 结构体变量名;
-
在定义结构体类型的同时定义变量,形式如下:
struct 结构体名 { 类型 成员名1; 类型 成员名2; }结构体变量名1,结构体量名2...;
3. 直接定义结构体变量
如果省略结构体名,则称之为无名结构体,这种情况常常出现在结构体内部用于定义结构体成员或者函数内部。定义形式一般为:
struct { 类型 成员名; 类型 成员名; ....... }变量名;
当然了,应该注意的是,这种无名结构体定义结构体变量的方法就没法再去定义其他的结构体变量了。因为它没有名字嘛,所以呢,它一般使用在我们在结构体内部定义一个结构体成员时使用。
- 结构体变量的使用
1.调用成员变量:结构体变量名.成员名
- 不能将结构体变量作为一个整体进行引用,而只能对结构体成员分别进行引用。
- 对结构体的成员变量可以像普通变量一样进行各种运算。
- 同一结构类型间可以相互赋值
2.结构体变量初始化
-
给结构体的每个成员赋初值,称为结构成员的初始化,语法格式如下:
struct 结构体名 变量名 = {初始数据表}; //定义的结构体变量的同时将其初始化: struct 结构体名 { 成员列表; }结构体变量名 = {初始化列表};
-
2. 结构体数组
-
结构体数组的定义
1.有相同类型的结构体也可以组成数组,一般称他们为结构体数组。该数组中每一个数据类型都是类型相同的结构体。
定义形式如下:struct 结构体名 { 类型 成员名; 类型 成员名; ...... }; struct 结构体名 数组名[元素个数];
2.定义结构体类型的同时,定义结构体数组,形式为:
struct 结构体名 { 成员列表; }数组名[元素个数];
3.直接定义结构体数组,形式为:
```c struct { 成员列表; }数组名[元素个数]; ``` 这种形式因为没有结构体变量名,因此也是不能去定义其他的结构体数组变量的。
-
结构体数组初始化
一般有三种形式:
struct 结构体名 { 成员列表; }; struct 结构体名 数组名[元素个数]={初始化列表};
struct 结构体名 { 成员列表; }数组名[元素个数] = {初始化列表};
struct { 成员列表; }数组名[元素个数]={初始化列表}
-
结构体数组的使用
a.引用结构体数组中某一元素的成员
例如,要引用第二个成员员的name成员:e[1].name
b.可以将结构体数组的元素值赋给另一个相同结构体类型的数组中的另一个元素,或赋给同一类型的变量。
c.不能将结构数组作为一个整体使用,如对结构体整体进行输入输出。
-
3. 结构体内存对齐问题
-
所谓结构体内存对齐呢,就是操作系统会将你所定义的结构体变量按照某一规则进行内存对齐(如一字节对齐,四字节对齐等)。然后对结构体内内的每一个成员在存储上面进行排列,使其遵循这一规则。
-
为什么要进行结构体内存对其呢?这就要回到计算机本身了,比如我们使用的是32位的机器,也就是说我们我们的地址线有32条,每次去内存中读取数据就是每次可以取4字节的数据。如果你的结构体成员的存储结构不满足这一存储要求那么操作系统就会帮你调整,具体做法就是将存储成员变量的出处单元或前或后的存储单元给空出来,凑够四个字节。这样每读取一次数据,就能获得一个完整的数据,而无需进行拼接,这样就加快了计算机效率,是一个以空间换时间的做法。
-
关于结构体字节对齐,平时在面试中还是比较容易问到和考到的。所以后面我会专门写一篇博客详细介绍下这个,这里只是简单的提一嘴。
4. 结构体指针
-
定义
设定一个指针变量用来指向一个结构体变量。此时该指针变量的值是结构体变量的起始地址。定义形式如下:
struct 结构体名 *结构体指针名;
5. 位域
-
所谓的位域就是把一个字节中的二进制划分为几个不同区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。其目的主要是为了节省内存空间。
定义形式为:
struct 位域结构体名 { 位域列表 }; 例如: struct data { unsigned int a:2; //a表示data的低两位 unsigned int b:3; //b表示data的3~5位 unsigned int c:5; //c表示data的6~8位 };
注意点:
-
各位域必须存储在同一个字节中,不能跨两个字节。
即当一个字节所剩空间不够存放另一个位域时,应该从下一个单元开始存放该位域。
-
可以使用0占位使得位域从下一个单元开始存储。如:
struct data { unsigned int a:2; unsigned int : 0; //用于占位 unsigned int b:3;//从下一字节开始存储 }
-
位域占用的位数不能超过8个二进制位。
-
允许位域无域名,但无名的位域不能使用。
-
位域的本质是结构体,其变量的定义方式和结构体类似。
位域变量的引用:
`位域变量名.位域名`
-
6. 共用体
-
1.定义
不同数据类型可以使用共同的存储区域,这种构造数据类型也叫作共用体。也称为联合体。定义形式:union 共用体名 { 成员列表; }; 如: union un { int a; char b; }un1;
共用体变量在存储时总是按其成员中数据长度最大的成员占用的内存空间计算其大小。如上面的例子中,该共用体的大小为4字节。(32位的机器中)
其成员的调用方式和结构体相同。
如:un1.a = 5; //调用成员变量,猜一下,此时un1.b的值是多少
因为二者共用同一块内存,所以他们的值相等。共用体的一个用法:用来测试机器大小端。想一想利用这个性质我们该怎么去做。
-
枚举
在枚举变量的定义中,会将变量的值一一列出来,枚举类型变量的值也就只限于列举出来的值的范围内。定义形式:
enum 枚举名{枚举成员列表};
枚举类型的申明有三种,基本和结构体类似。这里不再赘述,但有几点需要注意的:
- 枚举成员是该枚举类型的命名常数,任意两个枚举成员不能同名。
- 每个枚举变量都具有与之相关联的常数值,该值为int类型,每个枚举成员的常数值必须在该范围内。
- 声明的第一个枚举成员变量,如果没有给他赋初值的话默认为0。第一个枚举成员若没有赋初值的话,其值为0。
- 每一个枚举成员都是前一个枚举成员变量的值加1,若前一枚举变量已经赋初值则在该值基础上加1。
- 枚举成员都是常量,不能再对他们进行赋值(注意这个,避免出错)
- 实际上,枚举变量也是一种整型变量,它是一个常量整型值的列表。可以将成员的值赋给枚举变量,也可以把整数值赋给枚举变量。
- 枚举变量的成员值可以直接用,一般多用于switch 语句中。