/// define不是关键字,是一个预处理指令
///
struct Stu//这是一个类型(类似于int)通过类型创建变量,不占空间,只有变量创建出来,才能占据空间
{
char name[20];
int age;
char sex[10];
char tele[12];
};
void print(struct Stu* p)//p是指针,里面存的数据类型是地址
{
//p中存储的是地址。而*p代表该地址指向的哪个房间的名字,(*p).name,代表该房间存储的东西
printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", (*p).name, (*p).age, (*p).sex, (*p).tele);
//p中存储的是地址,p->代表该地址具体的位置,也就是存储数据的那房间,p->name代表去除该房间内存储的内容
printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", p->name, p->age, p->sex, p->tele);
}
int main()
{
//创建结构体并进行初始化
struct Stu s = {"张三",20,"男","15157197537"};//只有创建出来才能占据空间
//结构体对象.变量名
printf("%s的年龄为:%d,性别为:%s,电话为:%s\n", s.name, s.age, s.sex, s.tele);
print(&s);
return 0;
}
/*
结构是一种集合(数组是一组相同类型元素的集合)
结构类似于对象,比如说人具有姓名,年龄,身高等属性,也具有走,跑,跳等动作
*/
/*
结构体声明格式
struct 结构体名字
{
成员变量//成员可以是标量,数组,指针甚至是其它结构体
}变量列表;
变量列表可省略,变量列表的作用是在定义结构体的同时创建结构体变量
*/
//struct Peo //struct Peo是类型
//{
// struct People p;
// char name[20];
// char tele[12];
// char sex[5];
// int high;
//};//通常采用这种方法
//struct People
//{
// char name[20];
// char tele[12];
// char sex[5];
// int high;
//}P1,P2;//P1,P2是使用struct People结构体类型创建的两个变量
此时的P1,P2是两个全局变量
//int main()
//{
// struct Peo P3;//P3为局部变量
//
// return 0;
//}
//struct Peo //struct Peo是类型
//{
// char name[20];
// char tele[12];
// char sex[5];
// int high;
//};
//struct Stu
//{
// struct Peo p;
// int num;
// float f;
//};
//void print1(struct Stu s)
//{
// printf("%s %s %s %d %d %.2f\n", s.p.name, s.p.tele, s.p.sex, s.p.high, s.num, s.f);
//}
//void print2(struct Stu *h)
//{
// printf("%s %s %s %d %d %.2f\n", h->p.name, h->p.tele, h->p.sex, h->p.high, h->num, h->f);
//}
//int main()
//{
// //完全初始化
// struct Peo p = { "zhangsan","15157197539","男",185 };
// struct Stu s = { {"lisi","19825088479","女",166},100,3.14f };
//
// printf("%s %s %s %d %d %.2f\n", s.p.name, s.p.tele, s.p.sex, s.p.high, s.num, s.f);//结构体变量.成员变量
//
// struct Stu* h = &s;
// printf("%s %s %s %d %d %.2f\n", h-> p.name, h->p.tele, h->p.sex, h->p.high, h->num, h->f);//结构体指针->成员变量
//
// print1(s);//这种传参实际上是对s的一种临时拷贝,传过去之后会在栈区找一块区域存储s,这样就很浪费存储空间,浪费资源
// print2(&s);//地址只有4/8个字节,在压栈是创建的空间相对就比较小
// //故结构体传参时,尽量传地址,这样性能会更高一些
// return 0;
//}
自定义类型: 结构体,联合,枚举
结构体
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
结构的声明
struct tag //这只是一个类型,不用初始化
{
member-list;
}variable-list;
tag结构标签
member-list;成员列表
variable-list;变量列表,可写可不写
struct
{
char name[20];
int age;
}s1,s2,s3; //全局变量
//struct Stu
//{
// char name[20];
// int age;
//}s1,s2,s3; //全局变量
//
匿名结构体类型
//struct
//{
// int a;
// char b;
// float c;
//}x;
//struct
//{
// int a;
// char b;
// float c;
//}a[20], * p;
//
//int main()
//{
// struct Stu s3;//局部变量
// p = &x;// 虽然两个匿名结构体的成员变量相同,但是还是会被编译器认为成两个不同的结构体
// return 0;
//}
数据在内存中的存储结构
顺序表:arr[10]
1 2 3 4 5 顺序存放
(胡乱存放,但能通过上一个数据(节点)找打下一个,如同链条一样)
一个节点包含两个部分: 数据+下一个节点的地址
结构体的自引用:
struct Stu
{
char name[20];
struct Stu *next;
};
typedef struct Stu
{
char name[10];
struct Stu *next;
}Node;
struct Stu s1 等价于 Node s1
1 4
2 3 5
二叉树
结构体内存对齐(重要)//计算结构体的大小
对齐规则(核心:分清什么时候使用最大对齐数,什么时候使用最小对齐数)
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
//对齐的原因
1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
问。
结构体的内存对齐是拿空间来换取时间的做法
那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:
让占用空间小的成员尽量集中在一起。
#include
//struct S1
//{
// char c1;//1
// int i;//4
// char c2;//1
//};
s1内存存储情况
///*
//总大小最大对齐数的整数倍 12
// 偏移量 总个数
// --
// c1 | 0 1 第一个成员在与结构体变量偏移量为0的地址处
// --
// | 1 2
// --
// | 2 3
// --
// | 3 4
// --
// i | 4 5 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
// --
// i | 5 6
// --
// i | 6 7
// --
// i | 7 8
// --
// c2 | 8 9
// --
// | 9 10
// --
// | 10 11
// --
// | 11 12
// --
//*/
//struct S2
//{
// char c1;//1
// char c2;//1
// int i;//4
//};
//int main()
//{
// //printf("%d\n", sizeof(struct S1));//12
// //printf("%d\n", sizeof(struct S2));//8
//
// //#include
// //offsetof(type,member);
// //可以返回该成员在该类型中的偏移量,单位是字节
// printf("%d\n", offsetof(struct S1, c1));//0
// printf("%d\n", offsetof(struct S1, i));//4
// printf("%d\n", offsetof(struct S1, c2));//8
// return 0;
//}
/*
#pragma pack()//设置默认对齐数
#pragma pack(1) //设置默认对齐数为1
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma once //防止头文件被引用多次
*/