结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量
例如:声明一个学生类型,是想通过学生类型 来创建学生变量(对象)
描述学生 - 属性 -- 名字+电话+性别+年龄
#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;
}