文章时效性提示
本文发布于 506 天前,部分信息可能已经改变,请注意甄别。
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
参考:初识结构体
结构的声明
1 2 3 4 5
| struct tag { member-list; } variable-list;
|
例如描述一个学生,声明一个结构体类型,通过学生类型来创建学生变量:
——姓名、电话、性别、年龄
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Stu { char name[20]; char tele[12]; char sex[5]; int age; }s4,s5,s6;
struct Stu s3;
int main() { struct Stu s1; struct Stu s2; return 0; }
|
特殊的声明
匿名结构体类型
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct { int a; char b; float c; }x;
struct { int a; char b; float c; }a[20],*p;
|
结构体自引用
自引用方式
1 2 3 4 5
| struct Node { int data; struct Node* next; };
|
1 2 3 4 5 6 7 8 9 10 11 12
| typedef struct Node { int data; struct Node* next; }Node;
int main() { struct Node n1; Node n2; return 0; }
|
结构体变量的定义和初始化
1 2 3 4 5 6
| struct Point { int x; int y; }p1; struct Point p2;
|
定义变量同时赋值:
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct S { char c; int a; double d; char arr[20]; };
int main() { struct S s = {'c',100,3.14,"hello world"}; printf("%c,%d,%lf,%s\n",s.c,s.a,s.d,s.arr); return 0; }
|
打印的结果是:c 100 3.140000 hello world
结构体成员的嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> struct T { double weight; short age; };
struct S { char c; struct T st; int a; double d; char arr[50]; };
int main() { struct S s = {'c',{55.4,30},100,3.14,"hello world"}; printf("%lf\n",s.st.weight); return 0; }
|
打印的结果是55.400000
嵌套的结构体变量就是在大括号里加大括号
结构体内存对齐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <stdio.h> struct S1 { char c1; int a; char c2; };
struct S2 { char c1; char c2; int a; };
int main() { struct S1 s1 = {0}; printf("%d\n",sizeof(s1)); struct S2 s2 = {0}; printf("%d\n",sizeof(s2)); }
|
如何计算结构体大小?
——对齐规则
1、第一个成员在与结构体变量偏移量为0的地址处
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值
3、结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4、如果嵌套了结构体的情况,嵌套结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
为什么要内存对齐?
——性能强,兼容性强
修改默认对齐数
使用#pragma()指令来修改默认对齐数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include <stdio.h> #pragma pack(4) struct S { char c1; double d; }; #pragma pack() int main() { struct S s; printf("%d\n",sizeof(s)); return 0; }
|
默认的对齐数是8,#pragma pack(4)修改默认对齐数为4,使原先的结构体s的大小由16变成了12。(中间浪费的字节由8变成了3)
偏移量计算offsetof
size_t offsetof(structName, memberName);
用于计算偏移量,它不是函数,是一个宏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include <stdio.h> #include <stddef.h> struct S { char c; int i; double d; };
int main() { printf("%d ",offsetof(struct S, c)); printf("%d ",offsetof(struct S, i)); printf("%d ",offsetof(struct S, d)); return 0; }
|
打印的结果是0 4 8
结构体传参
结构体传参,可以传地址,也可以传本身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #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 = {0}; Init(&s); print1(s); print2(&s); return 0; }
|
结构体传参,最好传地址,因为传的值有可能过大,系统开销大,通过传地址,可以节约系统开销。