概述
目录
一、结构体
定义
使用
1.成员变量的范围
2.结构体嵌套
二、内存对齐
如何理解字节对齐问题:
如何计算结构体的大小?
指令对齐符
二、结构体指针
定义
使用
成员访问
一、结构体
定义
struct类型名
{
(成员列表属性)
成员1;
成员2;
.....
}; //重点是:需要哪些信息
eg:
struct Student
{
char name[20];
int age;
};//定义完成,其作用和内置类型一样,类型的设计不占用内存空间
使用
1.成员变量的范围
通过类型来定义变量,再对变量内的数据按照定义顺序依次初始化
- 结构体数组:
- eg:struct Studeng arr[]={{},{}...};
- 访问:
- arr[i].name,arr++
- 成员访问:
- 变量名称.结构体变量 ‘.’成员访问符
- eg:student.name
- 变量名称.结构体变量 ‘.’成员访问符
例如:
struct Student student = {"李四",14};
struct Student student1;//如果是局部变量(写在函数内部)->未初始化,成员内容为随机值,编译会报错;如果是全局变量(写在函数外部)->未初始化,编译器给成员列表默认值初始化int,short那些都是0,char类型为 ,编译不会报错
例题求解:
struct Student a;//利用struct Student数据类型定义一个变量a;
struct Student b = { "曹操",20};
b.age = 21;//结构体的普通变量通过“.”访问其成员
(1)修改b的名字为刘备
错误:b.name=”刘备”//不允许字符串赋值给数组,应该用循环,跟结构体没关系
正确:strcpy(b.name, "刘备");
(2)输出b的数据:名字和年龄
printf(" % s, % d", b.name, b.age);
(3)将a改为“孙权”,18
strcpy(a.name, "孙权");
a.age = 18;
简化使用:
1.struct类型名
{ }别名;
2.typedef struct 类型名 别名;
2.结构体嵌套
结构体内可以使用之前声明过的结构体类型
eg:
struct Date
{
int year;
int month;
int day;
}Date;
struct Student
{
const char* name;
int age;
Date birthday;
};
int main()
{
struct Student s1 = {"李四",14,{2001.9.18}};
}
二、内存对齐
如何理解字节对齐问题:
- 内存的基本单位是字节,理论上来说,可以任意地址访问变量,但实际上CPU并不是逐个字节的进行内存读取,而是以2,4,8的倍数的字节块来读写内存,因此对基本数据类型的地址做出了限制,那么就要求各种数据类型按照一定的规则在空间上排列。
- 有些平台每次都是从偶地址开始,而如果存放在奇地址开始的地方,就需要2个都读周期,并对两次读出的结果高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
- 由于不同平台对齐方式可能不同。如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情况下,互相发送的数据可能出现错乱,甚至引发严重的问题。
如何计算结构体的大小?
记住做法:通过补齐的方式,让当前变量即上面所有的大小加起来是当前变量大小的倍数,而且要满足最后的结果与结构体内变量最大字节对其。
注意1:当数组不是第一个成员是就要注意,要进行单个字节对其,而不是看整个数组的大小。
2:有嵌套struct时,大小不是按照整个struct计算,也是单独每个变量的类型。
特殊情况:在嵌套结构体时,如果是无名的strcut(既无变量名又无参数名),此时计算情况与上述的一般情况一致,如果是无参数名的struct A,则sizeof(A)=0;
添加:
#pragma pack(1)
是以1对其,其实就是不按照内存对其,有多少字节就是多少。
内存对齐理论原理:
1.结构体变量地址的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。
如下为例:
//eg:
struct Student
{
char name[20]; //1*20=20字节
int age; //4字节
};
因为20为结构体内最大字节,所以结构体变量首地址必须是20的倍数。如图
->倍数为0
2.结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节的整数倍。
3.结构体变量的总大小,为结构体变量中“最大基本数据类型成员所占字节数”的整数倍(注意:struct和数组都不是基本数据类型)
举例分析:
将如图字节在内存中分配
(1)
解:char cha:1字节,char chb:1字节,int ia:4字节,最起码要在4的位置放,因此浪费两个字节。1+1+2+4=8是4的倍数,因此结构体的字节大小为8
(2)
解:cha:1,da:8需要前面浪费7个字节,chb:1。8+8+1=17。最小24。
(3)
解:ch:3,ia:4,前面浪费一个,4+4=8,是4的倍数,则为8。
(4)嵌套结构体分析:
解:10+8+12=30,4*8=32浪费2个字节。
32+8=40,基本数据类型为double:8字节,40是8的倍数,结构体字节大小为40。
(5)数组分析要小心:
在该结构体内,数组short b[4]=8字节,short:2字节,char a=1字节,那么a是应该+1还是+7?实际应该是+1,因为,char a+1占用2个字节后,short本身就是2字节,从第2后面开始也合理。int c:4字节,最后结果为:2+8+4=14,4*4=16。因此,最小16字节
(6)
char a=1,d=8,char a在对对齐时+7还是+3?如果+3,char a占用4个字节内存大小,int:4字节,float:4字节,也是可以的。因此结果为1+3+8=12。
(7)
1+3+4+2=10,不是最大字节4的倍数,因此要在+2,最后结果为:12
(8)特殊情况需要记忆:
因为结构体sizeof(II)=0,它只定义了类型,没有变量名(在“};”处没有写东西),变量大小就是0,类型本身不占大小。1+3+0+4=8。=》8
(9)
struct是无名变量,虽然也没有写变量名,但是可以这么使用,此时的情况就和一般的情况一样
1+3+4+4+4=16
(10)嵌套联合体:
联合体union kk大小,sizeof(union kk)=4,1+3+4+4=12。
- 写代码时检验可以通过printf(“%d”,sizeof(struct A));输出检查。
指令对齐符
预处理指令#pragma pack(n),可以改变默认对其数,n的取值为1,2,4,8,16。
如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对其。
eg:字节对其数为2,a读取1次,浪费1个空间,b读取两次,c读取1次,浪费1个空间。
字节对其数为4,a读取1次,浪费3个空间,b读取1次,c读取1次,浪费3个空间。
二、结构体指针
定义
typedef struct Student* stu;
或者
struct Student
{
char name[20];
int age;
}*stu;
使用
通过类型来定义指针变量,再对其赋与指向。
eg:
Student s1 = { "张三",20 };
typedef struct Student* stu;
stu S=&s1;
通过S输出s1的内容。
eg:
printf(“%c,%d”,S->name,S->age);
成员访问
1.(*变量名称).结构体变量 ‘.’成员访问符
(*S).age; 必须有括号,因为“.”的优先级高于“*”
2.变量名称->结构体变量 ‘->’指向符
S->age;
最后
以上就是义气猎豹为你收集整理的结构体struct与内存对齐一、结构体二、内存对齐二、结构体指针的全部内容,希望文章能够帮你解决结构体struct与内存对齐一、结构体二、内存对齐二、结构体指针所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复