C语言 中的那些 自定义类型:结构体,枚举,联合,位段分析

1.结构体

1.1结构的基础知识

结构是一些值的集合,值的类型是可以不同的,这些值被称为成员变量。

1.2 结构体的声明


struct str  // str 为结构体标签
{

	member - list;  // 结构体成员列表
}variable - list;     // 结构体变量列表

例如描述一本书

struct book    //描述一本书 ,书名,价格
{
	char name[30];  //  书名

	double price;   //  价格

}s1,s2;     //   俩个结构体变量,s1,s2,  分号不可以省略

1.3 结构体的特殊声明

在声明结构体的时候可以不完全声明。即 ——匿名结构体类型

例如:

struct     //   省略了结构体标签 (tag)
{
	int i;

	char j;

}a = { 5,'p'};

省略了结构体标签代码并不会出错,但是有几个我们需要注意的点。

1.  匿名结构体的变量创建和初始化必须和结构体的声明同时完成,在主函数中无法完成创建匿名结构体变量和初始化。

struct
{
	char a;
	int b;
}s1;


struct
{
	char a;
	int b;
}*ps;


int main()
{
	ps = &s1;
}

即使当俩个结构体的成员变量相同时,编辑器也会默认俩个匿名结构体为不同类型,上述代码:ps = &s1 会报警告。

1.4 结构体的自引用

在结构体中,包含一个成员为结构体本身,这是否可行,又该如何实现。


struct exa
{
	char a;
	int b;
	struct exa s2;
}s1;

程序会报错,无法运行。这种直接的嵌套显然行不通。我们可以尝试用指针来解决。

struct exa
{
	char a;
	int b;
	struct exa *s2;
}s1;

这样的一个自引用结构体才是正确的。

1.5 typedef 重命名结构体

我们看一个例子

typedef struct
{
	char f;
	int  i;

}node; //    typedef 重命名结构体 为 node 


int main()
{ 
	// struct node s1 = { 'd' ,2 }
	node s1 = { 'd',2 };   //相对于普通的结构体,在创建变量时简化了一些。
}

typedef 重命名结构体后,我们再创建结构体变量时需省略 struct 

但是typedef 重命名一个自引用结构体时,应该怎么实现呢。

typedef struct
{
	char f;
	int  i;
	node* exa;
}node;

这样的代码,我们在运行时会报错。

typedef struct
{
	char f;
	int  i;
	struct node* exa;
}node;

这是正确的。

typedef 重命名的 自引用结构体,结构体中被引用的结构体 ,struct 不可省略,不可直接使用重命名后的结构体名称,必须加上 srtuct

1.6 结构体变量的定义和初始化

很简单,我们看一些例子就可以掌握。

struct score
{
	int a;
	int b;
}s1;  //  声明结构体,同时创建变量 s1 

struct score
{
	int a;
	int b;
}s2 = { 2,4 };  //  声明结构体,同时创建变量 s2 并初始化

struct score s3;   //  定义结构体变量 s3 

struct score s4 = { 1,2 }; // 定义结构体变量s4 并初始化
struct score1
{
	int a;
	int n;
	struct score* node;
}n1 = {2,4,NULL};  //自引用结构体初始化


struct score1 n2  = {2,5,NULL}   //   定义n2  并初始化

1.7 结构体传参

函数在传参的时候,需要压栈,会有时间和空间的系统消耗

如果传递的结构体对象过于大,参数压栈的系统开销比较大,会导致性能下降。

所以我们结构体传参的时候尽量传地址。

1.8  结构体内存对齐,位段

篇幅较大,我选择再写一篇。

(10条消息) 结构体内存大小计算,位段分析_杨斯文。的博客-CSDN博客

2. 枚举

2.1 枚举类型的定义

enum score  //成绩
{
	A,
	B,
	C,
	D,
	E
};

enum sex //  性别
{
	male,
	female
};

以上定义的enum score,   enum sex 都是枚举类型。

{ } 中的内容 是 枚举内容的可能取值,也叫枚举常量。

枚举常量是有值的,默认为0开始,依次递增1,我们在定义的时候也可以赋值。

enum sex //  性别
{
	male = 1,
	female = 0
};

2.2枚举的优点

1. 增加代码的可读性和维护性

2. 和#define 定义的标识符相比,枚举有类型检查,更严谨。

3. 防止了命名污染(封装)

4. 便于调试

5. 便于使用,一次定义多个常量

2.3 枚举的使用

enum score  //成绩
{
	A,
	B,
	C,
	D,
	E
};


enum score stu1 = A;

只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

3. 联合(共用体)

3.1联合类型的定义

联合是一种特殊的自定义类型

这种自定义的变量也包含一系列的成员,特征是这些成员公用同一块空间

比较简单,直接用代码展示联合类型的使用

union un   // 联合类型的声明
{
	char c;
	int i;
};

union un s1; // 定义联合变量

3.2联合的特点

1.联合的成员是公用一块内存空间的,一个联合变量的大小,至少是最大成员的大小。

2. 联合成员的起始地址都是一样的。

以上面的代码为例子

它在内存中的分布

 此时这个联合变量的大小为 4 个字节。

我们可以用联合的知识来判断当前机器是大端还是小端存储

union un  
{
	char c ;
	int i;
};

 int main()
{
	 union un s1;
	 s1.i = 1;
	 printf("%d", s1.c);
}

 数据的低位存在低地址处,小端存储。

3.3 联合大小的计算

联合的大小至少是最大成员成员变量的大小。

当最大成员大小不是最大对齐数整数倍的时候,要对齐到最大对起数的整数倍。

用一个例子来说明

union un  
{
	char arr[7] ;
	int i;
};

union un s1; 
int main()
{
	printf("%d", sizeof(union un));
}

 

char arr 虽然是数组,但是最大对齐数还是1,int i  最大对齐数为 4,

最大成员的大小为 arr数组 ,为7, 但7 不是最大对齐数的倍数,所以需要对齐到最大对齐数的整数倍,所以这个联合的大小为 8 个字节。

本文结束,感谢观看!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值