定义
在C语言中,结构体(struct)是一种用户自定义的复合数据类型,允许将不同类型的变量组合在一起形成一个新的数据类型。结构体由一组称为成员(member)的变量组成,每个成员可以是任何合法的数据类型,包括基本类型、指针、数组、甚至其他结构体。
就像是我们的身份证一样,上面写满了我们的姓名、性别、出生年月日等等,各个不同类型的变量,也就是各个成员们组合到了一起,再填上于我们相关的信息,就变成了一个可以代表我们的“结构体”。
结构体的定义形式如下:
struct 结构体名
{ 数据类型 成员名1;
数据类型 成员名2; // 可以有更多的成员 };
把身份证变为结构体就是这样:
struct sfz{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//身份证号
//……
};//注意这个分号,这很重要,不要漏了,不然就构不成结构体了。
结构体的特殊声明-匿名结构体(Anonymous Struct)
在某些情况下,我们可能只需要一个临时的结构体类型,而不需要为其定义一个具体的结构体名称。这时可以使用匿名结构体,即在声明结构体变量时直接定义结构体内容,而不指定结构体名称。例如:
struct {
int x;
int y;
} point;//这里的point就是一个匿名结构体变量,它包含了两个成员x和y。
结构体变量的创建和初始化
这部分很死,看看就好了。
#include
struct Stu{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号};
int main(){
//按照结构体成员的顺序初始化
struct Stu s = { "张三", 20, "男", "20230818001" };
printf("name: %s\n", s.name);
printf("age : %d\n", s.age);
printf("sex : %s\n", s.sex);
rintf("id : %s\n", s.id);
//按照指定的顺序初始化
struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = "⼥ };
printf("name: %s\n", s2.name);
printf("age : %d\n", s2.age);
printf("sex : %s\n", s2.sex);
printf("id : %s\n", s2.id); return 0;}
结构的自引用-结构体的递归?
在结构中包含⼀个类型为该结构本⾝的成员,是否像函数中递归一样,包含自己呢?比如,现在我们定义⼀个链表的节点:
struct Node{
int data;
struct Node next;
};
你认为这是对的吗,如果这是对的,那 sizeof(struct Node) 是多少?
想不出来吧,其实仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的大小就会⽆穷的大,是不合理的。
而正确的方式便是如此:
struct Node{
int data;
struct Node* next; };
结构体中的内存对齐(Memory Alignment in Structs):
结构体中的内存对齐是指编译器在安排结构体中的成员变量在内存中的存放位置时所采取的规则。它的目的是为了提高内存访问效率和硬件兼容性。
毕竟不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。
总体来说:结构体的内存对⻬是拿空间来换取时间的做法
内存对齐规则(Memory Alignment Rules):
- 每个成员变量都有一个对齐要求,通常是其自身大小。
- 结构体的大小是其成员变量大小的总和,但编译器会根据最大对齐要求对结构体进行对齐。
- 如果结构体的某个成员变量的地址不满足其对齐要求,则编译器可能会在其前面插入额外的字节,以保证后续成员变量的地址满足对齐要求。
示例(Example):
考虑以下结构体:
struct Example { char c; int i; };
假设char对齐到1字节,int对齐到4字节,那么该结构体的内存布局可能如下:
Offset 0: | c | (1字节)
Offset 1: | | (对齐填充)
Offset 4: | i | (4字节)
编译器在char类型后面插入了3个字节的对齐填充,以保证int类型变量i位于4字节边界上。
结尾
好好好,看得出来。根本没学会结构体。