本篇文章主要是对结构体数据类型的一个知识扩展,包含了结构体的嵌套使用、结构体数组、结构体指针。
1. 构造体的嵌套使用
在学习结构体时,有提到结构体里面的成员可以是基本数据类型,也可以是数组、结构体等其他类型。
那么,接下来就说一下,在定义结构体中嵌套另一个结构体的两种方法。
第一种方法:独立结构嵌套。
分别定义了两个结构,然后将其中一个结构嵌套在另一个结构中。
struct Birthday{
int dd;
int mm;
int yy;
};
struct Student{
char *name;
struct Birthday birthday;
};
这里需要注意两个点:
A. 嵌套的结构体(Birthday)必须要在被嵌套的结构体(Student)之前定义,如果顺序反了,编译器是不会通过的,会给出如下报错。
error: field 'birthday' has incomplete type
错误:字段'birthday'的类型是不完整的
这是因为C语言程序的编译是自上而下执行的。
如果两个结构体的顺序写反了,编译器首先是执行到 Student 结构,看到里面的 Birthday 结构声明的变量,因为结构体是程序员自定义的数据类型,系统是不提供的,而这里的 Birthday 结构还没有进行定义,所以C语言是不认识这种数据类型,就会给出报错。
B. 在定义结构中嵌套另一个结构,如果没有定义结构的别名,struct 和结构名称必须同时出现,才表示为结构体类型。
同时在结构体中,一个完整的成员必须包含类型以及变量名,缺一不可。
第二种方法:嵌入式嵌套
这种方式就不用考虑两个独立结构谁先谁后的问题,只需要在被嵌套的结构(Student)中以嵌入的方式定义嵌套的结构(Birthday)类型。
struct Student{
char *name;
struct Birthday{
int dd;
int mm;
int yy;
} birthday;
};
和前面的独立结构嵌套相比,如果嵌套的结构体比较少,可以采用这种方式。但是要嵌套好几个结构体,建议还是使用独立嵌套的方式,否则会导致代码看上比较冗长复杂。
嵌套结构体的初始化和访问方式如下:
// 变量初始化
Struct Student s1 = {"张三", {1,1, 2000}};
// 访问 Birthday 结构中 dd 成员;
s1.birthday.dd; // 1
关于结构体嵌套,还有一个非常重要的问题:所定义的结构体能将自身类型作为成员吗?
struct A{
struct A a;
} aa;
答案是不能的,像上面这种写法是错误的。
嵌套的是定义结构自身的变量,就会出现这种情况:aa.a.a.a.a.a.a……就会一直无限循环下去。
在内存分配的时候,由于无法确定所定义的结构体地长度,就不会被系统允许。
但是如果想要引用自身,也不是不行,可以通过指针来进行使用。
指针类型,无论是什么类型的指针,所占的内存大小都是固定的。
struct A{
struct A *a;
} aa;
结构体的指针类型的声明方式如下:
struct 结构名称 *变量名;
结构体的指针声明和基本数据类型是一样,都需要带上寻址运算符(&)。
struct Student{
char *name;
int age;
};
struct Student s1 = {"张三", 15};
struct Student *ps1 = &s1;
通过指针类型访问结构体中的成员的方式有两种。
第一种,通过访问运算符。
(*ps1).name; // 张三
由于访问运算符的优先级比较高,所以需要对 *ps1 添加上括号。
如果没有加上括号,先执行的是 ps1.name,而 ps1 是一个指针变量,所存储的是结构体 s1 的内存地址。
第二种方式,通过箭头运算符 -> 进行访问。
箭头运算符是C语言结构体的一种特殊的运算符,可以直接从结构体指针变量中访问结构体里面的成员。
ps1->age; // 15
数组,是用来存储相同类型的集合。
结构体数组,用来存储同一个结构类型的不同数据,也叫作结构的集合。
例如,定义了一个学生的结构,而一个班里面又有很多个学生。总不能一个一个地去声明不同数据的学生结构类型,这样做就是显得太麻烦了。
这时候,我们就可以用一个数组变量来存储起来。
结构体数组的定义方式如下:
struct Student{
char *name;
int age;
} class[5] = {
{"孙悟空", 500};
{"唐僧", 33};
{"猪八戒", 101};
{"沙僧", 98};
{"白龙马", 102};
};
定义的结构体数组变量 class 中括号里面的数字,如果有进行初始化操作,即数组中全部元素都已经赋值,则可以不用带。系统会自动根据数组里面的内容,给该数组确定相应的长度。
如果没有进行初始化,则必须要带上数组长度,否则就会出错。
结构体数组的访问方式也比较简单,通过数组索引值取出相应的结构,再通过访问运算符进行访问。
例如:我们想知道唐僧的年龄。
class[1].age; // 33
以上就是关于构造数据类型,结构体的知识扩展内容,包括了嵌套使用、结构体指针以及结构体数组的知识。
,