结构体、结构体传参与其内存对齐、位段

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

例如:声明一个学生类型,是想通过学生类型 来创建学生变量(对象)

           描述学生 - 属性 -- 名字+电话+性别+年龄

#include<stdio.h>
struct Stu
{
	char name[20];//姓名
	char tele[20];//电话
	char sex[10];//性别
	int age;  //里面的东西统称 成员变量
}s4,s5,s6;//这里也是全局结构体变量

struct Stu s3;//全局变量

特殊声明

        匿名(不加名字)结构体类型 --> 创建后直接跟上名字,不然后期无法再创建

        即使两个结构体类型参数一样,也不能使用指针类型的结构体存储另一个地址,系统认为是两个不同类型

结构体的自引用:

//结构体的自引用
//struct Node1
//{
//	int data;
//	struct Node1 n;
//};//错误的写法
typedef struct Node2
{
	int data;
	struct Node2* next;//结构体指针
}Node2;//正确的自引用方式

结构体使用举例:

struct T
{
	double weight;
	short age;
};
struct S
{
	char c;
	int a;
	struct T st;
	double d;
	char arr[20];
};
int main()
{
	struct Stu s1;
	struct Stu s2;//局部结构体变量
	struct Node2 n1;
	Node2 n2;
	//结构体初始化?  创建变量的同时初始化

	struct S s = { 'c',100,{75.3,18},3.14,"hello" };//结构体嵌套初始化
	printf("%c %d %lf %s \n", s.c, s.a, s.d, s.arr);
	printf("%.2lf  %hd", s.st.weight, s.st.age);
	return 0;
}

结构体内存对齐:

第一个成员在与结构体变量偏移量为0的地址处

其他成员要对齐到某个数字(对齐数)的整数倍的地址处

对齐数 --> 编译器默认的一个对齐数 与 该成员大小的较小值(vs默认值是8)

结构体总大小为最大对齐数(每个成员变量都有一个自己的对齐数)的整数倍

思考:结构体嵌套? 一样去叠加

修改默认对齐数  修改成1,就不存在对齐的问题

#pragma pack(4)  设置默认对齐数为4

#pragma pack()   取消设置的默认对齐数

//结构体内存对齐
#include<stdio.h>
#include<stddef.h>
struct S1
{
	char c1;
	int a;
	char c2;
};

struct S3
{
	double d;//8
	char c;//1  8+1 = 9,对齐的要求是对齐数的整数倍
	int i;//12 + 4 = 16
};

struct S2
{
	char c1;
	char c2;
	int a;
};

struct S4
{
	char c; //1
	struct S3 s3;  //16  1 + 16 = 17 --> 24
	double d; //8  8 + 24 = 32
};
int main()
{
	struct S1 s1 = { 0 };
	printf("%d\n", sizeof(s1));
	struct S2 s2 = { 0 };
	printf("%d\n", sizeof(s2));
	struct S4 s4;
	printf("%d\n", sizeof(s4)); 
	//内存对齐是用空间换取时间,设计结构体时,尽量小字节放一起
	//offsetof()可以计算相对偏量
	printf("%d\n",offsetof(struct S4, d));  //24

	return 0;
}

结构体传参,怎么传?

可以传值,可以传址(传地址效率更高)

但注意有时候尽量加上const来限定只读属性,避免误操作

//结构体传参

#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;
	Init(&s);//值传递并没有实际改变效果
	Print1(s);
	Print2(&s);//字节数更小
	return 0;
}

位段:

注意:位段的类型只能是int,unsigned int,signed int三种类型

//位段

#include<stdio.h>
//位段-二进制位
struct S
{
	int a : 2; //意思是,两个bit就够   2 -> 一个字节(8bit)
	int b : 5; //5bit 
	int c : 10;//10bit 已经使用17个bit  //前三个加起来已经不能再存下d
 	int d : 30;//四个字节(32bit)  //所以d再单独的开辟出一个空间
};//47bit位 - 


int main()
{
	struct S s;
	printf("%d\n", sizeof(s));  //8个字节
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值