一.结构体类型的声明
结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量。结构的声明基本形式:
struct tag
{
member-list;
}variable-list;
例如描述一个学生:
二.结构体变量的创建和初始化
我们直接先来看一个例子:
s1,s2,s3都是结构体变量,这些变量和上面的s4,s5,s6变量是一个道理的,但是上面的是全局的结构体变量,下面的是局部变量。
初始化的时候,因为结构体不是一个成员,我们要用大括号初始化,按着顺序一个一个给值,对变量初始化,这就是结构体变量的初始化。
比如:
我们还可以用另一种方式赋值。
三.结构成员访问操作符
我们举例来看怎么样访问结构体成员,并顺便把它打印出来。
这里用到了.操作符,用法是:结构体变量名.成员名。
四.结构体的特殊声明
在声明结构的时候,可以不完全的声明,比如:
这个时候结构体类型是没有名字的,这个结构体类型就叫做匿名结构体类型。匿名结构体-这种类型只能使用一次,因为它无法再进行创建变量。就是第一次创建这结构体类型的时候,用这个类型直接创建一个变量,只用一次,以后再也用不上了。
我们再来看这个代码:
第二段代码之前的是结构体指针类型,结构体类型加一个星就是结构体指针类型,p就是指针变量,所以p可以存放地址,那我们到底能不能将x的地址赋给p呢?
显然实际上是不行的,会报警告,编译器会认为这是两种不同的类型,因为这两个结构体连名字都没有,无法识别类型,所以当你赋值的时候会报警告。
编译器会把上面的两个声明当成完全不同的两个类型,所以是非法的。匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次。一定要记住:如果你要匿名,你要保证只用一次。
五.结构的自引用
这个结点能存数据又能有义务找到下一个结点,那该怎么做呢?我们先画图理解一下:
那我们把这个结点设置一个结构体,让它既包含数据,又包含下一个结点,每个结点都能包含一个数据和一个结点。那我们这样做到底行不行呢?
其实是不行的。我们怎么算这个结构体大小是多少?一个结点包含一个同类型的结点,那就是结点里面套结点,结点里面套结点,一直下去,理论上这个结点的大小是无限大的。所以这种写法一定是错误的。
那像链表这些结构怎么来定义呢?我们不就是想要这个结点找到下一个结点吗?,我们把下一个结点的地址放到上一个结点中不就行了。来看:
这个时候大小就比较好算了,一个指针不就是4个或8个字节,还有一个整型4个字节,所以整体结构体大小我们也能算出来。
这就是结构体自引用,一个结构体变量里面想找到跟它同类型的其他结点,那我们就可以用一个结构体指针变量作为这个结构体的成员。其实链表就是基于这种形式实现的,它的结点就是像我们上面的写的代码一样定义的。
正确的自引用方式:
struct Node
{
int data;
struct Node* next;
};
在结构体自引用使用的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引起问题,我们来看下面的代码:
我们用typedef重命名结构体名字为:Node,我们括号里面成员也改成Node* next,我们这样写有问题吗?
我们发现报错了,意思是当我们在括号里面成员使用Node的时候还没有Node。我们是有这个结构体类型才产生名字Node,而你在括号里面就提前用到了Node,这样是不行的,那我们怎么办呢?请看下面:
所以当你这结构体里面有同类型指针的时候,不要用它重命名新的名字,用旧的名字。从上面我们看到结构体有对齐方式,这是什么意思?,这就是我们将要讲的结构体内存对齐。
敬请期待下一篇,读下来对你有用的话,请给作者留下一个: