程序员成长之旅——C语言自定义类型

结构体

结构体类型的创建

首先要知道结构体是什么?

  • 结构体是一些值的集合;
  • 这些值可以是不同的类型。

这样才可以创建一个结构体。
举个例子

struct Stu
{
 	char name[20];//名字
 	int age;//年龄
 	char sex[5];//性别
 	char id[20];
};//分号一定要有

特殊的结构体的创建

struct
{
 	int a;
 	char b;
 	float c;
}x;
struct
{
 	int a;
 	char b;
 	float c;
}a[10],*p;

上面两种结构体创建声明时,省略了标签tag,也就是struct后面的东西。
那么可以直接用p=&x吗?
警告:编译器会把他们当成两个不同的类型所以是非法的。
结构体的自引用

struct Node
{
 	int data;
 	struct Node* next;//必须是指针
};
typedef struct
{
 	int data;
 	Node* next;
}Node;//这样写是完全不行的
//正确的应该是
typedef struct Node
{
 	int data;
 	struct Node* next;
}Node;
结构体的初始化
struct point
{
 	int x;
 	int y;
}p = {1,2};//声明类型的同时定义结构体的变量以及初始化
struct point p1 = { 1,2 };//定义结构体的变量以及初始化
struct Node
{
 	int data;
 	struct point f;
 	struct Node* next;
}n1={5,{1,2},NULL};
struct Node n2 = { 5,{1,2},NULL };//结构体嵌套初始化
结构体内存对齐

结构体内存对齐的大小求值主要是通过下面四个步骤计算:

  • 第一个成员在结构体偏移位为0的地址上
  • 其它成员变量要对齐到某个数字(对齐数)的整数倍上
    对齐数:编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8,Linux中的默认值为4
  • 结构体最终数为最大对齐数的整数倍数
  • 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

举个例子:

struct S1
{
 	char a;    // 1  
 	double b;   //  8 
 	char c;//  1  
};
//大小是多少?
//结构嵌套内存对齐
struct S2
{
 	char a;    // 1  
 	struct S1 p;//24
 	double b;   //  8 
};
int main()
{
 	printf("%d\n", sizeof(struct S1));//24
 	printf("%d\n", sizeof(struct S2));//40
 	system("pause");
 	return 0;
}

根据上面的步骤来不难计算出来,24和40。

我们有没有思考过为什么存在内存对齐?

//1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

//2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问只需要一次。>
//3.总的来说:结构体内存对齐就是用空间换时间。

设计结构体的时候我们要节省空间又要节省时间,那什么样才是最佳的结构体设计呢?

struct S
{
 	char a;
 	double b;
 	char c;
};
struct S1
{
 	char a;
 	char c;
 	double b;
};

S1明显比S更节省空间。
如果对齐数不合适的时候,我们可以怎么办呢?
修改对齐数

#pragma pack(4)
struct S
{
 	char a;
 	double b;
 	char c;
};
#pragma pack()//取消默认对齐数
int main()
{
 	printf("%d\n", sizeof(struct S));//16
 	system("pause");
 	return 0;
}
结构体位段的实现

位段的声明
位段的声明和结构体是类似的,只有两点不同。

  • 位段的成员必须是int,unsigned int,signed int或者char类型。
  • 位段的成员名后边有一个冒号和一个数字。

举个例子

struct A
{
 	int a : 2;
 	int b : 5;
 	int c : 10;
 	int d : 30;
};
int main()
{
 	printf("%d\n", sizeof(struct A));//8
 	system("pause");
 	return  0;
}

在这里插入图片描述

和结构体比较,位段可以很好的节省空间,但是存在跨平台问题。

位段计算大小时不考虑对齐问题。

枚举

定义
enum DAY//星期
{
 	Mon,
 	Tues,
 	Wed,
 	Thur,
 	Fri,
 	Sat,
 	Sun
};
enum SEX//性别
{
 	MALE,
 	FEMALE,
 	SECRET
};
enum COLOR//颜色
{
 	RED,
 	BLUE,
 	BALCK,
 	WRITE
};

上面的enum SEX, enum COLOR ,enum DAY,都是枚举类型,{ }里面的是枚举常量。
枚举的默认初值是0,然后依次递增加一,当然也是可以赋初值。

enum COLOR//颜色
{
 	RED=1,
 	BLUE,//2
 	BALCK,//3
 	WRITE=8
};
特点

1.增加代码的可读性和可维护性
2.便于调试
3.一次可定义多个变量
4.防止了命名污染(封装)
5.和#define比较有类型检查,更加严谨

使用

在这里插入图片描述

联合

定义

联合是一种特殊的自定义结构体,这个结构体包括了多个成员,而这些成员共用一个空间,因此联合也叫作共用体。
在这里插入图片描述

特点

联合的成员共用一块内存空间,这样一个联合的内存空间至少是最大成员的大小。
在这里插入图片描述
在这里插入图片描述

计算
  • 联合的大小最小也是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
    举例
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从零出发——

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值