C语言第十二章:结构体共用体(联合体)枚举typedef
Posted 歌咏^0^
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言第十二章:结构体共用体(联合体)枚举typedef相关的知识,希望对你有一定的参考价值。
目录
一、结构体
1、问题的引入
1)多个相同数据类型的数据可以用数组表示,那么,如果多个不同数据类型的数据用一个集合表示——结构体
2)前面我们所介绍的普通数据类型实际上远远未能满足我们对实际应用中的要求,比如说一个学生,可能包含的属性有年龄、姓名、分数等等,不可能用一个基本数据类型(int 、float 、char)就能打发他们,因为学生有很多的属性才能构成一个完整的数据--学生,所以说,我们需要自己定义一个复合数据类型,满足现实应用中的要求。
2、概念
自定义的一种复合数据类型
3、定义 结构体类型:
struct 结构体名
{
成员类型1 成员名1;
成员类型2 成员名2;
...
成员类型n 成员名n;
};
右大大括号}后是否加分号:
语句、定义不需要分号结尾,声明需要加分号(简单解释:右大括号}能表示结尾的就不需要分号), 结构体的定义是声明,所以需要分号结尾。
eg:
struct student
{
char name[16];
int age;
float score;
int id;
};
上面我们定义一个新的数据类型: struct student
这个类型里面包含了 name age score id等成员
1)结构体名字可以省略
2)要注意区别创建一个结构体类型与定义一个结构体变量
3)变量名(创建一个结构体类型名)可以省略,但是分号; 一定不能漏掉
4、使用struct student模块的结构体定义两个结构体变量:如
struct student Jose;
struct student sock;
5、其实说白了,结构体就是我们自己发明的数据类型,因此使用结构体至少包含两个步骤:
1)创建一个自定义的结构体类型
2)用这个自己做出来的数据类型定义一个结构体变量
6、访问结构体变量一般是访问结构体变量中的成员变量
(1)结构体变量名 . 成员变量名
struct student stu1;
stu1.age;
".":域操作符(成员引用符)
成员变量与普通变量的用法及含义是一样。
&(stu1.age)
(2) ( * 结构体指针变量名) . 成员变量
struct student *p = malloc(sizeof(*p));
(*p).age
(3)结构体指针变量名->成员变量名
->:指向结构体的成员变量
struct student *p = malloc(sizeof(*p));
p->age;
7、定义并初始化结构体变量的方法
结构体变量的初始化用{}
struct date
{
int year;
int month;
int day;
};
struct student
{
char name[32];
int age;
sturct date birthday;
};
(1)按定义时的顺序依次初始化,用逗号隔开
struct student stu1={"zhangsan",18,{2008,9,10}};
(2)不按定义时的顺序,指定成员初始化
struct student stu2={
.age=18,
.name="lisi",
.birthday={
.day = 10,
.month = 9,
.year = 2008
}
};
(3)结构体数组
struct student a[10]={
{"zhangxueyou",18,{2008,9,10}},
{"liudehua",18,{2007,9,10}}
};
8、一般来说,结构体会包含比较多成员,结构体变量的尺寸会比一般的变量大,所以结构体作为参数传入函数的时候,最好用地址,这样效率高
9、结构体变量的内存分配(结构体的大小)
struct node{
char a;
int b;
char c;
};
(1)结构体的各成员变量的内存布局问题
a.以定义时各成员变量出现的次序,依次保存。
b.结构体的大小需要字节对齐
(2)为何需要字节对齐?
a.从前面我们知道,目前计算机内存按照字节编址,每个地址的内存大小为1个字节。从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问。各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
b.假设CPU现在每一次从内存读取数据为4个字节,那么现在要从struct node结构体中把成员变量b的数据读取出来,按照内存紧密的方式排列,那么CPU需要访问内存2次才能把数据读取出来。所以为了提高CPU访问内存数据的效率问题,结构体的各个成员变量在内存空间中需要地址对齐。
c.作用:提高CPU访问内存数据的效率。
(3)字节对齐总结:
1、结构体定义的时候,变量成员的顺序会影响结构体的大小
2、对齐:成员变量以什么样的方式排列;紧密排列、还是松散中间是不是有间隔
3、结构体中对齐的字节数 按 最大个成员的基本数据类型大小对齐
二、共用体(联合体)
1、概念
几个不同的变量共同占用一段内存的结构,在C语言中,被称为"共用体"类型结构
2、定义共用体类型
union 共用体名
{
成员类型1 成员名1;
成员类型2 成员名2;
...
};
比如:
union A{
char c[9];
int n;
double d;
};
3、特点
a.联合体中的所有成员共享一段内存的
b.联合体中的最大个数据成员的大小就是联合体的大小
4、大小端模式
1)概念
一个多字节存储单元的低地址存储低有效位还是高有效位
2)为何会有大小端模式
以前不同的芯片公司在处理把寄存器的数据存放到内存中时,采用的方式不统一,才产生了大小端两种模式。
小端模式:低地址存放低字节数据
大端模式:低地址存放高字节数据
union data
{
int a;
char b;
};
union data n;
n.a = 0x12345678;
printf("%x\\n",n.b);//结果为78,说明是小端模式
3)实际应用场景
网络中两个不同端序的主机之间进行通信时,需要进行字节序转换
三、枚举
1、概念
枚举类型用于声明一组命令的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型。
2、格式
enum 枚举的名字{
常量名字1,
常量名字2,
常量名字3,
};
比如:
enum color{
red,
green,
blue
};
注意:如果里面的变量没有赋值,则默认从0开始,然后往后面递增,也就是red = 0, green = 1,blue = 2
enum color{
red = 1,
green,
blue
};
3、访问:外界访问枚举类型的数据成员可以直接访问
比如:
//定义一个枚举类型的变量
enum color mycolor;
//赋值的时候直接访问
mycolor = RED;
4、作用:不管是使用宏来定义常量,还是使用枚举来定义常量,目的只有一个:增强程序的可读性。
四、typedef
typedef 用来声明一个新类型
1、作用:给一个已经定义了的类型取一个新的名字,使新的名字更能表示它的含义。
typedef int size_t;
void *malloc(size_t size);
2、typedef与#define的区别
#define只是简单的字符串替换而已,而typedef则是为一个类型起新名字。
eg: typedef char* pStr1;
#define pStr2 char*
pStr1 s1,s2;
pStr2 s3,s4;
printf("%d %d %d %d\\n",sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4));
3、给数组取新名字
typedef int[10] array;
==>
typedef int array[10];//新的类型为array,代表int[10];
array a;//定义一个数组a,它有10个元素,每个元素为int类型。
4、给函数指针取新名字
int (*p)(int,char);//定义一个函数指针变量p
typedef int (*pfunc)(int,char);//声明一个新类型pfunc,该类型与p一样
以上是关于C语言第十二章:结构体共用体(联合体)枚举typedef的主要内容,如果未能解决你的问题,请参考以下文章