文章目录
前言
一、结构体的声明
1.1 正常声明
1.2 特殊的声明方式(匿名结构体)
1.3 结构体自引用
二、结构体变量的创建和初始化
三、结构体成员的访问
四、结构体对齐
4.1结构体的对齐规则
4.2修改默认对齐数
4.3某变量相对于首地址的偏移
4.4代码示例
五、结构体传参
总结
一、结构体的声明
1.1 正常声明
struct student
{
char name[20];
int age;
}s1, s2;//s1,s2为全局变量可不创建,但结尾一定要有分号
1.2 特殊的声明方式(匿名结构体)
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
} *p;
上述声明省略结构体标签,所构成的匿名结构体只能使用一次,在末尾创建变量,在编译语句:p=&x 时,编译不会通过,编译器会认为二者是不同类型。
1.3 结构体自引用
typedef struct node
{
int data;
struct node* next;//结构体指针,用于存放下一个结构体的地址
}NODE;
链表的基础。
二、结构体变量的创建和初始化
struct Point
{
int x;
int y;
}p1={10,18}; //声明类型的同时定义变量p1,并初始化。
struct Point p2={10,18}; //定义结构体变量p2,并初始化。
三、结构体成员的访问
结构体变量.成员变量名
结构体指针->成员变量名
#include <stdio.h>
typedef struct dent
{
char name[20];
int grade;
}dent;
typedef struct stu
{
int age;
double weight;
dent s1; //嵌套结构体
}stu;
int main()
{
stu s = { 10,55.5,{"不理不理",100} };
printf("%d %lf %s %d", s.age, s.weight, s.s1.name, s.s1.grade);
return 0;
}
四、结构体对齐
4.1结构体的对齐规则
(1).结构体的第⼀个成员对齐到相对结构体变量起始位置偏移量为0的地址处
(2).其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(对齐数=编译器默认对齐数与该成员变量大小的较小值。 )
VS中默认的值为8
Linux中没有默认对齐数,对齐数就是成员自身的大小
(3).结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)的整数倍。
(4).如果嵌套了结构体的情况,嵌套的结构体对齐到自己的成员中最大对齐数的整数倍处,结构
体的整体大小就是所有成员中最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,我们可以让占用空间小的成员尽量集中在一起。
4.2修改默认对齐数
方法:
#pragma pack(8)
被修改结构体
#pragma pack()
(详细使用见后续代码示例)
4.3某变量相对于首地址的偏移
offsetof 宏的实现:offsetof(某结构体,该结构体的某一变量)。
(详细使用见后续代码示例)
4.4代码示例
(1).默认对齐数
#include <stdio.h>
#include <stddef.h>
typedef struct dent
{
double b;
char c;
}S3;
typedef struct stu
{
char c1;
struct dent s3;
double d;
}S4;
int main()
{
S3 ss3= { 0 };
S4 ss4 = { 0 };
//计算结构体S3和S4的大小
printf("%d\n", sizeof(ss3));
printf("%d\n", sizeof(ss4));
printf("\n");//计算各成员变量的偏移量:
printf("%d\n", offsetof(S3,b));
printf("%d\n", offsetof(S3,c));
printf("%d\n", offsetof(S4, c1));
printf("%d\n", offsetof(S4, s3));
printf("%d\n", offsetof(S4, d));
return 0;
}
(2).修改默认对齐数:
#include <stdio.h>
#include <stddef.h>
#pragma pack(8)//修改默认对齐数为8(vs2022默认就为8)
typedef struct dent
{
double b;
char c;
}S3;
#pragma pack()//恢复默认
#pragma pack(1)//修改默认对齐数为1
typedef struct stu
{
char c1;
struct dent s3;
double d;
}S4;
#pragma pack()//恢复默认
int main()
{
S3 ss3= { 0 };
S4 ss4 = { 0 };
//计算结构体S3和S4的大小
printf("%d\n", sizeof(ss3));
printf("%d\n", sizeof(ss4));
printf("\n");//计算各成员变量的偏移量:
printf("%d\n", offsetof(S3,b));
printf("%d\n", offsetof(S3,c));
printf("%d\n", offsetof(S4, c1));
printf("%d\n", offsetof(S4, s3));
printf("%d\n", offsetof(S4, d));
return 0;
}
五、结构体传参
分为传值和传址,示例代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
typedef struct student
{
int age;
int grade;
}stu;
int main()
{
stu a = {0};
void initialize1();
initialize(a);//传值
printf("%d %d", a.age, a.grade);
void initialize2();
initialize(&a);//传址
printf("%d %d", a.age, a.grade);
return 0;
}
void initialize1(stu temp)//传值调用,另外开辟空间,不改变原数据
{
temp.age = 18;
temp.grade = 100;
}
void initialize2(stu* temp)//传址调用,使用原空间,原数据改变
{
temp->age = 18;
temp->grade = 100;
}
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递⼀个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能下降。故:结构体传参的时候,要传结构体的地址(若不想原结构体成员变量发生改变,可使用counst修饰)。
总结
后续更新使之完备......