C语言中结构体详解

发布于:2022-10-15 ⋅ 阅读:(387) ⋅ 点赞:(0)

目录

结构体介绍

一、建立结构声明

二、结构变量的定义和初始化

三、结构体的内存对齐

四、修改默认对齐数

五、结构体传参

结构体介绍

        C语言是一门面向功能的的开发语言,没有面向对象的概念,但是C语言提供了结构体来描述复杂对象,结构体并不属于内置类型,需要使用者自己建立结构声明(也被称作模板)。


提示:以下是本篇文章正文内容,下面案例可供参考

一、建立结构声明

        结构声明的一般形式(也被称作模板):

struct 结构名{

成员列表

};

        具体结构声明

struct book{
    char name[20];
    int age;
};

        首先是关键字struct,它表明跟在其后的是一个结构,后面是一个可选的结构名,在代码块中的是结构成员列表,每个成员都用自己的声明来描述,成员可以是任意的一种C的数据结构也可以是其他结构,结尾的分号是必须的它表示结构布局结束,把结构声明在何处表示了该结构体的储存类别,结构声明在函数内,就是一个具有自动存储期、块作用域且无连接的模板,在函数外声明时,就是一个静态存储期、文件作用域、外部链接的模板。

        结构体是一种数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据、需要存储空间;

        特殊结构声明(省略结构名的匿名机构声明)

struct{    //省略模板(结构体类型)名称的特殊声明
    char book[20];
    int age;
};

        省略结构名的结构声明,无法用模板(结构体类型)创建变量,只能在结构声明时创建结构体变量。

二、结构变量的定义和初始化

        在结构声明后,我们就可以通过模板来定义一个结构体变量,可以在结构声明时创创建或者在模块作用域中使用模块(结构体类型)创建。

        

struct book{    //在结构声明时定义变量
    char book[20];
    int age;
}s1,s2;

struct book s3;    //在结构声明的作用域中使用模板定义变量

        在定义一个变量后我们就要对它初始化,结构体变量的初始化,结构体变量的初始化又以下几种方式:

struct book{
	char name[20];
	int age;
}s1,s2={"laozi",20};    //在声明定义的同时初始化

int main() {
	struct book gg={"jianai",20};    //使用模板定义变量的时初始化
	gg.age = 20;
	gg.name[gg.age] = "gg";          //更改结构体变量成员内容
}

三、结构体的内存对齐

        了解了结构体的使用方法,还有一个问题结构体作为自定义类型,他在内存的开辟空间时多少呢,每个成员占用多少内存空间。

	struct book{
		char name;
		int age;
		char str;
	}s1,s2={'a',20,'b'};
int main() {
	printf("%zd",sizeof(s2));
}

     

          两个char的占用两个字节,一个int占用四个字节,拿s2的大小总共是六个字节,但实际sizeof计算s2的大小却是12个字节???

        这里就要提到结构体的内存对齐规制了:

         

 

        为什么存在内存对齐?

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

        2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访 问。 

四、修改默认对齐数

        #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。

#pragma pack(1)    //设置默认对起数为1
	struct book{
		char name;
		int age;
		char str;
	}s1={'a',20,'b'};
#pragma pack()    //在定义结构体变量后还原默认对起数
int main() {

	printf("%zd\n",sizeof(s1));
}

        我们在修改默认对齐数为1是,所有成员的对齐数都为1,成员偏移量可以是任何数,所以1+4+1=6个字节的大小。

五、结构体传参

	struct book{
		char name;
		int age;
		char str;
	}s1={'a',20,'b'};
	void gg_1(struct book s) {
		printf("%c %d %c", s.name, s.age, s.str);
}
	void gg_2(struct book* s) {
		printf("%c %d %c", s->name, s->age, s->str);
	}
int main() {
	gg_1(s1);
	gg_2(&s1);
}

        这里我们封装了两个打印结构体成员内容的函数,一个是传值,一个是传址,以上两个函数均能实现目的,那么他们的区别在哪里呢?

        函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。 如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降,所以相较于传值,传址的速度和占用空间都要跟优。

        

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到