引言这是一篇对结构体的详细引见,这篇文章对结构体申明、结构体的自援用、结构体的初始化、结构体的内存散布和对齐规定、库函数offsetof、以及启动内存对齐的要素、如何修正自动对齐数、结构体传参启动引见和说明,目录引言结构体的申明结构体的基础结构的申明匿名结构体类型结构体的自援用typedef作用于结构体的疑问结构体变量的定义和初始化多...。
引言
这是一篇对结构体的详细引见,这篇文章对结构体申明、结构体的自援用、结构体的初始化、结构体的内存散布和对齐规定、库函数offsetof、以及启动内存对齐的要素、如何修正自动对齐数、结构体传参启动引见和说明。
目录
引言
结构体的申明
结构体的基础
结构的申明
匿名结构体类型
结构体的自援用
typedef作用于结构体的疑问
结构体变量的定义和初始化
多个元素的初始化要用大括号{ }
结构体的内存对齐
1.对齐规定
1.例子
2.例子
3.例子
4.例子
offsetof
offsetof的经常使用
编辑
为什么要存在内存对齐
修正自动对齐数
结构体传参
结构体的申明
结构体的基础
在一个变量中,要寄存性别、年龄、效果、地址多种类型的数据时,C言语准许用户自己建设由不同类型数据组成的组合型的数据结构,它称为结构体。
结构的申明
结构体是怎样申明的呢?
struct tag
{member_list;
}variable_list; //分号不能丢struct Student
{//在校生的关系消息char name[20];int age;
}s1,s2;
- tag,Student是结构体名
- member_list是成员表列
- struct是申明结构体类型是必定经常使用的关键字,不能省略
- s1,s2变量就是在校生变量。
- { }前面要记得把“ ;”带上
struct tag就是一个结构体类型,咱们可以依据自己的要求建设结构体类型,struct Teacher,struct Student等结构体类型,各自蕴含不同的成员。
假设将s1,s2放在main函数的外面,那么s1,s2就是全局变量。
struct Student
{//在校生的关系消息char name[20];int age;
}s1,s2;int main()
{return 0;
}
匿名结构体类型
结构体在申明的时刻省略了却构体标签(tag),没有名字的结构体类型只能经常使用一次性,被称为 匿名结构体类型 。
由于没有名字,编译器会把上方的两个代码当成齐全不同的两个类型。
所以,p = &x.
会由于类型不同报错。
struct
{char name[20];int age;
}s1;struct
{char name[20];int age;
}a[20],*p;
结构体的自援用
结构体的自援用用到数据结构中的链表。
数据结构中有顺序表、链表的概念,
咱们经过链表就可以成功结构体的自援用。
struct Node
{int>typedef struct Node
{int>typedef struct Node
{int>struct Point
{int x;int y;
}p1 = { 2,3 };
多个元素的初始化要用大括号{ }
在结构体中,假设存在多个元素的变量,咱们初始化时要经常使用大括号。
像数组一样,arr[] = { 0, 1, 2, 3, 4 };
struct score
{int n;char ch;
};
struct Stu
{char name[20];int age;struct score s;
};int main()
{struct Stu s1 = { "zhangsan",20,{100,'q' } };printf("%s %d %d %cn", s1.name, s1.age, s1.s.n, s1.s.ch);return 0;
}
结构体的内存对齐
如何计算结构体的大小?
结构体的内存散布是怎样的?
1.对齐规定
首先把握结构体的对齐规定
1. 结构体的 第⼀个成员 对⻬到和结构体变量起始位置 偏移量为0 的地址处
2. 其余成员变量要对⻬到某个数字 (对⻬数)的整数倍 的地址处。
对⻬数 = 编译器自动的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值。
- VS 中自动的值为 8
- Linux中 gcc 没有自动对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3. 结构体总⼤⼩ 为 最⼤对⻬数 (结构体中每个成员变量都有⼀个对⻬数,一切对⻬数中最⼤的)的整数倍。
4. 假设嵌套了却构体的状况, 嵌套的结构体成员 对⻬到⾃⼰的 成员中最⼤对⻬数的整数倍 处,结构体的全体⼤⼩就是一切最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
只是文字的说明,免不了艰涩难懂,接上去用 例子 来给大家解说
1.例子
#include <stdoi.h>
struct S1
{char c1;int i;char c2;
};
int main()
{printf("%dn", sizeof(struct S1));return 0;
}
解析:
2.例子
#include<stdio.h>
struct S2
{char c1;char c2;int i;
};
int main()
{printf("%dn",sizeof(struct S2));return 0;
}
解析:
3.例子
#include<stdio.h>
struct S3
{double d;char c;int i;
};
int main()
{printf("%dn",sizeof(struct S3));return 0;
}
解析:
4.例子
这个例子包括了嵌套结构体的状况, 嵌套的结构体成员 对⻬到⾃⼰的 成员中最⼤对⻬数的整数倍 处,结构体的全体⼤⼩就是一切最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
#include<stdio.h>
struct S3
{double d;char c;int i;
};
struct S4
{char c1;struct S3 s3;double d;
};
int main()
{printf("%dn",sizeof(struct S4));return 0;
}
解析:
offsetof
前往成员的偏移量 , 头文件 <stddef.h>
offsetof (type,member)
offsetof的经常使用
type是类型,
#include <stdio.h>
#include <stddef.h>
struct S1
{char c1;int i;char c2;
};
int main()
{printf("%dn", offsetof(struct S1, c1));printf("%dn", offsetof(struct S1, i));printf("%dn", offsetof(struct S1, c2));return 0;
}
为什么要存在内存对齐
- 平台要素 (移植要素):不是一切的配件平台都能访问恣意地址上的恣意数据的;某些配件平台只能在某些地址处取某些特定类型的数据,否则抛出配件意外。2. 性能要素:数据结构(尤其是栈)应该尽或许地在⾃然边界上对⻬。要素在于,为了访问未对⻬的内存,处置器要求 作两次内存访问;⽽对⻬的内存访问仅要求⼀次访问。假定⼀个处置器总是从内存中取8个字节,则地址必定是8的倍数。假设咱们能保障将一切的double类型的数据的地址都对⻬成8的倍数,那么就可以 ⽤⼀个内存操作来读或许写值了。否则,咱们或许要求执⾏两次内存访问,由于对象或许被分放在两 个8字节内存块中。对齐规定的思维:把数据放在机器可以一次性访问失掉数据的空间内,使访问更具效率。
修正自动对齐数
当结构体的对齐方式不适宜时,咱们也可以修正自动对齐数。
#pragma pack()
#include <stdio.h>
#pragma pack(1)//设置自动对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//敞开设置的对⻬数,恢复为自动
int main()
{//输入的结果是什么?printf("%dn", sizeof(struct S));return 0;
}
结构体传参
- 传值调用,将数据经过参数传过去,而后函数print会创立独立的空间,对传上来的数据启动存储
- 传址调用,将数据的地址传过去,函数经过指向数据的地址对数据启动经常使用,不要求再建设空间对数据启动寄存。
#include<stdio.h>
struct S
{int src="https://img-blog.csdnimg.cn/direct/b2d177f2dc1c40c6b3b1b06078388bec.png" /><p class="quietlee_903ce_9225f">上方的<strong>传值调用</strong>print1 和 <strong>传址调用</strong>print2 函数那哪个更好?</p>答案是:⾸选print2函数。<p class="quietlee_a5e00_13237"><br></br></p>
客服邮箱:kefu@itcaiji.cn
版权声明:未标注转载均为本站原创,转载时请以链接形式注明文章出处。如有侵权、不妥之处,请联系站长删除。敬请谅解!