结构体
目录
一、结构体类型的声明
首先我们来了解一下结构的基础知识:
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以不同类型的变量。
如数组是一组相同类型的元素的集合,而结构体也是一些值的集合,结构体的每个成员可以是不同类型的。
结构的声明
struct tag
{
member-list;
}variable-list;
//结构体关键字:struct
//结构体的标签:tag
//结构体的类型:struct tag
//结构的成员列表:member_list
//结构体变量列表:variable_list
例:
#include <stdio.h>
//声明一个结构体类型
//声明一个学生类型,是想通过学生类型来创建学生变量(对象)
//描述学生:属性 - 名字+性别+年龄+电话号码
struct Stu
{
char name[20]; //名字
char sex[10]; //性别
int age; //年龄
char phone[12];//电话
}; //记住这里要加分号
struct Stu s3;//全局变量
int main()
{
//创建的结构体变量
struct Stu s1;
struct Stu s2;
return 0;
}
特殊的声明
在声明结构的时候,可以不完全的声明。
例:
//匿名结构体类型
struct
{
int a;
char c;
}sa;
struct
{
int a;
char c;
}* psa;//匿名结构体指针类型
思考:在上面代码的基础上,下面的代码合法吗?
int main()
{
psa = &sa;
return 0;
}
执行结果:
警告:编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的。
结论:当两个匿名结构体类型内部的内容一样时,仍然是两个不同结构体类型
二、结构的自引用
思考1:在结构中包含一个类型为该结构本身的成员是否可以呢?
//代码1
struct Node
{
int data;
struct Node next;
};
思考2:可行吗?如果可以,那sizeof(struct Node)是多少?
解答:不行。
假设代码1中的方式可以执行,那么在创建结构体的过程中,struct Node next由于结构体struct Node类型还没创建完成,所以其类型的大小是未知的,而struct Node类型的是否能成功创建又依赖于struct Node next类型大小的确定性。
所以这两者自相矛盾。因此上述方法不行!
结构体正确的自引用方式
//代码2
struct Node
{
int data;//4 数据域
struct Node* next;//4/8 指针域
};
思考3:这串代码为什么可以成功呢?
解答:首先此处结构体自应用方式并不是直接利用结构体来创建变量,而是创建指向该结构体类型的指针。
我们知道,指针的大小跟其所指向的类型无关,仅跟平台环境有关,32位平台指针大小为4个字节,64位平台,指针大小为8个字节。
正因为指针大小的确定性,所以再自引用的时候结构体类型的整体大小也是可以确定的。
思考4:这样写代码可行吗?
//代码3
typedef struct
{
int data;
Node *next;
}Node;
解答:不行
由于此时struct后面省略掉了Node,所以匿名重新命名结构体为Node,那么此时编译器就会不认识Node。(就好比先有鸡还是先有蛋)
因为结构体类型有重命名才能产生Node,而此时还未定义Node就在结构体内部使用了Node,所以会产生错误。
解决方案:
typedef struct Node
{
int data;
struct Node *next;
}Node;