C语言自定义类型详解

一、结构体

对于 人、书 这样的 复杂对象、基本数据类型是无法表达的,只能表达其中的某一个方面,但将复杂对象的这些方面结合起来,相当于表达了复杂对象,使用结构体便可以达到此目的

1. 结构体声明

struct tag
{
	//Member_List
}//Variable_List;

struct 结构体关键字
tag 结构体标签名:符合标识符命名规则即可
Member_List 成员列表:结构体成员的定义
Variable_List 变量列表:结构体类型声明时创建的变量,可以省略

注意:花括号后的分号不能省略

在上述的结构体声明中标签 tag 是可以省略的,称为匿名结构体

需要注意:

  • 匿名结构体只能在声明结构体同时创建结构体变量
    由于没有标签名无法在声明结构体后创建变量
  • 对于两个成员相同的匿名结构体,编译器认为这是两个不同的结构体

结构体1

2. 结构体变量的创建及初始化

结构体创建变量有如下两种方式:

//在结构体声明的同时创建结构体变量 p1,p2 
struct people
{
	char name[20];
	int age;
} p1,p2 = {"张三", 20};

//在结构体声明后创建结构体变量 p3 (匿名结构体无法创建变量)
int main()
{
	struct people p3 = {.age = 18, .name = "李四"};

	return 0;
}

由于结构体变量有多个成员,初始化时需要使用花括号

  • 结构体变量 p2 在创建的同时按顺序的方式初始化
  • 结构体变量 p3 在创建的同时以指定成员的方式初始化

3. 访问结构体成员

结构体变量访问其成员时,通过结构体.成员名的方式

p3.name = "王五";
p3.age = 30;

结构体指针访问其指向结构体变量的成员时,通过结构体->成员名,或者(*结构体指针).成员名的两种方式

struct people* ps = &p3;
ps->name = "王五";
(*ps).age = 30;

4. 结构体内存对齐

结构体大小并不是结构体所有成员的大小相加后的结果,而是需要遵循四条对齐规则

  • 第一个成员存储于 相对结构体变量起始地址 0偏移 位置处

  • 第二个及之后的成员存储于 相对结构体变量起始地址 的某个 对齐数整数倍的偏移 位置处
    对齐数:成员变量存储所占空间的大小编译器默认对齐数 中的 较小值

  • 结构体的总大小需要对齐到 相对结构体变量起始地址 偏移量为最大对齐数整数倍地址处
    最大对齐数:每一个成员的对齐数中的最大值

  • 对于 嵌套的结构体变量 对齐到 该嵌套的结构体的最大对齐数整数倍地址处

#include <stdio.h>

struct S1
{
	char c;
	short s;
	int i;
};

struct S2
{
	char c;
	int i;
	short s;
};

int main()
{
	struct S1 s1;
	struct S2 s2;
	printf("%d %d", sizeof(s1), sizeof(s2));

	return 0;
}

输出
8 12

在这里插入图片描述

注意:数组的对齐数以数组元素的对齐数来确认

5. 修改默认对齐数

默认对齐数通过如下指令可以修改

//修改默认对齐数为 num(整形常量)
pragam pack(num)

//...

//恢复编译器默认对齐数
pragam pack()

6. 结构体传参

函数实参和形参之间是以值传递的方式进行的

函数调用时,如果实参传递为结构体变量时,形参也需要创建一个和实参相同大小的结构体来接收,当结构体很大时,时间和空间上都会存在不小的开销
一个更优的方式为传递结构体地址,在函数中通过->操作符可以访问实参的结构体
如果在函数中不希望改变实参所指向的结构体,可以在函数的参数部分加上 const 声明形参

二、枚举

枚举声明如下:

enum tag {Possible_Values_1, Possible_Values_2, ……, Possible_Values_n };

enum 枚举的关键字
tag 枚举标签名:符合标识符命名规则即可
Possible_Values1 枚举可能取值:该值默认为 (int)0,声明时可以赋值
...
Possible_Values1 枚举可能取值:该值默认为上一个枚举可能取值 + 1,声明时可以赋值

注意:花括号后的分号不能省略

在生活中,诸如:颜料三原色,星期一,星期二,……,星期天等,可以采用枚举的方式表达

enum color { RED = 3, YELLOW = 5, BLUE = 10 };
enum week { Monday = 1, Tuesday, Wednesday, Thursday,,Friday, Saturday, Sunday };

三、联合体

在某些场景中,对于一个复杂对象,在某时刻,只会使用他的一个属性时,可以使用联合体

union tag
{
	//Member_List
}//Variable_List;

union 联合体关键字
tag 联合体标签名:符合标识符命名规则即可
Member_List 成员列表:联合体成员的定义
Variable_List 变量列表:联合体类型声明时创建的变量,可以省略

注意:花括号后的分号不能省略

联合体的特点:联合体中的多个成员,占用同一片空间,遵循如下规则

  • 每一个成员变量都存储于 相对联合体变量的起始地址 偏移量为 0 的地址处
  • 联合体的总大小需要对齐到 相对结构体变量起始地址 偏移量为最大对齐数整数倍地址处
    对齐数:成员变量存储所占空间的大小编译器默认对齐数 中的 较小值
    最大对齐数:每一个成员的对齐数中的最大值

注意:数组的对齐数以数组元素的对齐数来确认

#include <stdio.h>

union U1
{
	char c;
	int i;
}u1;

union U2
{
	char c[5];
	int i;
}u2;

int main()
{
	printf("%d %d", sizeof(u1), sizeof(u2));

	return 0;
}

输出
4 8

在这里插入图片描述

由联合体的特点可知:同一时刻访问联合体同一个变量才有意义
联合体变量的创建、初始化、及访问和结构体是相似的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值