-
问题的引入
int a;
int b[10];如果要用C语言去对一个"学生"进行描述该怎么描述呢?
学生:
学号 —> int num;
姓名 —> char name[128];
性别 —> char/int gender;//0女 1男
年龄 —> int age;
地址 —> char addr[256];
…结构体去描述类似于“学生”这样的物理。
C语言允许程序猿自定义自己的组合类型:
结构体
共用体
枚举 -
结构体
自定义的一种组合类型(1) 结构体怎么定义?
struct 结构体名
{
成员数据类型1 成员名1;
成员数据类型2 成员名2;
成员数据类型3 成员名3;
…
成员数据类型n 成员名n;
};
结构体类型是由多个成员组成,而且每一个成员都有自己的类型(只要是合法的类型都是可以的),
当然不同的成员,类型是可以相同的,但是成员的名字不能相同。
“结构体名”:
要符合C语言中标识符的命名规则即可。
例子:
struct student//声明了一种新的类型
{
int num;//学号
char name[128];//姓名
int gender;//性别
int age;
char addr[256];
//....
};
struct student ----> 你定义的新的数据类型的名字
“成员数据类型1,成员数据类型2…”:
只要是C语言合法的数据类型都是可以的(基本类型、构造类型、指针…)
“成员名1,成员名2…”:
要符合C语言中标识符的命名规则即可.
定义一个新的类型的变量:
类型名 变量名 {=初始值};
struct student stu;//定义了一个变量stu,stu的数据类型是struct student;
(2) 结构体成员的内存布局
1. 结构体类型所占空间是各成员变量所占空间之和(可能会填充)。
2. 结构体内各成员变量按他们定义时出现的次序,依次保存。
例子:
struct s1
{
char a;
int b;
short c;
};
struct s1 s;
sizeof(s) == 1 + 4 + 2 == 7//error
sizeof(s) == 12//right
计算一个结构体大小的时候需要考虑其内存布局,结构体在内存中存放是按单元来存放的, 每一个单元多大取决于结构体中最大的基本类型的大小。
struct s2
{
char a;
short b;
int c;
};//8个字节
struct s3
{
char a;
short b;
short c;
};//6个字节
struct s4
{
char a;
char b[2];
char c[4];
};//7个字节
struct s5
{
int a;
char b;
double c;
};//16个字节
struct s6
{
char a;
int b;
char c;
double d;
};//20个字节
这是因为在32位的操作系统中,是按4字节对齐的,意思就是哪怕结构体中的最大变量的 长度超过了4个字节,也是按4字节一个单元来算的。 而64位的操作系统是根据最大变量的长度来确定对齐的,如果最长的数据类型是8字节, 则8字节对齐,如果最长的数据类型是4字节,则4字节对齐。 为了内存优化,一般就采用字节对齐。 字节对齐就是变量存储的地址是变量的有效字节对齐值的整数倍。 即: address % 最终有效字节对齐值 = 0; 32位的操作系统下,变量的字节对齐值: char 1 short 2 int float long double 4 64位的操作系统下,变量的字节对齐值: char 1 short 2 int float long 4 double 8 无论是哪种编译器,字节对齐都要符合一下三个准则: 1. 结构体变量的首地址能够被其最宽基本类型成员的字节对齐值大小所整除。 2. 结构体的每一个成员变量的地址相对于结构体首地址的偏移量都是成员变量的大小 的整数倍。 3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍。
(3) 结构体成员变量的引用
1) . (域操作符)
作用:用来取某一个子成员
语法:结构体变量名.成员变量名
—> 取结构体变量内部的成员变量
如:
struct student stu;
stu.num = 20;
stu.age = 15;
…
scanf(“%d”,&stu.num);//从键盘上获取学号
用一个指针指向一个结构体:
struct student *p = malloc(sizeof(struct student));
<===> struct student *p = malloc(sizeof(*p));
2) 通过指针去访问结构体
(*结构体指针).成员变量名
(*p).age
(*p).num
3) -> (分量运算符)
语法:
结构体指针->成员变量名
p->age = 20;
p->num = 20;
…
(4) 定义并初始化结构体变量
结构体的初始化用{}
//日期
struct data
{
int year;
int month;
int day;
};
//学生
struct student
{
int num;
char name[32];
struct data birthday;
float score;
};
-
按定义时的顺序依次初始化各成员变量,用逗号隔开。
struct student stu = {1,“caixukun”,{1999,9,9},99.99}; -
不按顺序来, .成员变量名 = 值
struct student = {
.birthday = {
1999,9,9
},
.score = 99.99,
.name = "caixukun",
.num = 1
};
struct student class[50];//结构体数组
-
结构体数组的初始化
a. 按数组元素的顺序依次初始化
struct student class[3] = {
//class[0]是一个结构体,按上面(1)(2)的方式来初始化结构体变量
{1,“zhangfei”,{123,1,1},0},
{2,“guanyu”,{122,1,1},50},
{3,“liubei”,{122,1,1},100}
};b. 不按数组元素的顺序来初始化 [下标] =
这种初始化的方式不同的编译器不一定支持
struct student class[3] = {
[0] = {1,"zhangfei",{123,1,1},0},
[2] = {3,"liubei",{122,1,1},100},
[1] = {2,"guanyu",{122,1,1},50}
};
-
共用体
union 共用体名
{
成员数据类型1 成员名1;
成员数据类型2 成员名2;
成员数据类型3 成员名3;
…
成员数据类型n 成员名n;
};共用体与结构体最大的区别:
结构体所占内存大小是各成员变量之和
共用体所占内存大小是各成员变量中最大的那个共用体的存储空间是各成员变量之间共用的。
同一时刻只能用一个成员变量,为了节省内存空间。
例子:
union test
{
int a;
int b;
};
union test t;
sizeof(t) == 4
t.a == 250
t.b == 250
union test
{
char a;
int b;
};
union test t;
sizeof(t) == 4
t.a == ?
t.b == 250
计算机上实际上有两种不同的存储模式:大端模式和小端模式
-
枚举
把该类型变量所有只能的值都列举出来。所以枚举一定是可以列举的值,也就是整数值。
当一个变量有几种可能的值,可以将其定义为枚举类型。
int weekday;//星期1~7
语法:
enum 类型名
{
枚举元素的列表;
};
如:
enum weekday{sun,mon,tue,wed,thu,fir,sta};
enum weekday week = wed;
printf(“%dn”,week); //3
枚举变量的初始化:
枚举变量的赋值只能是枚举元素之一。
枚举元素为代表整形的常量,从左至右依次代表0,1,2,3…
可以指定枚举元素的数值,未指定的元素依次从左至右顺序加1(数值可重复的)
如:
enum weekday{sun,mon = 2,tue,wed = 0,thu,fir,sta};
0 2 3 0 1 2 3



