结构体

结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
参考:初识结构体

结构的声明

12345
struct tag{	member-list; }variable-list;

例如描述一个学生,声明一个结构体类型,通过学生类型来创建学生变量:
——姓名、电话、性别、年龄

12345678910111213141516
struct Stu{      char name[20];      char tele[12];      char sex[5];      int age;}s4,s5,s6;//s4,s5,s6和s3一样,都是全局的结构体变量 struct Stu s3;//创建了s3这个结构体的全局变量 int main()   {      struct Stu s1;    struct Stu s2;//创建了s1,s2两种结构体变量(局部变量)    return 0;  }

特殊的声明

匿名结构体类型

12345678910111213
struct{	int a;	char b;	float c;}x;//创建匿名结构体类型时,必须在后面写上结构体类型变量,否则之后无法创建 struct {	int a;	char b;	float c;}a[20],*p;//*p匿名结构体指针

结构体自引用

自引用方式

12345
struct Node{	int data;	struct Node* next;};
123456789101112
typedef struct Node{	int data;	struct Node* next;}Node; int main(){	struct Node n1;	Node n2;	return 0;}

结构体变量的定义和初始化

123456
struct Point{	int x;	int y;}p1;//声明类型的同时定义变量p1struct Point p2;//定义结构体变量p2

定义变量同时赋值:

12345678910111213
struct S{    char c;    int a;    double d;    char arr[20];}; int main() {    struct S s = {'c',100,3.14,"hello world"};//结构体成员初始化    printf("%c,%d,%lf,%s\n",s.c,s.a,s.d,s.arr);//结构体成员的访问    return 0;}

打印的结果是:c 100 3.140000 hello world

结构体成员的嵌套

123456789101112131415161718192021
#include <stdio.h>struct T{    double weight;    short age;}; struct S{    char c;    struct T st;    int a;    double d;    char arr[50];}; int main() {    struct S s = {'c',{55.4,30},100,3.14,"hello world"};    printf("%lf\n",s.st.weight);//访问嵌套的结构体变量    return 0;}

打印的结果是55.400000
嵌套的结构体变量就是在大括号里加大括号

结构体内存对齐

12345678910111213141516171819202122
#include <stdio.h>struct S1{    char c1;    int a;    char c2;}; struct S2{    char c1;    char c2;    int a;}; int main(){    struct S1 s1 = {0};    printf("%d\n",sizeof(s1));//12    struct S2 s2 = {0};    printf("%d\n",sizeof(s2));//8}

如何计算结构体大小?
——对齐规则
1、第一个成员在与结构体变量偏移量为0的地址处
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
3、结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4、如果嵌套了结构体的情况,嵌套结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

为什么要内存对齐?
——性能强,兼容性强

修改默认对齐数

使用#pragma()指令来修改默认对齐数。

123456789101112131415
#include <stdio.h>#pragma pack(4)//设置默认对齐数是4struct S{    char c1;//1    //7    double d;//8};#pragma pack()//取消设置默认对齐数int main(){    struct S s;    printf("%d\n",sizeof(s));    return 0;}

默认的对齐数是8,#pragma pack(4)修改默认对齐数为4,使原先的结构体s的大小由16变成了12。(中间浪费的字节由8变成了3)

偏移量计算offsetof

size_t offsetof(structName, memberName);
用于计算偏移量,它不是函数,是一个宏。

12345678910111213141516
#include <stdio.h>#include <stddef.h>struct S{    char c;    int i;    double d;}; int main(){    printf("%d ",offsetof(struct S, c));    printf("%d ",offsetof(struct S, i));    printf("%d ",offsetof(struct S, d));    return 0;}

打印的结果是0 4 8

结构体传参

结构体传参,可以传地址,也可以传本身。

123456789101112131415161718192021222324252627282930313233
#include <stdio.h>struct S{    int a;    char c;    double d;}; void Init(struct S* ps){    ps->a = 100;    ps->c = 'w';    ps->d = 3.14;} void print1(struct S tmp){    printf("%d %c %lf\n",tmp.a,tmp.c,tmp.d);} void print2(const struct S* ps){    printf("%d %c %lf\n",ps->a,ps->c,ps->d);} int main(){    struct S s = {0};    Init(&s);    print1(s);//传值    print2(&s);//传址    return 0;}

结构体传参,最好传地址,因为传的值有可能过大,系统开销大,通过传地址,可以节约系统开销。

🔍 ×