C语言结构体(struct)

1.结构体类型的说明

前面我们学的数据类型都只包含一种数据类型,即使是数组,也只能是同一类型的多个元素。在实际应用中,通常存在由多种不同类型的数据组成的实体,如一个职工的数据包括编号,姓名,性别,出生日期,文化程度等等。如果用独立的简单数据项分别表示它们,就不能体现数据的整体性,不便于操作,针对这种问题,C语言规定可以用“结构体”数据类型来描述。

2.结构体类型定义的一般形式

结构体类型是一种“构造”而成的数据类型,那么在说明和使用它之前必须先定义它,也就是构造它。如同在说明和调用函数之前要先定义函数一样。结构体类型和系统预定义的标准类型一样,可以用来定义变量,结构体类型的一般形式:

struct 结构体类型名
{
 成员变量说明列表
};

 其中花括号内的内容是该结构体类型的成员说明,每个成员说明的形式为:

数据类型符 成员变量名;

例如,由年,月,日组成的结构体类型为:

struct date
{
int year;
int month;
int day;
};

 又如一个职工实体的结构体类型为:

struct employee
{
long no;//编号
char name[20];//名字
char sex;//性别
struct date birth;//出生日期
char education[30];//教育程度
double salary;//工资
long IDcard;//省份证号码
char addr[40];//家庭住址
};

 对以上说明:

1.

struct是定义结构体类型的关键字,struct后面的“结构体类型名”,是任意选取的,但应符合标识符的命名规则。建议使用具有一定意义的单词作为结构体类型名。

2.

花括号括起来的是结构体成员变量的说明,按照之前变量的定义方式就可以,虽然成员变量的定义形式同变量定义,但不能直接使用。

3.

结构体成员变量的类型可以不相同。

4.

结构体类型struct employee内含有一个结构体类型成员birth,说明结构体可以嵌套定义,但是这种嵌套不能包含自身,即不能自己定义自己(因为这样的结构体变量的为无穷大)。但是可以通过指针访问自己(即定义一个结构体指针变量)如:

struct node
{
int date;
struct node* next;
};

 5.

定义一个结构体类型,并不意味着系统将分配一段内存单元来储存各个数据项成员,这只是定义类型而不是定义变量。他告诉系统该结构体由哪些类型的成员构成,并把他们当作一个整体来处理,struct employee是程序设计者自定义的类型,它与系统预定义的标准类型一样,可以用来定义变量,使变量具有struct employee类型。如:struct employee worker,workers[20];分别定义了struct employee 结构体类型的变量worker和struct employee 结构体类型的数组workers。

1.匿名结构体

匿名结构体只能使用一次

struct
{
char c;
int i;
}s={'x',100};

 ps:匿名结构体中含有变量s.

2.结构体的重命名

typedef struct Node
{
	int date;
	struct Node* next;
}Node;

这种写法等同于下面的:

struct Node
{
	int date;
	struct Node* next;
};
typedef struct Node Node;

 上述代码都是将结构体struct Node重命名为Node。

 3.结构体的内存对齐

结构体的对齐规则:

1.

结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。

2.

其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数=编译器默认的对齐数与该成员变量大小的较小值。vs默认对齐数为8,Linux中gcc没有默认的对齐数,对齐数就是其成员自身大小。(不同的编译器默认的对齐数可能不同)

3.

结构体总大小为最大对齐数(结构体中所有对齐数中最大的)的整数倍。

4.

如果存在嵌套结构体的情况,嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍,结构体的总大小就是所有对齐数(含嵌套结构体成员的对齐数)的整数倍。

 例题1;

代码自取:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct S
{
	char c1;
	int i;
	char c2;
};
int main()
{
	struct S s = { 0 };
	printf("%zd", sizeof(s));
	return 0;
}

例题2:

 

代码自取:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct S
{
	char c1;
	char c2;
	int i;
};
int main()
{
	struct S s = { 0 };
	printf("%zd", sizeof(s));
	return 0;
}

下面我们画图来解析上面两个例题

从上面我们可以知道,虽然两个例题结构体内的成员都是一样的,但是成员的顺序的不同也会影响总的字节大小。 

 例题3:

代码自取:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct S1 
{
	char c1;
	char c2;
	int i;
}s1;
struct S2
{
	char c3;
	struct S1 s1;
	double d;
}s2;
int main()
{
	printf("%zd", sizeof(s2));
	return 0;
}

依旧是画图解释哦:

 

 针对上述例题,我们不难得出,在设计结构体时,既要满足对齐,又要节省空间,第一种方法,可以让占空间小的成员尽量集中在一起。第二种方法,我们可以修改系统默认的对齐数。修改方法如下:#pragma pack(n)这个预处理指令,可以将编译器的默认对齐数修改为n。紧接着在其下面再加一条#pragma pack()则可以取消设置的默认对齐数。

4,结构体的位段

位段式是专门用来节省空间的。

struct S
{
	int _a : 2;//2代表_a只占两个bit,下面的数字意义以此类推
	int _b : 5;
	int _c : 20;
	int _d : 30;
};

 位段的内存分配:

1.位段的成员可以是int,unsigned int ,signed int或是char等类型。

2.位段的空间是按需要以四个字节(int)或一个字节(char)的方式来开辟的。

3.位段在不同的平台下可能是不同的:16位平台下,int是2个字节,如果int _a:27;则出现错误,因为27>2*8.

4.不能对位段的成员取地址(&)。

位段的跨平台问题:

1.int位段被当成有符号数还是⽆符号数是不确定的。

2.位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会 出问题。

3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。

4.当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃 剩余的位还是利⽤,这是不确定的。

下面在vs上解析下面代码:

#define _CRT_SECURE_NO_WARNINGS 1
#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; //00001010
	s. b = 12;//00001100
	s.c = 3;  //00000011
	s.d = 4;  //00000100
	return 0;
}

 

 结构体的内容就到这里啦!码字不易,请留下你的点赞,关注,评论吧!谢谢咯!雯雯文下次再和大家见面咯!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值