C语言的结构体、联合和枚举
结构体是C语言中一种非常重要的数据结构。与数组不同,结构体类型的变量的成员变量(数组称元素)可以具有不同的类型,并通过成员变量的名称获取指定成员。联合和结构体相似,但联合类型的变量的所有成员都共享同一存储空间,每次只能存储一个成员。枚举类型是一组命名了的整数值。结构体、联合、枚举和数组都是用于创建多种多样的、与基本数据类型同样的用户自定义的数据类型。
结构体
结构体类型的声明
结构体类型的声明格式如下:
struct
{
类型 成员变量1;
类型 成员变量2;
...
} 变量1, 变量2;
变量1和变量2都是该结构体类型的变量,结构体类型的变量的成员变量按声明的顺序在内存中依序存储。结构体为其所有成员设置了单独的命名空间,因此可以在结构体外存在与结构体内成员同名的变量。
结构体类型变量的成员可以是数组类型的变量,数组变量的元素也可以是结构体类型的。
结构体类型的变量的初始化
结构体类型的变量的初始化是依次列出结构体类型的变量各成员的值,用,
隔开,并用大括号扩起来,形式如下
struct
{
类型 成员变量1;
类型 成员变量2;
...
} 变量1 = {成员变量1的初始值, 成员变量2的初始化值,...},
变量2 = {成员变量1的初始值, 成员变量2的初始化值,...};
注意:初始化式中的初始化值必须按结构成员的声明顺序给出,且初始化式中的表达式必须是常量表达式。
结构体类型的变量的操作
结构体类型的变量通过成员名称访问其内部的成员,其访问格式为:
结构体类型变量.成员变量
.
是C语言的一个运算符,优先级和++
和--
相同,几乎高于所有其他的运算符。
结构体类型变量的成员是一个左值,可以看作一个变量使用。类型一致的结构体类型变量之间可以使用赋值运算符相互赋值。
使用结构体类型作为函数的参数和返回值时,实际上使用的都是结构体类型的变量的副本。这样结构比较大的时候,会产生大量的开销,所以一般都使用结构体类型的变量的指针。
结构体类型
按照声明结构体类型时定义变量的方式要求变量必须在一个地方完全声明,否则当在新的地方用同样的方式定义变量时,不仅造成代码的结构臃肿,更重要的是C语言会将这些变量看成是不同的类型。为了解决这个问题,C语言利用结构标记来标识特定结构体类型的名字,这样就可以在别的地方使用结构标记来声明属于同样结构体类型的变量了。结构标记的声明格式如下:
struct 结构标记
{
类型 成员变量1;
类型 成员变量2;
...
} 变量1, 变量2;
struct 结构标记 变量3;
struct 结构标记 变量4;
注意:使用结构标记时,不能省略标记前面的struct
单词。
除了使用结构标记,还可以使用typedef
来为定义结构体类型的别名,其使用形式为:
typedef struct
{
类型 成员变量1;
类型 成员变量2;
...
} 结构体类型;
结构体类型 变量1;
结构体类型 变量2;
注意:当命名结构体类型时,通常两者都可以使用,但用于链表时必须强制声明结构标记。
/**************************************
* struct_declare.c *
* *
* C语言的结构体声明、定义和使用 *
**************************************/
#include <stdio.h>
#include <string.h>
#define NAME_LEN 30
typedef struct EmployedPerson
{
char name[NAME_LEN + 1];
int number;
char sex;
} Employee;
int main()
{
struct
{
int number;
char name[NAME_LEN+1];
int on_hand;
}part1 = {10, "Jonh", 5},
part2, part3;
printf("part1的number: %d, name: %s, on_hand: %d\n", part1.number, part1.name, part1.on_hand);
part2.number = 20;
strcpy(part2.name, "Tom");
part2.on_hand = 15;
printf("part2的number: %d, name: %s, on_hand: %d\n", part2.number, part2.name, part2.on_hand);
part3 = part2;
printf("part3的number: %d, name: %s, on_hand: %d\n", part3.number, part3.name, part3.on_hand);
struct EmployedPerson employee1 = {"Tim", 10, 'M'};
Employee employee2 = {"Smith", 50, 'W'};
printf("employee1的name: %s, number: %d, sex: %c\n", employee1.name, employee1.number, employee1.sex);
printf("employee2的name: %s, number: %d, sex: %c\n", employee2.name, employee2.number, employee2.sex);
return 0;
}
联合
联合和结构体一样,联合类型的变量可以由具有不同类型的一个或多个成员变量构成。但编译器只为联合类型的变量分配最大的成员变量需要的内存空间。联合类型的变量的所有成员变量共用这段内存空间,因此给一个成员赋予新值就会修改其他成员的值。
联合类型的声明方式和结构体类型的声明方式一样:
union
{
类型 成员变量1;
类型 成员变量2;
} 联合变量;
访问联合类型变量的成员的方法和访问结构体类型变量的成员的方法相同,且联合类型的变量的成员也是左值可以像变量一样使用。同时可以类似于结构体类型为其声明联合标记和类型定义。联合类型的变量也可以使用赋值运算符执行赋值操作,也可作为参数和返回值在函数中使用。
联合类型的变量初始化时,只有第一个成员可以获得初始值,其初始化的一般形式为:
union
{
类型 成员变量1;
类型 成员变量2;
} 变量 = {成员变量1的值};
注意:初始化式两边的大括号是不可以省略的。
联合主要包括以下常见的应用,一是通过在结构体类型中使用联合节省空间,二是使用联合类型的变量作为数组元素构建含有不同类型的混合的数据结构。
为了解决无法知道联合类型的变量当前存放的是哪个成员的问题,可以把联合类型的变量作为结构体类型变量的成员,且结构体类型提供另一个成员变量作为标记来提示当前存储在联合类型变量中的是哪个成员。而这个标记成员使用枚举类型是非常合适的。
/**************************************
* using_union.c *
* *
* C语言中的联合类型 *
**************************************/
#include <stdio.h>
typedef union Number
{
int i;
float f;
} Number;
typedef struct
{
int kind;
Number number;
} TagedNumber;
#define INT_KIND 0
#define FLOAT_KIND 1
int main()
{
TagedNumber number1 = {INT_KIND};
number1.number.i = 10;
TagedNumber number2;
number2.kind = FLOAT_KIND;
number2.number.f = 15.0f;
printf("number1的值为: %d\n", number1.number.i);
printf("number2的值为: %f\n", number2.number.f);
return 0;
}
枚举
枚举类型是C语言为具有少量可能值的变量设计的特殊类型。枚举类型的声明方式为:
enum
{
枚举常量1,
枚举常量2,
...
枚举常量n
} 枚举变量1, 枚举变量2;
同结构体和联合类似,可以使用标记和typedef
定义枚举类型。
C语言将枚举类型的变量和常量作为整数处理,在声明枚举类型时,如果没有为某枚举常量指定值时,则该枚举变量的值比前一个常量的值加1。如果第一个枚举常量为指定值,则其值默认为0。注意:枚举的值作为整数使用,但不要把整数作为枚举的值。
/**************************************
* using_enum.c *
* *
* C语言中的枚举类型 *
**************************************/
#include <stdio.h>
typedef union Number
{
int i;
float f;
} Number;
typedef enum{INT_KIND, FLOAT_KIND} Type;
typedef struct
{
Type kind;
Number number;
} TagedNumber;
#define INT_KIND 0
#define FLOAT_KIND 1
int main()
{
TagedNumber number1 = {INT_KIND};
number1.number.i = 10;
TagedNumber number2;
number2.kind = FLOAT_KIND;
number2.number.f = 15.0f;
printf("number1的值为: %d\n", number1.number.i);
printf("number2的值为: %f\n", number2.number.f);
return 0;
}
参考文献
- K.N. King 著,吕秀峰 译. C语言程序设计-现代方法. 人民邮电出版社