目录
1.结构的声明
struct tag//标签
{
member-list;//成员
}variable-list://变量
例如我们想要声明一名学生的基本信息
struct student//自定义
{
char name[10];//姓名
int age;//年龄
char sex;//性别
}s1;
2.变量的创建和初始化
struct student//自定义
{
char name[10];//姓名
int age;//年龄
char sex;//性别
}s3//全局变量;
struct student s4;//全局变量
int main()
{
//按照结构体成员顺序初始化
struct student stu = { "zhangsan",18,'m' };//局部变量
printf("%s", stu.name);
//不按照结构体成员顺数初始化
struct student s1 = { .age=18,.name="lisi",.sex='m'};//局部变量
printf("%d", s1.age);
return 0;
}
特殊情况:匿名结构体
特点:没有标签
struct
{
char name[10];//姓名
int age;//年龄
char sex;//性别
};
struct
{
char name[10];//姓名
int age;//年龄
char sex;//性别
}s;
struct
{
char name[10];//姓名
int age;//年龄
char sex;//性别
}*p;
int main()
{
p = &s;
return 0;
}
从以上代码可以看到当主函数想要使用两个匿名结构体的时候编译器将两个声明当成两个完全不一样的类型,造成了非法访问,所以如果没有对匿名结构体进行重新声明的话,只能使用一次。
重新声明
使用typedef对结构体进行重新声明
typedef struct
{
char name[10];//姓名
int age;//年龄
char sex;//性别
}stu;
int main()
{
stu s;
return 0;
}
3.结构体自引用
struct node
{
int a;
struct node next;
//⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤,是不合理的
};
正确写法:应该在结构体内包含同类型结构体指针
struct node
{
int a;
struct node* next;
};
4.内存对齐
我们来看以下代码
struct s
{
int i;//4
char c;//1
int a;//4
};
int main()
{
printf("%zd", sizeof(struct s));
return 0;
}
int类型占4个字节,char类型占1个字节,但是运行结果却和我们预想的不一致,这就审计到了内存对齐的内容。
为什么要内存对齐?
1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:为了访问未对齐的内存,处理器需要 作两次内存访问;而对齐的内存访问仅需要⼀次访问。
总而言之就是为了节省时间而浪费一些内存的做法。
对齐规则:
1.结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的⼀个对齐数与该成员变量大小的较小值。
3.结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的 整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
运行结果也和我们预想的一致。
嵌套结构体情况
struct ss
{
char i;//1
char c;//1
int a;//4
};
struct s
{
char i;//1
struct ss s1;
};
int main()
{
printf("%zd", sizeof(struct s));
return 0;
}
结构体是用空间换时间,那怎样才能节省一些空间呢?
struct ss
{
char i;//1
char c;//1
int a;//4
};
struct s
{
char i;
int a;
char c;
};
int main()
{
printf("%zd\n", sizeof(struct ss));
printf("%zd", sizeof(struct s));
return 0;
}
答案就是让占用空间小的成员尽量集中在⼀起。