【C语言】自定义类型

结构体

初阶结构体

类型声明

常规声明已在初阶结构体阐述,在这里再来分享一个特殊声明
这种声明也叫匿名结构体类型
在这里插入图片描述

1.该定义方式一般在只用一次的情况下应用
2.匿名结构体的成员如果一样,在编译器看来也是不同类型的结构体,如:

struct
{
	char name[20];
	char id[12];
}ss;

struct
{
	char name[20];
	char id[12];
}a[20],*ps;
int main()
{
	ps = &ss;
	return 0;
}

在这里插入图片描述会报错,显示类型不兼容

自引用

在结构体中包含一个类型为该结构本身的成员,是否可以?
在这里插入图片描述
事实上,这种方法有误!!!
int data数据区
struct Node next 指针域,改正struct Node* next

再来看一种:
在这里插入图片描述
错误点:类似于先鸡还是先有蛋的问题
(typedef是类型重命名)

再来一组:

typedef struct Node 
{ 	
	int data;//数据 	
	struct Node* next;//指针 
} Node, * pNode; 
//pNode相当于struct Node* 

变量的定义和初始化

struct Book
{
	char name[20];
	float price;
	char id[12];
}s = { "语文", 55.5f, "PGC001" };

struct Node
{
	struct Book b;
	struct Node* next;
};

int main()
{
	struct Book s2 = { "数学", 66.6f, "HG001" };
	struct Node n = { {"英语", 66.8, "TG001"}, NULL };

	return 0;
}

内存对齐(重点!!!)

先看一个案列:

struct s1
{
	char c1;//1
	int i;//4
	char c2;//1
};
struct s2
{
	char c1;//1
	char c2;//1
	int i;//4
};
int main()
{
	struct s1 s1;
	struct s2 s2;
	printf("s1:%d\n", sizeof(s1));//12
	printf("s2:%d\n", sizeof(s2));//8
	return 0;
}

运行结果:
在这里插入图片描述首先,来看对齐规则:
在这里插入图片描述补充:VS编译器默认对齐数为8;Linux环境下没有默认对齐数,没有默认对齐数时,自身大小就是对齐数。
练习一下:

struct s3
{
	double c1;
	char c2;
	int i;
};

它的大小是多大呢?答案是:16。你做对了吗?若没有请 注意第二条规则的理解与使用!

验证偏移量的函数:

struct s3
{
	double c1;
	char c2;
	int i;
};
#include<stddef.h>
//offsetof - 宏  包含于头文件  stddef.h
//计算结构体成员相对于起始位置的偏移量
int main()
{
	printf("%d\n", offsetof(struct s3, c1));
	printf("%d\n", offsetof(struct s3, c2));
	printf("%d\n", offsetof(struct s3, i));
	return 0;
}

在这里插入图片描述
在看一个例子,假如结构体中的成员中还有结构体呢?

struct s3
{
	double c1;
	char c2;
	int i;
};
struct s4
{
	char c1;
	struct s3 s3;
	double d;
};
int main()
{
	struct s4 s;
	printf("%d\n", sizeof(s));
	return 0;
}

在这里插入图片描述
这里根据对齐规则第四条,s3先自身根据对齐规则确定大小,然后把s3作为一个普通成员变量来处理即可。
补充:s的最大对齐数位为8,不要当成16!!!

内存对齐的意义:
1.平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

总体来说: 结构体的内存对齐是拿空间来换取时间的做法。

为了尽量节省空间,应该将占用空间小的成员变量集中在一起·(如案例一)。

修改默认对齐数(特殊点,当4改为1时,不对齐)

#pragma pack(4)//设置默认对齐数为4
struct s
{
	char c;
	double d;
};
#pragma pack()//取消设置
int main()
{
	struct s s1;
	printf("%d", sizeof(s1));
	return 0;
}

在这里插入图片描述在这里插入图片描述结论:结构在对齐方式不合适的时候,可以自己更改默认对齐数。

传参

结构体传参,要传结构体的地址。

实现位段(位段的填充&可移植性)

在这里插入图片描述
还有一个·char。

struct A
{
	int a : 2;
	int b : 3;
	int c : 3;
	int d : 3;
};

位段内存分配

1.位段的成员可以是int unsigned int signed int或者是char(属于整形家族)类型
2位段的空间上是按照需要以4个字节( int)或者1个字节( char)的方式来开辟的。
3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

在这里插入图片描述
在这里插入图片描述

位段应用

在这里插入图片描述

枚举

定义

使用

enum Sex
{
	male = 2,//枚举初始化
	female,
	secret
};
enum Day
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};
int main()
{
	enum Sex s = male;
	enum Day d = Fri;

	enum Day d1 = 4;
	//在c++中该语法有误,d1 和 4 不是一种类型,不能赋值
	//枚举具有类型检查
	//避免命名污染,与其他地方冲突

	printf("%d\n", s);
	printf("%d\n", d);
	printf("%d\n", d1);
	return 0;
}

优点

在这里插入图片描述

联合(共用)

类型的定义

union Un
{
	char c;
	int i;
};//两个对象,同一时间只用一个
int main()
{
	union Un u;
	return 0;
}

特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

int check_sys()
{
	union u
	{
		char c;
		int i;
	}u;
	u.i = 1;
	return u.c;
}
int main()
{
	if (1 == check_sys())
	{
		printf("小");
	}
	else
		printf("大");
	return 0;
}

大小计算

需要对齐(最大对齐数的整数倍),如:在这里插入图片描述

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值