结构体(内存对齐)和共用体—C语言
来源:互联网 发布:淘宝保证金有什么用 编辑:程序博客网 时间:2024/06/06 02:27
结构体
C语言学到现在,相信大家已经熟知了基本类型(整型、实型、字符型)的变量和一种构造类型数据(数组),但是只有这些数据类型是不够的,因此我们接下来介绍C语言中可以将不同类型的定义自己的数据类型——结构体。
结构体与数组的比较
由于结构体和数组有很大的类似之处,所以我们首先来说说结构体与数组异同:
- 都由多个元素组成
- 各个元素在内存中的存储空间是连续的
- 数组中各个元素的数据类型相同,而结构体中的各个元素的数据类型可以不相同
结构体的定义和使用
1. 结构体的定义语法:
struct 结构体名{ 类型名1 成员名1; 类型名2 成员名2; ... 类型名n 成员名n;};
刚开始学的童鞋一定要注意,结构体是一种数据类型而不是一个变量,既然是一种数据类型,我们下来就讲讲定义结构体类型变量的几种方法。
2. 定义结构体类型变量的几种方法:
- 定义结构体类型时,同时定义该类型的变量
struct [student] /* [ ]表示结构体名是可选的 */{ char name[10]; char sex; int age; float score;}stu1, *ps, stu[5]; /* 定义结构体类型的普通变量、指针变量和数组 */
- 先定义结构体类型,再定义该类型的变量
struct student{ char name[10]; char sex; int age; float score;};struct student stu1, *ps, stu[5]; /* 定义结构体类型的普通变量、指针变量和数组 */
- 用类型定义符typedef先给结构体类型命别名,再用别名定义变量
typedef struct [student]{ char name[10]; char sex; int age; float score;}STU;STU stu1, *ps, stu[5]; /* 用别名定义结构体类型的普通变量、指针变量和数组 */
再次给初学的童鞋说明一下:
- 类型和变量不要混淆,只能对变量赋值、存取或运算,并且在编译时,对类型是不分配空间的,只对变量分配空间。
- 结构体的成员也可以是一个结构体变量
- 结构体中的成员名可以与程序中的变量名相同,二者不代表同一对象。(如变量num和struct student中的num是两回事)
3. 结构数组和结构指针:
- 结构数组:该数组的每一个元素都是相同的结构体类型
- 结构指针:是指向结构的指针。由一个加在结构变量名前的"*" 操作符来定义
4. 结构体变量成员的引用:
在定义了结构体变量以后,当然可以引用这个结构体,但不能将一个结构体变量作为一个整体进行操作,只能对结构体变量中的某个成员进行操作,引用方式如下:
- 结构体变量名. 成员名: stu1.name
- 结构体指针变量->成员名: ps->name
- (*结构体指针变量). 成员名: (*ps).name
- 结构体变量数组名. 成员名: stu[0].name
5. 结构体变量的初始化
和其他类型一样,对结构体变量可以在定义时指定初始值:
struct [student]{ char name[10]; char sex; int age; float score;}stu[2]={{"SAN", 'F', 22, 90.5}, {"GI", 'M', 20, 88.5}};
结构体内存对齐问题
C语言结构体对齐也是老生常谈的话题了,也算是结构体中的一个小难点,内容虽然很基础,但一不小心就会弄错。
内存对齐的规则很简单:
- 起始地址为该变量类型所占内存的整数倍,若不足则不足部分用数据填充至所占内存的整数倍。
- 该结构体所占总内存为结构体成员变量中最大数据类型的整数倍。
接下来我们看一个例子:
struct str1 { char a; int b; float c; double d; };
str1这个结构体占用的内存是多少呢?如果用变量类型直接想加,得到的结果是17,但显然不是这样的。这个程序运行的正确结果是24。为什么呢?
分析如下:
char型变量占一个字节,所以它的起始地址为0,
而int类型占4个字节,它的起始地址应该是4(的整数倍),那么内存地址1、2、3就需要被填充。
float占用4个字节,而结构体中a,b两个成员变量占了0到7内存地址,c的地址从8开始,符合规则一,占用内存地址为8到11。
double类型占8个字节,所以d的起始地址就应该从16开始,那么12、13、14、15内存地址就需要被填充。d从16地址开始,占用8个字节。
整个结构体占用字节数为24,符合规则二。内存分配如图:红色区域为填充部分
--
总之结构体对齐可以总结为三个基本原则:
- 数据成员对齐规则:结构体的数据成员中,第一个成员从offset为0的地址开始,以后每一个成员存储的起始位置为该成员大小的整数倍
- 结构体作为成员: 如果一个结构体1作为另一个结构体2的数据成员,则在结构体2中结构体1要从1内部成员最大的整数倍地址开始存储。
- 结构体的总大小(sizeof): 为该结构体内部最大基本类型的整数倍,不足的要补齐,而不是简单的所有成员的大小总和。
再举一个例子:
struct str2 { double a; int b; char c; double d; };
str2这个结构体占用的内存空间是多少呢?是24!
分析如下:
首先double类型的a占用内存地址为0~7
int类型的b起始地址为8,符合规则一,占用地址为8~11
char类型的c占一个字节,地址为12
那么double类型的d,起始地址为13吗?显然不是,满足规则一的地址是16,所以d起始地址为16,占用16到23。
结构体总共24个字节,满足规则二。
但是如果这个结构体最后再加一个成员变量 char e,那这个结构体占用的内存是多少?
分析:
char类型的e起始地址为24,占用地址为24,但是结构体一共有25个字节,就不满足规则二了,怎么办呢?
为了满足规则二,我们将25~31进行填充,因此整个结构体占用32个字节。
共用体
C语言中还有一种将不同类型的几种变量存放到同一段内存单元中。这几个不同的变量共同占用同一段内存结构的数据类型———共用体
- 共用体类型变量的定义
union 共用体名{成员列表;}变量列表;
- 共用体变量的引用 和结构体变量一样,共用体变量也不能被直接引用,而只能引用共用体变量中的成员。
- 共用体同一个内存段可以用来存放几种不同类型的成员,但是在每一瞬间只能存放其中的一种,而不是同时存放几种。换句话说,每一瞬间只有一个成员起作用,其他的成员不起作用,即不是同时都在存在和起作用。
- 共用体变量的地址和它的各个成员的地址都是同样的
- 共用体变量中起作用的成员是最后一次被赋值的成员。
- 共用体类型可以出现在结构体类型的定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型的定义中,数组也可以作为共用体的成员。
结构体与共用体并不难,结构体更加重要一些,用的也多一点,尤其要格外掌握结构体的内存对齐问题
- 结构体(内存对齐)和共用体—C语言
- <C语言>结构体与联合体(共用体)的地址排布问题(内存字节对齐)
- c语言共用体对齐
- c语言共用体对齐
- c语言结构体对齐 共用体对齐 位域对齐 面试常考题目
- C语言结构体和共用体(2)
- C语言结构体对象内存对齐
- C语言结构体的内存对齐
- 解析C语言结构体对齐(内存对齐问题)
- 解析C语言结构体对齐(内存对齐问题)
- 解析C语言结构体对齐(内存对齐问题)
- 解析C语言结构体对齐(内存对齐问题)
- C语言结构体的大小——内存对齐和位域的使用
- C语言_结构体和共用体
- c语言中的结构体和共用体
- c语言的结构体,共用体和枚举
- C语言共用体和与结构体的区别
- C语言学习------3.1 结构体和共用体
- flume之Channel
- Oracle中时间日期格式转换及常用日期函数
- 机器学习小试(8)使用TensorFlow跑通一个通用增量学习流程-增量学习
- C++中virtual的三种用法
- Sublime Text 3 简体中文汉化包使用方法
- 结构体(内存对齐)和共用体—C语言
- Hive编程(十)【调优】
- Java开发快递物流项目(4)
- 【异常】SparkSession执行action操作时java.lang.ClassNotFoundException: org.codehaus.commons.compiler.Unchecked
- 欢迎使用CSDN-markdown编辑器
- (安卓) 三级缓存具体逻辑(内存,磁盘{数据库},网络)
- linux下mysql开启远程访问权限 防火墙开放3306端口
- [bzoj3112][Zjoi2013]防守战线
- No module named 'spacy.en'