#include<stdio.h> //结构体 //数组是一组相同类型的元素的集合,结构体也是一些值的集合,但是结构的每个成员可以是不同类型 //struct Book //b1,b2,b3,b4,b5,b6都是创建的变量 //{ // char name[20]; // int price; // char id[12]; //}b4,b5,b6;//全局变量 //int main() //{ // struct Book b1; // struct Book b2;//局部变量b1,b2,b3 // struct Book b3; // return 0; //}
声明时,可以不完全声明,如
//struct//匿名结构体类型(创建变量s) //{ // char c; // int i; // char ch; // double d; //}s;
但是下面这种,在编译器角度是不对的,因为是两种不同的类型
//struct //{ // char c; // int i; // char ch; // double d; //}s; //struct //{ // char c; // int i; // char ch; // double d; //}*ps; //int main() //{ // ps = &s; // return 0; //} //结构体自引用 //struct Node//Node不能省略(不能匿名),因为此处的Node(名字)要放下一个结构体的指针 //{ // int data;//定义数据 // struct Node* next;//把下一个结构体的地址放在该结构体中 // //在结构体里,不是包含同类型的结构体变量,而是包含同类型的结构体指针 //}; //int main() //{ // //struct N sn;是错误的,结构体不能自己包含自己 // //在结构体里,不是包含同类型的结构体变量,而是包含同类型的结构体指针 // return 0; // //} //struct S //{ // char c; // int i; // //}s1,s2; //struct B //{ // double d; // struct S s; // char c; //}; //int main() //{ // struct B sb = { 3.14,{'w',100},'q' };// 3.140000 w 100 q // //结构体操作符有 . 和 -> // printf("%lf %c %d %c", sb.d, sb.s.c, sb.s.i, sb.c); // return 0; //} //struct S //{ // char c1; // int i; // char c2; //}; //struct S2 //{ // char c1; // int i; // double d; //}; //struct S3 //{ // char c1; // char c2; // int i; //}; //struct S4 //{ // double d; // char c; // int i; //}; //struct S5 //{ // char c1; // struct S4 s4; // double d; //}; //struct S6 //{ // char n; // int m; //}; //struct S7 //{ // int n; // char m; //};
结构体内存对齐
1.结构体的第一个成员永远都放在结构体变量在内存中存储位置的10偏移处开始
2.从第2个成员往后的所有成员,都放在上一个成员的最小倍数的整数倍的地址处
(如char c int i放置为0~3(1-3浪费掉,但是必须是int的最小倍数4倍)4~7)
(如果是上一个结构体类型,就浪费掉上一个结构体距离最近的类型的最小倍数)---参见s5
3.结构体的总大小是结构体的所有成员的对齐数的整数倍
注意:放在前放在后都一样
//int main() //{ // struct S s = { 0 }; // printf("%d\n", sizeof(s));//12 0~3(1-3为浪费掉,下一个int为4)+4~7+8~11(9-11浪费掉)=12个 // struct S2 s2 = { 0 }; // printf("%d\n", sizeof(s2));//12 0~3(1-3为浪费掉,下一个int为4)+4~7+8~15=16个 // struct S3 s3 = { 0 }; // printf("%d\n", sizeof(s3));//8 // //0(下一个char为1,是倍数,不需要浪费)+1~4(2-4为浪费掉,下一个int为4)+5~7=8个 // struct S4 s4 = { 0 }; // printf("%d\n", sizeof(s4));//16 0~7+8~11(9-11为浪费掉,下一个int为4)+12~15=16个 // struct S5 s5 = { 0 }; // printf("%d\n", sizeof(s5));//32 // //0~7(1-7为浪费掉,下一个S4里面的第一个是double,为8)+8~23+23~31=32个 // struct S6 s6 = { 0 }; // printf("%d\n", sizeof(s6));//8 // struct S7 s7 = { 0 }; // printf("%d\n", sizeof(s7));//8,放在前放在后都一样 // return 0; //} //为什么存在内存对齐? // 拿空间换时间 //1.平台问题:某些平台只能在某些地址访问特定类型的数据 //2.性能原因:访问未对齐的内存,需要访问两次,对其的内存,访问一次就可以 //所以 //在设计结构体时,既要满足对齐,又要满足空间,需要: //让空间小的尽量集中在一起 //当对齐方式不合适时,可以自己更改默认对齐数 //修改默认对齐数方法如下 //#pragma pack() //#pragma pack(2) //struct S //{ // char c1; // int i; // char c2; //}; //#pragma pack(1) //struct S2 //{ // char c1; // int i; // char c2; //}; //int main() //{ // printf("%d\n", sizeof(struct S));//8 2+4+2 // printf("%d\n", sizeof(struct S2));//6 1+4+1 // return 0; //}