一.结构体变量的声明
1.1结构体变量
struct tag
{
member-list;
}variable-list;
解释:tag是结构体的名字,member-list是结构体变量中的成员(成员可以是不同类型),variable-list是一个变量的名字。
1.2结构体变量的创建(两种方法)
(1)
struct Stu
{
int age;
char sex[10];
}person;
(2)
struct Stu
{
int age;
char sex[10];
};
struct Stu person;
1.3结构体访问操作符
(1)直接访问
结构体变量.成员名(单纯访问到变量)
(2)间接访问
结构体变量->成员名(访问到成员的地址)
1.4结构体的初始化
(1)常量式
#include<stdio.h>
struct Stu
{
int age;
char sex[10];
};
int main()
{
struct Stu s={18,"male"};
return 0;
}
(2)变量式
#include<stdio.h>
struct Stu
{
int age;
char sex[10];
}s;
int main()
{
scanf("%d",&s.age);
scanf("%s",&s.sex);
return 0;
}
1.5结构体声明
其实定义结构体的时候,其实可以不输入tag的相应内容,但是呢,这样的结构体基本上只能使用一次!!!
二.结构体传参
下面两种传参方式,哪一种更好呢?
struct S
{
int data[1000];
int num;
};
struct S s={{1,2,3,4},1000};
//结构体传参
void print1(struct S s)
{
printf("%d\n",s.num);
}
//结构体地址传参
void print2(struct S*ps)
{
printf("%d\n",pa->num);
}
int main()
{
print1(s);//传值
print2(&s);//传地址
return 0;
}
很显然,print2更好。
reason:函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候, 结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
结论:结构体传参的时候,要传结构体的地址。
三.结构体的内存对齐(重中之重)
3.1对齐规则
1.结构体的第一个成员直接对齐到相对于结构体变量起始位置为0处偏移。
2.从第二个成员开始,要对齐到某个【对齐数】的整数倍的偏移处。
3.结构体的总大小,必须是最大对齐数的整数倍。每个结构体成员都有一个对齐数,其中最大的对齐数就是最大对齐数。
4.如果嵌套了结构体的情况。嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
sample:
首先,一般都是向较小的数取对齐数,例如,int大小为4,系统指定的对齐数为8. 8 > 4,所以取4为对齐数,红色和绿色的是存了的地址,白色的就是浪费的空间,所以说对齐方式很浪费空间,可是按照计算机的访问规则,这种方式提高了效率。从上可以看出,该结构体的大小为:1 + 4 + 1 + 3(浪费的空间(白色)) = 9,然后通过法则三知道9是不行的,要偏移到12,因为总大小要是最大对齐数的整数倍。
3.2包含结构体的计算
对于结构体中的结构体,关键的是把对齐数找到,可以看出SS结构体的大小为8,但是对齐数总大小不是按8为倍数的而是按4的的这就说明,结构体的大小在结构体中不会与指定对齐数进行比较,所以就可以把结构体SS看作是一个char和一个int类型。所以呢,结构体的总大小为:1 + 3 + 4 +1 + 3 + 4 + 1 + 3(偏移量) = 20。