1 引言
● 结构体(Structure)[在C标准中有时也称为聚合体(Aggregate)]是统一在同一个名字之下的一组相关变量的集合,它可以包含不同类型的变量
● 结构体通常用来定义储存在文件中的记录
● 将指针和结构体联合使用,可以实现更复杂的数据结构,如链表、队列、堆栈和数
2 结构体的定义
● 关键字 struct 用来引出一个结构体定义
● 关键字 struct 之后的标识符称为结构体标记,它是用来给这个结构体定义命名的。结构体标记与关键字 struct 一起用来声明具有这个结构体类型的变量
● 在结构体定义的花括号内声明的变量是结构体的成员
● 同一个结构体类型中的成员不能重名
● 每一个结构体定义都必须用一个分号来结束
● 结构体的成员可以是具有原始数据类型的变量,也可以是聚合体聚合体数据类型的变量
● 一个结构体不能包含它自身的实例,但可以包含一个指向相同类型的另外一个对象的指针
● 包含一个指向自身结构体类型的指针为成员的结构体称为自引用结构体。自引用结构体被用来构建链式数据类型
● 结构体定义创建一种新的可用来定义变量的数据类型
● struct card {
char* face;
char* suit;
}aCard, deck[52], * cardPtr;
将aCard声明为一个类型为struct card 的变量将deck声明为一个包含了52个具有struct card类型的元素数组将cardPtr声明为一个指向struct card类型的指针上述语句完成后,系统为一个类型为struct card的变量aCard、数组feck中的52个struct card类型的元素以及一个未初始化的指向struct card类型的指针申请空间
● 结构体定义中的结构体标记名是可以省略的。若结构体定义中没有标记名,则该结构体类型的变量就只能在结构体定义的同时进行声明
● 运用于结构体上的合法操作只有:将结构体变量赋值给其他具有相同类型的结构体变量用&运算符取得结构体变量的地址访问结构体变量中的成员用sizeof运算符确定结构体变量的大小
3 结构体的初始化
● 可以采用初始值列表来对结构体进行初始化
● 若列表中初始值个数少于结构体成员的个数,则剩余成员自动地被初始化为0(成员是指针时,被初始化为NULL)
● 在函数之外定义的结构体变量,若没有显式地在外部进行初始化,将被自动地初始化为0或NULL
● 通过将一个结构体变量赋值给另外一个与其类型相同的结构体变量,或逐个对结构体变量成员进行赋值来实现结构体变量的初始化
4 结构体访问
● 可以用结构体成员运算符(.)和结构体指针运算符(–>)来访问结构体的成员
● 结构体成员运算符是通过结构体变量名来访问结构体成员的
● 结构体指针运算符通过指向结构体的指针来访问结构体成员
5 在函数中使用结构体
● 将结构体传递给函数有三种方式:
传递结构体的个别成员传递整个结构体传递一个指向结构体的指针
● 结构体变量在默认的情况下以传值的方式被传递给一个函数的
● 若采用(模拟)按引用方式来传递一个结构体,传递给被调函数的是结构体变量的地址。结构体数组(与其他数组一样)都是自动以(模拟)按引用方式传递的
● 要想以传值的方式来传递一个数组,可创建一个以该数组为成员的结构体,然后以传值的方式来传递这个结构体。这样数组就以传值的方式被传递过去了
6 typedef的使用
● 关键字typedef提供了一种为已定义好的数据类型创建同义词的机制
● 为了创建更简短的类型名称,通常使用typedef 来定义结构体类型的名字
● typedef 还常常被用来为基本数据类型创建一个别名。例如,一个处理4字节长整数的程序运行于某个系统时,会被要求用类型 int 定义变量;而运行于另外一个系统时,则会被要求用类型long定义变量。为了可移植,程序就用typedef 为4字节长的整数创建一个别名,如Integer。这样,只需对别名Integer的定义做一次修改,就可使程序能够运行于两个不同的系统之上
7 共用体
● 共用体是以与声明一个结构体相同的格式,通过关键词union来声明的。它的成员共享同一个存储空间
● 共用体的成员可以是任意数据类型,但是存储一个共用体所用的字节总数,必须保证至少足以能够容纳其最大的成员
● 每次只允许访问共用体的一个成员,确保以正确的数据类型来访问共用体中的数据
● 可对共用体执行的操作有:两个具有相同类型的共用体之间的赋值,用&运算符取得一个共用体变量的地址,用结构体成员运算符或结构体指针运算符来访问共用体的成员
● 可以在声明语句中,用与其第一个成员数据类型相同的数值来对共用体进行初始化
8 位运算符
● 在计算机内部,,所有数据都是以二进制数序列的形式来表示的,每个数位取值0或1
● 在大多数计算机系统中,8个二进制数位的序列组成一个字节——存储一个字符型变量的标准存储单元,其他数据类型的变量则语言更多的字节来存储
● 位运算符用来处理整型操作数(如字符型 char 、短整型 short 、整型 int 以及长整型 long );有符号整型和无符号整型的各个数位。通常将操作数当成无符号整型数据来处理
● 位运算符有:按位与(&),按位或(||),按位异或(^),左移(>>),右移(<<)和按位取反(~)
● 按位与、按位或和按位异或都是逐位地对两个操作数进行比较。当两个操作数相应的二进制数位都是1时,按位与运算符才会将运算结果的二进制数位设置为1。只要两个操作数相应数位有一个是1(或者两个都是1),按位或运算符就会将运算结果的相应的二进制数位设置为1。仅当两个操作数相应的二进制数位只有一个是1时,按位异或运算符才将运算结果相应的二进制数位设置为1
● 左移运算符是将其左边的操作数按位向左移动,移动的位数由其右边的操作数指定。右边腾空的数位补0,左边移出的数位丢弃
● 右移运算符是将其左边的操作数按数位向右移动,移动的数位由其右边的操作数指定。对无符号整数进行右移运算时,左边腾空的数位补上0,右边移出的数位丢弃
● 按位取反运算符是将其操作数中所有的0设置成1,所有的1设置成0,然后得到运算结果
● 通常,按位与运算符要与一个被称为掩码的操作数一起使用,掩码是某些特定位被置成1的一个整数。掩码用来在选取某些数位的同时屏蔽掉其他数位
● 符号常量CHAR_BIT(在头文件 < limits.h >中定义)表示一个字节中的二进制位数(标准情况下是8)。可以用它来增强一个位操作程序的可移植性和可扩展性
● 每个二进制位运算符都有一个相应的位运算后赋值运算符
9 位域
● 当结构体或共用体中有无符号整型或有符号整型成员时,C语言允许用户指定这些成员所占用的存储位数,这被称为位域。通过将数据存储在它们所需的最小数目的存储位内,位域能够提高存储空间的利用率。
● 声明一个位域的方法是:在无符号整型或有符号整型的成员的名字后面加上一个冒号 ( : )和一个表示位域宽度的整型常数。这个常数值必须是一个整数,其范围取值在0到系统中存储一个整形所需二进制位数之间的闭区间内
● 对结构体中位域成员,是按照与其他成员相同的方式来访问的
● 可以指定一个无名位域作为结构体中的补位
● 宽度为0的无名位域将使下一个位域对齐在一个新的存储单元的边界上
10 枚举常量
● 通过关键字enum引入的枚举常量,是一个用标识符表示的整形常量的稽核。除非专门定义,枚举常量中枚举的值都是从0开始并且递增1
● 在定义枚举类型时,可以通过给标识符赋值来显式地给枚举常量定值