原文发布于Hibiki33’s Blog,转载请标明出处。
结构体
结构体的定义和变量的声明
像 int
、float
、char
等是由C语言本身提供的数据类型,不能再进行分拆,我们称之为 基本数据类型 ;而结构体可以包含多个基本类型的数据(或指针),也可以包含其他的结构体(或结构体指针),我们将它称为 复杂数据类型 或 构造数据类型 。
例如一个学生,我们可以构造以下结构体:
struct student {
char *name; // 姓名
int number; // 学号
int age; // 年龄
char class; // 班级
float score; // 成绩
};
通过构造结构体,我们可以方便的对一个拥有一定属性的聚合进行操作(如筛选、条件排序等)。
既然该结构体已经成为一个数据类型,那么就可以用它来申明变量,如:
struct student stu1, stu2;
此外,在数据结构课程中,常用如下格式进行结构体的定义:
typedef struct student {
char *name;
int number;
int age;
char class;
float score;
} stu, *STU;
这种写法表示:将 struct student
这个语句定义为(或者说表示为)stu
这种简写,而 *s
表示这个结构体的指针。在声明变量时:
stu stu1, stu2; // 这种写法与上述 struct student stu1, stu2; 等价
STU stu3; // 表示声明了一个student结构体的指针stu3 当然此时stu3没有指向任何地址
此外,自引用结构将会在链表部分详细说明。
结构体的存储空间
理论上讲结构体的各个成员在内存中是连续存储的,和数组非常类似,例如上面的结构体变量 stu1
、stu2
的内存分布为4 + 4 + 4 + 1 + 4。但实际上,当我们运行以下程序段:
#include <stdio.h>
struct student {
char *name;
int number;
int age;
char class;
float score;
};
int main(int argc, char **args)
{
struct student stu1, stu2;
printf("%d\n", sizeof(stu1));
return 0;
}
我们会发现输出了24,这与C语言的内存对齐有关,目的是提高寻址效率,读者可以自行查阅资料深入了解。
联合
联合的定义
联合是一种数据类型,该类型变量可以在不同时间内维持定义它的不同类型和不同长度的对象,也就是说提供单独的变量,以便合理地保存几种类型中的任何一类变量。
定义形式:
union 联合名 {分量表} 联合变量名;
例如:
union v_tag {
int ival;
float fval;
char *pval;
} uval;
if(utype == INT) printf("%d\n", uval.ival);
else if (utype == FLOAT) printf("%f\n", uval.fval);
else if(utype == STRING) printf("%s\n", uval.pval);
else printf("bad type\n");
注意:使用联合,用法必须一致,即取出的类型必须是最近存入的类型。因此,在使用联合时,要记住当前存于联合中的类型是什么,不允许存入是一种类型,而取出是另一种类型。
联合可以出现在结构和数组中,数组和结构也可以出现在联合中:
struct symtab {
char *name;
int flags;
int utype;
union {
int ival;
float fval;
char *pval;
} uval;
};
声明及使用:
struct symtab st[100];
printf("%d", st[10].uval.ival);
结构体和联合的异同
在定义或说明形式上,union
和 struct
很类似,但在任何时刻联合只允许联合中说明的某一成员留在联合里。结构由多个成员(分量)所组成,而联合只有一个成员,只不过该成员的名字和类型可以在规定的几个里选定一个。
因此,联合可以看作是一个特殊的结构,其所有成员在结构中的位移量都是0,当对联合变量分配存贮空间时,应保证它能容纳最大的一个成员的大小,而存贮空间的边界应能适于联合中的所有可选成员的类型。
对联合成员的引用方式完全和结构的情况一样。
枚举
枚举的语法定义格式为:
enum 枚举名 {枚举元素1, 枚举元素2};
比如对于一星期7天,我们往常会这样定义:
#define MON 0
#define TUE 1
#define WED 2
#define THU 3
#define FRI 4
#define SAT 5
#define SUN 6
如果使用枚举的话:
enum DAY {
MON, TUE, WED, THU, FRI, SAT, SUN // 第一个枚举成员的默认值为整型的0 后续枚举成员在前一个基础上加1
};
可以在定义枚举类型时改变枚举元素的值:
enum season {spring, summer=3, autumn, winter};
没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5。
定义和声明与结构体都很类似。例如:
#include <stdio.h>
#include <stdlib.h>
int main()
{
enum color { red=1, green, blue };
enum color favorite_color;
printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");
scanf("%u", &favorite_color);
switch (favorite_color)
{
case red:
printf("你喜欢的颜色是红色");
break;
case green:
printf("你喜欢的颜色是绿色");
break;
case blue:
printf("你喜欢的颜色是蓝色");
break;
default:
printf("你没有选择你喜欢的颜色");
}
return 0;
}
当输入1时,输出为:
请输入你喜欢的颜色: (1. red, 2. green, 3. blue): 1
你喜欢的颜色是红色
此外,对于上述例子,我们可以对原本的整型变量进行类型转换:
int a = 1;
favorite_color = (enum color) a;