结构体是不同类型值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量
结构体和其他类型基础数据类型一样,例如 int类型、char类型
只不过结构体可以自定义数据类型进行复杂对象的描述就会使用到结构体
结构体声明的语法形式:
方法一:
struct book
{
char a[20];
char b[15]; 成员列表
int c;
};
int main()
{
struct book t;
}
方法二:
struct book
{
char name[20];
char id[15]; 成员列表
int price;
}s1,s2,s3;
全局变量,局部变量struct
{
int a;
char b;
float c;
}s;
匿名结构类型,但是只能用一次例题:
如果二种匿名结构类型的成员相同,类型是否相同?
struct
{
int a;
char b;
float c;
}s;
struct
{
int a;
char b;
float c;
}*pd;3
int main()
{
*pd = s;
二种类型是否相等?
}
下面是错误的示范
struct G
{
int f;
struct G;
};
int main()
{
struct G s;
}
这种想想都知道是不可以运行的了,无限循环,因为如果要计算结构体的大小,那大小是多少
正确的自引用方式:
struct Node
{
struct Node* next;
};
是否可以用匿名结构体进行结构体自引用?
是否可以用 typedef 进行类型重命名后,进行结构体自引用?
typedef struct
{
int data;
Node* next;
}Node;
把匿名结构体,用 typedef 重新命名为 Node,然后进行结构体自引用
正确的写法:
typedef struct Node
{
int data;
struct Node* next;
}Node;
有了上面的结构体类型,接下来就是定义和初始化了
struct K
{
int a;
char b;
};
struct H
{
int a;
char b;
}pd; //这个是全局变量
int main()
{ // 定义变量的同时,赋初始值
struct K b = { 6,'G'};
struct H pd = { 66,'A'};
printf("%d %c\n", b.a, b.b); //打印
printf("%d %c\n", pd.a, pd.b); //打印
return 0;
}
结构体嵌套:指的是结构体里包含结构体
struct KG
{
int a;
char b;
};
struct H
{
int a;
char b;
struct KG q; // 结构体嵌套
};
int main()
{
struct H pd = { 66,'A',4,'J'};//初始化
printf("%d %c %d %c\n", pd.a, pd.b,pd.q.a,pd.q.b); //打印
return 0;
}
这里我们来探讨一下结构体是怎么计算大小?
struct S
{
char a;
int b;
char c;
};
int main()
{
struct S pd = { 0 };
printf("%d\n", sizeof(s));
return 0;
}
结果:

为什么结果是 12 呢?
如果想要正确的计算,首先得掌握结构体的对齐规则:
图解:
我们先前算的 6 为什么不正确呢?
反而结果是 12


练习题
struct S2
{
char c1;
char c2;
int i;
};
printf("%d\n", sizeof(struct S2))
图解:

练习题 1
struct S
{
double c1;
char c2;
int i;
};
printf("%d\n",sizeof(struct S));
图解:

练习题 2
结构体的嵌套的计算方式
struct S
{
double c1;
char c2;
int i;
};
struct S3
{
char c1;
struct S s1;
double d;
};
int main()
{
struct S3 s3 = { 0 };
printf("%d\n", sizeof(s3));
return 0;
}
图解:

内存对齐总是会浪费空间,为什么存在内存对齐?
原因有二个:
那在设计结构体的时候,我们既要满足对齐,又要节省空间
如何做到:
例如:
S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别
struct S1
{
char c1;
int i;
char c2;
}; s1 的大小是 12 个字节
------------------------------------
struct S2
{
char c1;
char c2;
int i;
}; s2 的大小是 8 个字节
计算结构体的大小的小技巧
所有结构体成员加起来的大小结构体成员大小中最大的那个数所有结构体成员加起来的大小是否是结构体成员大小中最大的那个数的倍数计算结构体大小的默认对齐数是可以修改的
#pragma 这个预处理指令,可以改变我们的默认对齐数
#pragma pack(2)//设置默认对齐数为2
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
这个的意义在于:结构在对齐方式不合适的时候,我可以自己更改默认对齐数
offsetof 是计算某个结构体成员离最开始的地址(0)的偏差是多少
offsetof 的头文件是:《stddef.h》
offsetof 的使用:
#include<stddef.h>
struct S
{
char c1;
int i;
char c2;
};
int main()
{
printf("%d\n", offsetof(struct S, i));
return 0;
}
结果:
之前计算过,i 的偏移量是 4

结构体传参有二种方法
1.形参
打印时用的是.操作符
如果是传的是形参的方式,传的是整个数结构体的大小,比较占空间
struct peo
{
char name[20];
char srx[10];
int tele[12];
};
print(struct peo str)
{
printf("%s %s %d\n", str.name, str.srx, str.tele);
}
int main()
{
struct peo s = { "小明","男","15846092751" };
print1(s);
}
2.实参以指针的方式
打印时用的是->操作符
这种方式传的是地址,最大也就是4个或8个字节
struct peo
{
char name[20];
char srx[10];
int tele[12];
};
print1(struct peo* str)
{
printf("%s %s %d\n", str->name, str->srx, str->tele);
}
int main()
{
struct peo s = { "小明","男","15846092751" };
print2(&s);
}