14.C基础_结构体

定义与使用

1、定义

定义结构体:

定义结构体时,需要注意最后的分号必须加上。

定义结构体时,成员只去声明类型,不进行赋值。赋值在定义结构体变量时进行。

struct 结构体名{
    结构体成员列表
};                //注意这里的分号

定义结构体变量:

方法1:正常定义结构体变量

struct 结构体名 结构体变量名;

方法2:定义结构体时,定义结构体变量

struct 结构体名{
    结构体成员列表
}变量名1,变量名2; //直接在这里写变量名,变量名之间用,隔开               

2、初始化结构体变量

情况1:全部成员赋值

全部成员赋值就是在定义结构体变量后直接加上成员值,各个成员值之间用" , "分隔。

struct 结构体名 结构体变量名 = {依次赋值的成员值};

情况2:部分成员赋值

部分成员赋值需要在赋值时指定成员并赋值。

struct 结构体名 结构体变量名 = {
    .成员1 = 值,
    .成员2 = 值
};

情况3:定义结构体时,定义结构体变量的初始化

struct 结构体名{
    结构体成员列表
}变量名 = {成员值};

3、访问结构体变量

方式1:当为结构体变量时,用" . "来访问成员

方式2:当为结构体指针时,用" -> "来访问成员

结构体数组

结构体数组就是一个数组,它的成员是一个结构体变量。

定义与赋值:

定义与赋值的方法与一维数组完全一样。

struct 结构体名 数组名[数组大小] = {{第1个结构体成员初始化值},{第2个结构体成员初始化值}};

结构体嵌套结构体

结构体嵌套结构体就是结构体中成员的类型可以是结构体。

作用:

解决不同结构体中重复的、完全一样的部分

示例:

假设现在要创建两个结构体来管理学生、老师的信息。对于学生,有姓名、性别、学分这三个信息;对于老师,有姓名、性别、电话号码这三个信息。可以看到,在学生和老师的信息中姓名、性别这两个信息是重复的。因此可以建立一个结构体来封装它们,这样使得学生和老师的结构体定义变得更加简洁。

代码如下:

#include <stdio.h>
struct both{   //老师和学生共有的成员
	char* name;
	char* sex;
};
struct student{//学生信息结构体
	struct both stu;
	int score;
};
struct teacher{//老师信息结构体
	struct both tea;
	char* phone;
};

int main(){

	//struct both tBothStu = {"stuName","沃尔玛购物袋"};
	struct both tBothTea = {"teaName","纸扎投石车"};

	struct student stu1 = {{"stuName","沃尔玛购物袋"},100};//可以直接赋值结构体
	struct teacher tea1 = {tBothTea,"123124123"};//也可以通过定义的结构体进行初始化

	printf("stu1:name=%s  sex=%s  score=%d\n",\
			stu1.stu.name,\
			stu1.stu.sex,\
			stu1.score
		  );
	printf("tea1:name=%s  sex=%s  phone=%s\n",\
			tea1.tea.name,\
			tea1.tea.sex,\
			tea1.phone
		  );
	return 0;
}

运行结果如下: 

结构体的大小

字节对齐是什么:

对于结构体,编译器会自动对其成员变量进行对齐,以提高数据存取的效率。

结构体大小计算步骤:

相关名词:

  • 自身对齐:数据类型的大小就是自身对齐的大小,例如char为1,int为4
  • 默认对齐:与电脑位数有关。32位默认对齐为4,64位默认对齐为8
  • 有效对齐:有效对齐=min(自身对齐,默认对齐),是结构体中实际占用空间的大小
  • 存放地址:存放地址一定能够整除有效地址

计算步骤:(依次计算成员空间)

  1. 确定自己操作系统的位数,从而确定默认对齐方式
  2. 计算第一个成员,通过公式:" 有效对齐 = min(自身对齐,默认对齐) "计算有效对齐
  3. 查看当前的存放地址是否能够整除有效对齐字节数,不能整除需要补空间对齐。                    注意:补其后能够整除的数值是下一个变量的起始地址,并没有存储数据                            例如:补其后是12,那么实际的有数据的空间只到11                  
  4. 依次计算其他成员空间
  5. 查看最终存放地址是否能够整除" max(全部有效对齐) "

结构体大小手算示例:

假设有一个如下的结构体,在64位的操作系统下计算其结构体大小(假设起始地址为0x00)

struct test{
    char a;
    int b;
    char c;
    char d;
};

 列出如下表格,依次计算存储地址:

变量名类型自身对齐默认对齐有效对齐存储地址
achar18(64位)10 1 2 3
bint48(64位)44 5 6 7
cchar18(64位)18
dchar18(64位)19 10 11

计算a:可以计算出有效对齐为1,存储地址为0,可以整除,所以存储地址为0

计算b:可以计算出有效对齐为4,存储地址为1,不能整除,所以补齐到最小的可以整除4的地址,即:补齐到4。a的空间为0,1,2,3;b的空间为4,5,6,7这四个字节用于存储

计算c:可以计算出有效对齐为1,存储地址为8,可以整除,所以存储地址为8

计算d:可以计算出有效对齐为1,存储地址为9,可以整除,所以存储地址为9

整体大小计算:可以计算出max(全部有效对齐)=max(1,4,1,4)=4,存储地址9不能整除4,所以补齐到最小的可以整除4的地址,即:补齐到12。因此最终结构体大小为0~11,共12字节

位域

什么是位域:

位域就是把一个字节中的二进制位分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

例如:现在有一个字节的空间,可以让bit0~bit2表示信息a,让bit3~bit5表示信息b,让bit6~bit7表示信息c。这样一个字节分为了3个域,域名就是a,b,c;a域的位数为3,b域的位数为3,c域的位数为2。

位域的定义:

位域定义就是把结构体中的成员列表换成位域列表,格式为:<类型> <位域名>:<位域长度>

以例题为例,那么a,b,c这三个域的定义如下:

struct test{
    char a:3;
    char b:3;
    char c:2;
};

对于上述定义,如果按照结构体成员来定义,计算出的大小应该为3字节。而按位域方法定义,计算出来的大小为1字节。这样就节省了空间。

补充练习:结构体大小手算例题 

例题1:

假设有一个如下的结构体,在64位的操作系统下计算其结构体大小(假设起始地址为0x00)

struct test{
    char a;
    short b;
    char c;
    char d;
};

 列出如下表格,依次计算存储地址:

变量名类型自身对齐默认对齐有效对齐存储地址
achar18(64位)10 1
bshort28(64位)22 3
cchar18(64位)14
dchar18(64位)15

 最终补齐地址为6,实际存储空间为0~5,6字节

例题2:

假设有一个如下的结构体,在64位的操作系统下计算其结构体大小(假设起始地址为0x00)

struct test{
    char a;
    double b;
    char c;
    char d;
};

 列出如下表格,依次计算存储地址:

变量名类型自身对齐默认对齐有效对齐存储地址
achar18(64位)10 1 2 3 4 5 6 7
bdouble88(64位)88 9 10 11 12 13 14 15
cchar18(64位)116
dchar18(64位)117 18 19 20 21 22 23

 最终补齐地址为24,实际存储空间为0~23,24字节

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值