自定义结构体类型

目录

结构体

结构的声明

结构体变量的几种表达形式

1 结构体变量写在结构体声明的之后

2 结构体变量的定义也可以与结构体的声明同时,这样就简化了代码。

3 对结构体的成员逐个赋值:

4 可以对结构体进行整体赋值:有2种

第一种

第二种

匿名结构体

结构体的自引用

结构内存对齐

根据下面的几个点来注意

默认对齐数

位段

 位段的内存分配

位段组成

结构体的应用    

结构数组 

  

结构体传参

枚举

联合体



结构体

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

结构的声明

struct tag
{
	member_list;//成员变量
};

结构体变量的几种表达形式

1 结构体变量写在结构体声明的之后

#include"stdio.h"
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};
int main()//下面为结构体变量的初始化
{
	struct stu ok = { "haha",21,"man","okkk"};
	printf("%s %d %s %s" ,ok.name,ok.age,ok.sex,ok.id);
};

2 结构体变量的定义也可以与结构体的声明同时,这样就简化了代码。

#include"stdio.h"
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}stu = { "okk",20,"man","ok" };

3 对结构体的成员逐个赋值:

#include"stdio.h"
#include"string.h"
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};
int main()//下面为结构体变量的初始化
{
	struct stu stu1;
	strcpy(stu1.name, "ok");//数组名为常量,不能初始化
	stu1.age = 20;
};

4 可以对结构体进行整体赋值:有2种

第一种

#include"stdio.h"
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
};
int main()
{
	struct stu ok = { "haha",21,"man","okkk"};
	printf("%s %d %s %s" ,ok.name,ok.age,ok.sex,ok.id);
};

第二种

struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}stu1;
int main()
{
	stu1 = stu { "okkk", 20, "oo", "ooo"};结构体定义在声明同时进行
}

匿名结构体

下面来介绍一下匿名结构体类型顾名思义,就是没有名字的结构体类型。

struct
{
	int a;
	int b;
	float c;
}x;//必须要有这个才能引用,好比一个变量。

匿名结构体只能使用一次,前面如何使用已经说过了,结构声明和结构体定义一起进行。

结构体的自引用

下面来看一下结构体的自引用

struct Node
{
	int data;
	struct Node next;
};

 上图就是表示结构体的自引用比如说一个数组内有1,2,3,4,5。出现1之后,要立马出现2,  这个就是表示结构体的自引用,而上面写的正不正确,运行一下。

  程序出现错误,Node表示正在运行,说明文件不断在引用,说明这个引用是错误的。

struct Node
{
	int data;
	struct Node* next;

};

这个就表示,第一个数字和下一个数字的地址,这样就不会冲突。就不会产生结构体内的不断死循环。

结构内存对齐

#include"stdio.h"
struct S
{
	char c;
	int a;
	char c1;
};
struct S1
{
	char c;
	char c1;
	int a;
};

int main()
{
	struct S s = { 0 };
	struct S1 s1 = { 0 };
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s));
}

 为什么不是6和6呢?这就涉及到了一个结构体的内存对齐问题

下面用图表示一下可能会更加好

根据下面的几个点来注意

1. 第一个成员在与结构体变量偏移量为 0 的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
3.对齐数 = 编译器默认的一个对齐数 与 该成员大小的 较小值
4.  结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
5. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

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

而如果是内存对齐就这读取二次,这个还是比较简单一点的,如果数据在大就会,内存对齐的优势就会产生。

默认对齐数

这里就有小伙伴就会说,我不想放弃内存空间又想得到时间快的话,就设置默认对齐数,
#include"stdio.h"
#pragma pack(2)//修改默认对齐数为2//节省2个空间
struct S
{
	char c;
	int a;
	char c1;
};
struct S1
{
	char c;
	char c1;
	int a;
};

int main()
{
	struct S s = { 0 };
	struct S1 s1 = { 0 };
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s));
}

#include"stdio.h"
#include"stddef.h" 
struct S
{
	char c;
	char  a;
	int  c1;
};
int main()
{
	printf("%d\n", offsetof(struct S, c));//与原始位置偏移的多少。
	printf("%d\n", offsetof(struct S, a));
	printf("%d\n", offsetof(struct S, c1));
}

offsetof是查找与初始位置偏移量的多少。

位段

下面先来看一个例子

#include"stdio.h"
struct S
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	struct S s;
	printf("%d\n", sizeof(s));可以猜一猜字节会是多少
}

有的小伙伴可能会猜到字节是16。

 其实是8,这就涉及到了一个我们本次要说的位段问题。

#include"stdio.h"
struct S
{
	char a: 3;
	char b: 4;
	char c: 5;
	char d: 4;
};
int main()
{
	struct S s = {0};
	s.a = 10;
	s.b = 20;
	s.c = 3;
	s.d = 4;
}

来看下字符的内存分配,我们首先看一下它们总共占了几个字节,a和b占一个字节,c占一个字节,d占一个字节,总共三个字节,分别将他们由10进制,变成2进制,再截取他们的所占的位段。

             上图所示就是,所占的内存。

 上面就是&s地址所占的内存的大小

分别所占的内存是2 2 3 4

总结

 位段的内存分配

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

位段组成

1. 位段的成员必须是 int unsigned int signed int
2. 位段的成员名后边有一个冒号和一个数字。
上面主要说的是结构体的的概念和如何存储的,下面该说一下结构体如何应用的。

结构体的应用    

结构数组 

  

#include"stdio.h"
struct stu
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}stu1[5] ;
int main()
{
	int a;
	struct stu stu1 [5]= { { "okkk", 20, "oo", "ooo"  },{"ooook",30,"iiii","ooooo"} };
	int length = sizeof(stu1) / sizeof(struct stu);
	int i = 0;
	for (i = 0; i < length; i++)
	{


		printf("%s %d %s %s\n", stu1[i].name, stu1[i].age, stu1[i].sex, stu1[i].id);
	}
}

先定义,后初始化,整体赋值。

结构体传参

#include"stdio.h"
struct S
{
	int a;
	char c;
	double d;
};
void Init(struct S* ps)
{
	ps->a = 100;
	ps->c = 'w';
	ps->d = 3.14;
}
void print1(struct S tmp)
{
	printf("%d %c %lf", tmp.a, tmp.c, tmp.d);
}
void print2(struct S* ps)
{
	printf("%d %c %lf",ps->a,ps->c,ps->d);
}
int main()
{
	struct S s = { 0 };
	Init(&s);//地址传参
	print1(s);//值传参
	print2(&s);//地址传参比值传参更省空间。
}

枚举

什么是枚举,枚举就是举例,把你所要描述的东西,一个列举出来,就比如说衣服,衣服有很多种颜色,红色,黑色,白色,各种颜色,等等。这个就是枚举。
#include"stdio.h"
enum color
{
	gree,
	red,
	yellow
};
int main()
{
	enum color s = gree; //我们选了一个绿色
};
这些可能取值都是有值的,默认从 0 开始,一次递增 1 ,当然在定义的时候也可以赋初值。 例如
这个就是初始值开始的,如图
#include"stdio.h"
enum color
{
	gree,
	red,
	yellow
};
int main()
{
	enum color s;
		printf("%d\n", gree);\\从零开始的初始值

};

 这个就是从初始值零开始的

 上图就是赋值从1开始的。

联合体

联合类型的定义 联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以 联合也叫共用体)。
#include"stdio.h"
union Un
{
	char c;
    int i;
};
int main()
{
	union Un un;
	printf("%d\n", sizeof(un));
}

                 小伙伴们可以猜下,这个un变量名,占几个字节,有点可能会猜成5个字节,因为一个字节和四个字节,下面运行下代码可以看下,占几个字节。

 占4个字节,这就引出了联合体的定义他们共用一个空间。既然他们共用一个空间话,那它们地址应该相同。

 它们的地址确实相同,如果不理解联合的定义,也可以理解成它们的地址相同。那么问题来了,那么联合体的字节是怎么确定的呢?联合体的字节是它们中的类型占的最大的字节。比如说整型和字符类的在一起,那么联合体的字节就是4。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

邋遢道长!

谢谢,大哥

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

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

打赏作者

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

抵扣说明:

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

余额充值