📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨
📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】
📢:文章若有幸对你有帮助,可点赞 👍 收藏 ⭐不迷路🙉
📢:内容若有错误,敬请留言 📝指正!原创文,转载请注明出处
文章目录
引言
回顾一下数组存在两个明显的缺陷:
1.定义时必须明确给出大小,且这个大小在以后不能再更改;
2.数组要求所有的元素的类型必须一致。 从数组到结构体的进步之处
一、结构体的概念
结构体属于用户自己的自定义数据类型,也就是一些数据类型的元素集合,这些元素数据类型可以相同,也可不同。
1.结构体可以认为是从数组发展而来的。其实数组和结构体算是数据结构的范畴,数组就是最简单的数据结构、结构体比数组更复杂一些,链表、哈希表之类的比结构体又复杂一些;二叉树、图等又更复杂一些。
2.结构体是用来解决数组的第二个缺陷,可将结构体理解为一个其中元素类型可以不相同的数组。结构体完全可以取代数组,只是在数组可用的范围内数组比结构体更简单。
二、结构体的意义
数组可以理解为一种特殊的结构体,特殊在于封装在内的各个元素类型是相同的。结构体和数组都是作为整体定义,但是使用的时候,都是使用封装的子元素。因此,设置结构体的意义:用于一些需要将不同数据类型的元素结合在一起的场合,而这种是数组无法做到的。
三、结构体的定义
方式1:先定义结构体类型,然后再用类型来定义变量
struct MyStruct
{
int a;
};
struct MyStruct S1;
方式2:定义结构体类型的同时定义结构体变量。
struct MyStruct
{
int a;
}s1;
s1.a=1;
方式3:使用typedef定义结构体
typedef struct MyStruct
{
int a;
}s1;
s1 stu1;
stu1.a = 1;
上述代码案例中s1是struct MyStruct的别名(将struct MyStruct重命名为s1),等同于struct MyStruct。s1是类型名称,而不是变量。
四、结构体的使用步骤
4.1、定义结构体类型
例如:
struct students//定义结构体
{
char name[20];//姓名
unsigned int age;//年龄
int male;//性别
};
4.2、定义结构体变量。
使用第一步定义的类型定义结构体变量。例如:
struct students S1;//定义变量
4.3、访问结构体成员变量。
使用的是结构体变量中封装的各个子元素,而不是结构体变量本身。
例如:
S1.name[0] ='b';//对变量赋值
S1.age = 3;
printf("这个学生的姓名叫%c\n他%d岁了", S1.name[0], S1.age);
五、访问结构体变量中的元素
5.1访问方式
(1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式);
(2)结构体变量中的元素访问方式:用.或者->的方式来访问。
只是C语言规定用结构体变量来访问元素用. ;
用结构体变量的指针来访问元素用->。
(3)结构体的访问方式有点类似于数组下标的方式
(4)结构体变量的点号或者->访问元素本质上还是用指针来访问
5.2结构体对齐访问
(1)结构体中元素的访问本质上用指针方式,结合这个元素在整个结构体中的偏移量和这个元素的类型来进行访问。
(2)结构体要考虑元素的对齐访问,所以每个元素实际占用字节数和自己本身的类型所占的字节数不一定完全一样。(譬如char c实际占字节数可能是1,也可以是2,也可能是3····)
(3)一般来说,用.的方式来访问结构体元素时,可以不用考虑结构体的元素对齐。因为编译器会处理这个细节。但是因为C语言本身是很底层的语言,而且做嵌入式开发经常需要从内存角度,以指针方式来处理结构体及其中的元素,因此还是需要掌握结构体对齐规则。
5.3 结构体为何要对齐访问?
(1)结构体中元素对齐访问主要原因是为了配合硬件,也就是说硬件本身有物理上的限制,因为对齐排布和访问会提高效率,否则会大大降低效率。内存本身是一个物理器件(DDR内存芯片,SoC上的DDR控制器),本身有一定的局限性:如果内存每次访问时按照4字节对齐访问,那么效率是最高的;反之,不对齐访问效率要低很多。
(2)还有很多别的因素和原因,导致我们需要对齐访问。譬如Cache的一些缓存特性,还有其他硬件(譬如MMU、LCD显示器)的一些内存依赖特性,所以会要求内存对齐访问。
(3)对比对齐访问和不对齐访问:对齐访问牺牲内存空间,换取了速度性能;而非对齐访问牺牲访问速度性能,换取了内存空间的完全利用。
结构体对齐的规则和运算
编译器本身可以设置内存对齐的规则,有以下的规则需要记住:
32位编译器,一般编译器默认对齐方式是4字节对齐。
结构体对齐的分析要点和关键:
1、结构体对齐要考虑:结构体整体本身必须安置在4字节对齐处,结构体对齐后的大小必须4的倍数(编译器设置为4字节对齐时,如果编译器设置为8字节对齐,则这里的4是8)。为了避免“坑害”下一个结构体,因此结构体整体必须是4的倍数。
2、结构体中每个元素本身都必须对其存放,而每个元素本身都有自己的对齐规则。
3、编译器考虑结构体存放时,以满足以上2点要求的最少内存需要的排布来算。
六、结构体指针及访问
结构体指针是指向结构体类型的指针变量,它可以用来操作和访问结构体的成员。通过结构体指针,可间接访问和修改结构体成员,而不需要使用结构体变量本身。
下面是一个示例,展示了如何声明和使用结构体指针:
#include <stdio.h>
// 定义一个学生结构体
struct Student {
char name[20];
int age;
float score;
};
int main() {
// 声明一个学生结构体指针变量
struct Student *studentPtr;
// 创建一个学生结构体变量
struct Student student;
studentPtr = &student; // 将结构体指针指向结构体变量
// 使用结构体指针访问和修改结构体成员
strcpy(studentPtr->name, "John");
studentPtr->age = 20;
studentPtr->score = 95.5;
// 打印结构体成员的值
printf("Name: %s\n", studentPtr->name);
printf("Age: %d\n", studentPtr->age);
printf("Score: %.2f\n", studentPtr->score);
return 0;
}
在上面的示例中,我们首先定义了一个指向struct Student类型的结构体指针变量studentPtr。然后,创建了一个struct Student类型的结构体变量student,并将结构体指针指向结构体变量,通过studentPtr =&student;实现。这样就可以通过结构体指针访问结构体的成员。
总结
1.使用结构体指针访问结构体成员的语法是 -> 运算符。例如,studentPtr->name 表示通过结构体指针访问结构体的name成员。
2.需要注意的是,在使用结构体指针之前,必须将其指向有效的内存空间,可以通过创建一个结构体变量或动态分配内存来实现。
3.结构体指针在C语言中非常常用,尤其在处理动态内存分配和传递结构体参数时。它允许我们以指针的方式引用和操作结构体的成员,方便了对结构体数据的存储和处理。