允许自己创造的一些类型
自定义类型:结构体,联合体,枚举
结构体的声明
结构是一些值得集合,这些值称为成员变量,结构的每个成员可以是不同的类型变量
//定义变量类型
#include<stdio.h>
struct Stu
{
//成员变量
char name[20];
int age;
float weight;
}s4,s5,s6;//全局变量
int main()
{
struct Stu s1;//局部变量
struct Stu s2;
struct Stu s3;
}
特殊的声明
声明结构的时候,可以不完全声明
匿名结构体类型
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20],*p;
上面的结构在声明时,省略了结签(tag)
但是,编译器会将其认为是非法的。因为会将其当成两个不同的类型
结构的自引用
数据结构,描述的是,数据在内存中的存储结构结构
【包括线性数据结构和树形的数据结构】
自引用的创建的正确方式:
typedef struct
{
int data;
char c;
}s;
typedef struct Node
{
int data;
Node* next;
}Node;
结构体变量的定义和初始化
struct Stu
{
int x;
int y;
}p1;
struct Stu p2;
//声明变量的同时定义变量p1
//定义结构体的变量p2
//初始化:定义变量的同时赋初值
struct Stu p3={x,y}
struct Stu //类型声明
#include<stdio.h>
struct S
{
int a;
char c;
}s1;
struct S s3
{
float f;
struct S s;
};
int main()
{
struct S s2={100,'q'};
struct S s3={.c='r',.a=2000};
struct B sb={3.14,{200,'w'}};
print("%f %d %c\n",sb.f,sb.s.c,sb.s.c);
}
struct B sb={3.14,{200,'w'}};//结构体的嵌套的初始化
结构体内存对齐
结构体的对齐规则:1.在结构体中每个地址都跟0地址有一个偏移量, 第一个成员在与结构体变量偏移量为0的地址处 2.从第二个成员开始,以后每个成员都要对齐到某个对齐数的整数倍处,这个对其数是:成员自身大小和默认对齐数的较小值(vs环境下默认对齐数是8,gcc环境下没有默认对齐数,没有默认对齐数时,对其数的大小就是成员自身的大小)3.当成员全部存放进去后,结构体总大小必须是,所有成员的对齐数中最大对齐数的整数倍。如果不够,则浪费空间对齐 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
简单来说:结构体的内存对齐是拿空间换时间的做法,可以节省时间。
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到: 让占用空间小的成员尽量集中在一起。
//例如:
struct S1
{
char c1;
int i;
char c2;
};
struct S2
{
char c1;
char c2;
int i;
};//S1和S2类型的成员一模一样,但是S1和S2所占空间的大小有了一些区别
默认修改对其数
#pragma 这个预处理指令,这里再次使用,可以改变默认对齐数。
#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
char c1;
int i;
char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
//输出的结果是什么?
printf("%d\n", sizeof(struct S1));
printf("%d\n", sizeof(struct S2));
结构体传参
struct S
{
int data[1000];
int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print1(s); //传结构体
print2(&s); //传地址
return 0;
}
结构体传参的时候呢,是有系统压栈开销的。如果这个结构体比较大,压栈时所需要的空间,开销就比较大。如果我们传结构体地址,一个地址无非就4个或8个字节,占的空间是比较小的。在相同的效果下,穿地址比传结构体更好一些。