7、用户自定义数据类型
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7、⽤户⾃定义数据类型
1、结构体
1.1、结构体的定义
在实际的处理对象中,有许多信息是由多个不同类型的数据组合在⼀起进⾏描述,⽽且这些不同类型的数据是互相联系组成了⼀个有机的整体。
此时,就要⽤到⼀种新的构造类型数据-----结构体,简称结构。
结构体的使⽤为处理复杂的数据结构(如动态数据结构等)提供了有效的⼿段,⽽且,它们为函数间传递不同类型的数据提供了⽅便。
结构体和数组⼀样,也是⼀种构造型数据类型,是⽤户⾃定义的新数据类型,在结构体中可以包含若⼲个不同数据类型和不同意义的数据项(当然也可以相同),从⽽使这些数据项组合起来反映某⼀个信息。
结构体是⼀种构造数据类型,结构体的语法如下:
Struct 结构体名
{
数据类型成员名1;
数据类型成员名2;
数据类型成员名3;
….
数据类型成员名n;
};
在花括号中的内容也称为“成员列表”或“域表”。
其中每个成员的命名规则与变量名相同,成员之间⽤“;”作为结束符,整个结构的定义也⽤“;”作为结束符,数据类型可以是基本变量类型、数组类型、结构体类型、联合体类型或枚举类型等。
先定义结构体类型,再定义结构体变量。
结构体中的成员名可以与程序中的变量名相同,⼆者并不代表同⼀对象,编译程序可以⾃动对它们进⾏区分。
定义结构体类型时不会分配空间,只有⽤结构体类型定义变量时才会分配空间。
总结⼀下结构体类型的特点:
(1)、结构体类型是⽤户⾃⾏构造的
(2)、它由若⼲不同的基本数据类型的数据构成
(3)、它属于C语⾔的⼀种数据类型,与整形、浮点型相当。
因此,定义它是不分配空间,只有⽤它定义变量时才分配空间。
1.2、结构体变量的声明、使⽤及初始化
1.2.1、结构体变量的声明
在定义了结构体类型后,就可以声明结构体类型的变量。
有下⾯⼏种形式:
(1)、先定义结构体类型,再定义变量名
Struct 结构体名
{
类型成员名;
类型成员名;
};
Struct 结构体名变量名1,变量名2…;
这⾥的结构体名是结构体的标识符,不是变量名。
类型可以是基本的数据类型也可以是其它构造型数据类型。
Struct +结构体名:表⽰数据类型,两者不能分开写。
Struct 变量名1,变量名2…;这种写法是错误的,没有指明是哪种结构体类型。
结构体名变量名1,变量名2…;这种写法也是错误的,因为没有struct关键字。
(2)、在定义数据类型的同时,定义变量
Struct 结构体名
{
类型成员名;
类型成员名;
}变量名1,变量名2…..;
(3)、直接定义结构体变量
Struct
{
类型成员名;
类型成员名;
}变量名1,变量名2…..;
1.2.2、结构体变量的使⽤
结构体变量是不同数据类型的若⼲数据的集合体。
在程序中使⽤结构体变量时,⼀般情况下不能把它作为⼀个整体参加数据处理,⽽参加各种运算和操作的是结构体变量的各个成员项数据。
结构体变量的成员⽤以下⼀般形式表⽰:
结构体变量名.成员名;
结构体变量在使⽤时注意以下⼏点:
(1)、不能将⼀个结构体类型变量作为⼀个整体加以引⽤,⽽只能对结构体类型变量中的各个成员分别引⽤
(2)、如果成员本⾝⼜属⼀个结构体类型,则要⽤若⼲个成员运算符,⼀级⼀级的找到最低的⼀级成员。
只能对最低级的成员进⾏赋值或存取⼀级运算。
(3)、对成员变量可以像普通变量⼀样进⾏各种运算
(4)、在数组中,数组是不能彼此赋值的,⽽结构体类型变量可以相互赋值。
在C语⾔中,同⼀结构体类型的结构体变量之间允许相互赋值,⽽不同结构体类型的结构体变量之间不允许相互赋值,即使两者包含有同样的成员。
1.2.3、结构体变量的初始化
与其他类型变量⼀样,也可以给结构体的每个成员赋初值,这称为结构体的初始化。
⼀种是先定义结构体类型,再在定义结构体变量时进⾏初始化,语法格式如下:
Struct 结构体名变量名 ={初始数据表};
另⼀种是在定义结构体类型时进⾏结构体变量的初始化。
Struct 结构体名
{
类型成员名;
类型成员名;
}变量名={初始数据表};
1.3、结构体数组
1.3.1、结构体数组的定义
具有相同结构体类型的结构体变量也可以组成数组,称他们为结构体数组。
结构体数组的每⼀个数组元素都是结构体类型的数据,他们都分别包括各个成员(分量)项。
定义结构体数组的⽅法和定义结构体变量的⽅法相仿,只需说明其为数组即可,可以采⽤以下⽅法:
(1)、先定义结构体类型,再⽤它定义结构体数组,定义形式如下:
Struct 结构体名
{
类型成员名;
类型成员名;
};
Struct 结构体名数组名[元素个数];
(2)、定义结构体类型的同时,定义结构体数组,定义形式如下:
Struct 结构体名
{
类型成员名;
类型成员名;
}数组名[元素个数];
(3)、直接定义结构体数组,定义形式如下:
Struct
{
类型成员名;
类型成员名;
}数组名[元素个数];
1.3.2、结构体数组的初始化
结构体数组在定义的同时也可以进⾏初始化,并且与结构体变量的初始化规定相同。
结构体数组初始化的⼀般形式时:
Struct 结构体名
{
类型成员名;
类型成员名;
};
Struct 结构体名数组名[元素个数]={初始数据表};
或者
Struct 结构体名
{
类型成员名;
类型成员名;
}数组名[元素个数] ={初始数据表};
或者
Struct
{
类型成员名;
类型成员名;
}数组名[元素个数] ={初始数据表};
由于结构体变量是由若⼲不同类型的数据组成,⽽结构体数组⼜是由若⼲结构体变量组成。
所以要特别注意包围在⼤括号中的初始数据的顺序,以及它们各个成员项间的对应关系。
1.3.3、结构体数组的使⽤
⼀个结构体数组的元素相当于⼀个结构体变量,因此前⾯介绍的有关结构体变量的规则也适⽤于结构体数组元素。
1.4、结构体指针
可以设定⼀个指针变量⽤来指向⼀个结构体变量。
此时该指针变量的值是结构体变量的起始地址,该指针称为结构体指针。
结构体指针与前⾯介绍的各种指针变量在特性和⽅法上是相同的。
与前述相同,在程序中结构体指针也是通过访问⽬标运算“*”访问它的对象。
结构体的指针在程序中的⼀般定义形式为:
Struct 结构体名 *结构指针名;
其中的结构体名必须是已经定义过的结构体类型。
结构体指针访问结构体成员:结构体指针->成员名;
结构体变量名代表的是整个集合本⾝,作为函数参数时传递的整个集合,也就是所有成员,⽽不是像数组⼀样被编译器转换成⼀个指针。
1.5、结构体嵌套结构体
结构体中的成员也可以是另外⼀个结构体。
1.6、结构体做函数参数
将结构体作为参数向函数中传递,传递⽅式有两种:值传递和地址传递。
struct student
{
};
void temp(struct student S);//值传递
void temp(struct student *S);//地址传递
1.7、结构体中const使⽤场景
结构体中const⽤来防⽌误操作。
void temp(const struct student *S);//地址传递,加const后,只能读结构体中的数据,不能修改结构体中的数据
2、位域
2.1、位域的定义
计算机的内存是以字节为单位,为变量分配内存,也是以字节为单位,但是,实际上,有些信息的存储,并不需要占⽤⼀个字节,只需要⼀个或⼏个⼆进制位就够了。
所谓位域就是把⼀个字节中的⼆进位划分为⼏个不同的区域,并说明每个区域的位数。
每个域有⼀个域名,允许在程序中按域名进⾏操
作。
这样就可以把⼏个不同的对象⽤⼀个字节的⼆进制位域来表⽰。
位域的定义与结构体的定义很相似,其⼀般形式如下:
Struct 位域结构名
{
位域列表;
};
其中位域列表的形式为:数据类型位域名:位域长度;
例如:
Struct data
{
Unsigned char a:2;//1~2位
Unsigned char b:3;//3~5位
Unsigned char c:3;//6~8位
}
关于位域的定义,有⼀些问题需要注意:
(1)、各位域必须存储在同⼀字节⾥,不能跨两个字节
(2)、位域占⽤的位数,不能超过8个⼆进制位
(3)、允许位域⽆域名
Struct data
{
Unsigned int a:2;//1~2位
Unsigned int b:5;//3~7位
Unsigned int c:3;//8~10位该位跨字节了
};
当⼀个字节所剩空间不够存放另⼀位域时,应从下⼀字节单元起开始存放该位域,也可以有意使某位域从下⼀单元开始。
可以使⽤下⾯的⽅式,来解决这个问题:
Struct data
{
Unsigned int a:2;//1~2位
Unsigned int b:2;//3~4位
Unsigned int :0;//5~8位空域填0表⽰该字节剩余的位不⽤
Unsigned int c:5;// 1~5位
Unsigned int d:1;// 6位
Unsigned int e:2;// 7~8位
Unsigned int f:3;// 1~3位
Unsigned int :2;// 4~5位⽆名位域,它只是⽤来填充或调整位置,⽆名的位域是不能使⽤的
Unsigned int g:3;// 6~8位
};
2.2、位域变量的说明
(1)、先定义位域类型,在声明变量
例如:
Struct data
{
Unsigned int a:2;//1~2位
Unsigned int b:3;//3~5位
Unsigned int c:3;//6~8位
};
Struct data t1,t2;
(2)、定义位域类型的同时,声明变量
例如:
Struct data
{
Unsigned int a:2;//1~2位
Unsigned int b:3;//3~5位
Unsigned int c:3;//6~8位
}t1,t2;
和结构体类似,这种⽅式声明的变量,多是全局变量
(3)、直接定义位域类型的变量
Struct
{
Unsigned int a:2;//1~2位
Unsigned int b:3;//3~5位
Unsigned int c:3;//6~8位
}t1,t2;
这种⽅式,由于位域没有类型名,因此,不能再程序的其它位置,继续声明变量。
这种写法,通常在函数内部。
2.3、位域的使⽤
位域的使⽤和结构体成员的使⽤相同,其⼀般形式为:
位域变量名.位域成员名
3、共⽤体
在C语⾔中,不同数据类型的数据可以使⽤共同的存储区域,这种数据构造类型称为共⽤体,简称公⽤,⼜称联合体。
共⽤体在定义、说明和使⽤形式上和结构体相似。
两者本质上的不同仅在于使⽤内存的⽅式上。
定义⼀个共⽤体类型的⼀般形式为:
Union 共⽤体名
{
数据类型成员;
数据类型成员;
数据类型成员;
……
};
共⽤体中的所有成员使⽤同⼀块内存,所有成员的起始地址是⼀样的,内存的⼤⼩由数据类型最⼤的成员决定。
由于共⽤体中各成员的数据长度往往不同,所以共⽤体变量在存储时总是按其成员中数据长度最⼤的成员占⽤内存空间。
在这⼀点上,共⽤体和结构体不同,结构体类型变量在存储时总是按各成员的数据长度之和占⽤内存空间。
因此,当多个数据需要共享内存或者多个数据每次只取其⼀时,可以⽤共⽤体。
数据的低位存放在低地址上。
共⽤体也可以和位域结合起来使⽤。
4、枚举
在C语⾔中还有⼀种构造类型,即枚举。
在实际问题中,有些变量只有⼏种可能的取值。
例如:⼀周只有七天,程序中的错误只有那么⼏种等。
针对这样特殊的变量,C语⾔提供了“枚举”类型,在枚举的定义中,会将变量的值⼀⼀列出来。
当然,枚举类型的变量的值也就只限于列举出来的值得范围内。
4.1、枚举类型的定义
枚举类型的定义形式如下:
enum 枚举名
{
枚举成员列表;
};
在枚举成员列表中列出所有可能的取值,以分号结尾。
注意和结构体、联合体类似,“enum 枚举名”是新定义的类型名。
枚举类型变量只占4个字节。
枚举值默认从0开始,往后逐个加1,如果第⼀个成员不赋值,就默认为0;如果第⼀个成员赋值,那么后⾯的成员就从第⼀个成员的值逐渐递增。
枚举成员不能具有相同的名称,枚举成员都是常量。