上一篇:从0开始学c语言-31-关于字符串的各种函数+字符串旋转判断_阿秋的阿秋不是阿秋的博客-CSDN博客
目录
开始之前请注意最重要的一点:
这是自定义类型,它是一种数据类型,是一种让编译器知道该如何分配你传递过来的数据的数据类型,只不过这种类型是你自定义的。而这种类型的声明是并不会向内存申请分配空间的,只有你在把它变为自定义类型(结构体、枚举、联合)变量的时候才会分配相应的内存空间,单纯的自定义类型声明并不会占用内存!!!
1` 结构体
之前有写过两篇
从0开始学c语言-22-结构体声明和初始化、结构体大小、结构体成员访问、结构体传参_阿秋的阿秋不是阿秋的博客-CSDN博客
从0开始学c语言-10-结构体以及一些作业_阿秋的阿秋不是阿秋的博客-CSDN博客
所以结构体这里简单介绍就过了。
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
1`2 结构体声明
struct tag
{
member-list;
}variable-list;
特殊的声明
在声明结构的时候,可以不完全的声明。
//匿名结构体类型
struct
{
int a;
char k;
int arr[12];
}s;//依旧可以创建结构体变量
struct
{
int a;
char k;
int arr[12];
}*ps;
int main()
{
ps = &s; //err
//虽然成员变量都一样,但是
//编译器依旧认为这两个不是同一类型的
return 0;
}
上面的两个结构在声明的时候省略掉了结构体标签( tag )注:只能用一次,因为没有结构体tag
1`3 结构的自引用
错误的自引用
struct n
{
int a;
struct n k; //计算size会死循环,不能这样
};
//会警告类型不完整
正确的自引用方式是在结构体中创建 指向本结构体 的结构体指针。
struct n
{
int a;
struct n* next;
};
至于怎么自引用,看图。
自引用的原理图
分为指针域和数据域,实际上和数据结构有关。
重命名
思考如果我们这样重命名行不行
typedef struct
{
int data;
Node* next;
}Node;
这样写不行,因为不知道先有的Node,还是Node指针
应该这样写。
typedef struct Node
{
int data;
struct Node* next;
}Node;
1`4 结构体变量的定义和初始化
struct Point //类型声明
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
struct Node
{
int data;
struct Point p; //结构体
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
1`5 结构体内存对齐(求大小)
虽然我在这篇文章里
从0开始学c语言-22-结构体声明和初始化、结构体大小、结构体成员访问、结构体传参_阿秋的阿秋不是阿秋的博客-CSDN博客
写过求结构体大小的方法,但是那个方法没有这个更接近本质。
结构体的对齐规则:1. 第一个成员在 与结构体变量偏移量 为0的地址处。2. 其他成员变量要 对齐 到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员类型大小的较小值。VS中默认的值为8;成员类型大小(数组只看指向类型的大小);3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
练习1:
struct S1
{
char c1;
int i;
char c2;
};
按照上面的规则,算一下这个结构体的大小。
1. 第一个成员在 与结构体变量偏移量 为0的地址处。
struct S1
{
char c1; //偏移量0
int i;
char c2;
};
2. 其他成员变量要 对齐 到某个数字(对齐数)的整数倍的地址处。对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。