不理不理学结构体

文章目录

前言

一、结构体的声明

 

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修饰)

 

 

总结

后续更新使之完备......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值