想要知道typedef是什么,那么故事就要从 struct讲起,其实挺简单的。
总结:
定义存储结构的新变量时,需要struct关键字;
使用typedef定义、声明变量时就可以删除struct关键字。
没有struct这个关键字,代码看起来会更简单、更容易理解。
正片开始:
- 结构体类型——struct
结构体是一种较为复杂但却非常灵活的构造型数据类型(就是我们自己造出来的类型
最初我们先学习的是定义变量,但是一个变量只能给它赋一个值,
后来呢,为了实现定义一个变量就能给它赋多个值,就出现了【数组】,
但是,一个数组里面存放的元素都必须是同一种类型。
怎样才能定义一变量就能使用多个值,同时值还能不受类型的限制呢?
于是就出现了结构体。
结构体类型的说明格式,如下
struct 结构体标识名 (
取张三狗蛋都行类型名1(int / double / float / char) 结构成员1,2,3……
类型名2(int / double / float / char) 结构成员1,2,3……
……
类型名n(int / double / float / char) 结构成员1,2,3……
}
举个例子,你家打算养一匹马(爱上一匹野马,可我的家里没有草原 )
你想知道这匹马的信息,比如年龄多大、有多高,父母亲叫什么等等。
struct Horse
{
int age;
int height;
char name [20];
char dad [20];
char mom [20];
};
[Horse] 是定义的结构标记符,也是我们新定义出来的结构类型,一个结构就是一个复合的数据类型。
[Horse] 的地位就好比int、float、double、char等数据类型。
假如,你想给你家的一匹马取名叫 “张三”;你就可以这样赋值
struct Horse zhang_san = {
4, 170, "张三", "张大山", "李四"
};
在这里我们声明该[struct Horse]类型的变量为zhang_san;
注意: 结构定义、结构变量声明语句都用分号结束。
在 “张三”结构成员的初始值中,张三的父亲是“张大山”,母亲是“李四”;
对结构体变量赋值是C编译程序按每个成员在结构体中的顺序一一对应赋值,
不允许跳过前面的成员而给后面的成员赋值;
但是可以只给前面的若干个成员赋值,后面没有赋值的成员,系统将自动为数值型和字符型数据赋值为0;
当然,也可以在一行语句中声明多个结构变量。
声明的方式和声明C语言标准类型的多个变量一样。例如:
struct Horse a1, a2;
上面这行语句声明了两个Horse类型的变量 a1, a2;
比起标准类型的声明,这个声明只增加了关键字struct。
为了使这行语句简单我在此没有初始化变量,一般应初始化变量且Horse类型的每个变量都应有自己的一组字段。
定义存储结构的新变量时,需要struct关键字,但没有这个关键字代码看起来会更简洁。所以struct的克星typedef就出现了。
- typedef
使用typedef定义,声明变量时就可以删除struct关键字。例如:
typedef struct Horse Horse;
这个语句把Horse定义为struct Horse。把这个定义放在源文件的开头,下文就可以定义Horse类型的变量:
Horse wang_wu = {
3, 150, "王五", "王大五", "赵六"
};
不再需要struct关键字,代码也更简洁,结构类型看起来像是普通的类型。
- 访问结构成员
现在知道如何定义结构及声明结构变量了,还必须引用结构的成员。
结构变量的名称不是一个指针,所以需要特殊的语法访问这些成员。
要引用结构成员,应在结构变量名称的后面加上一个句点,再加上成员变量名称。
举个栗子,假如小马 “张三” 的岁数不是4,而是5;就要将其修正,如下;
zhang_san.age = 5;
结构变量名称和成员名称间的【.】称为“成员选择运算符”;
结构成员和相同类型的变量完全一样,可以给它们设定值,也可以像普通变量一样使用它们。
其实,在初始化列表中,可以指定成员名,如下:
Horse wang_wu = {
.height = 150, .name = "王五", .age = 3, .mom = "赵六",.dad = "王大五"
};
现在哪个成员初始化什么值就不容易出错了,我们可以按照不同的顺序初始化列表。
结构体的长度是所有成员变量的长度和。
- 未命名的结构
不一定要给结构指定标记符名字。
用一条语句声明结构和该结构的实例时,可以省略标记符名字。在上边提到的例子中,声明了Horse类型和该类型的实例zhang_san,也可以改为:
struct Horse
{
int age;
int height;
char name [20];
char dad [20];
char mom [20];
}zhang_san; //简化了复杂的名字
最后一个大括号与分号之间的zhang_san 目的是简化紧随stuct之后的标记符名字Horse;
结构类型定义通常放在全局作用域中。
typedef 和 struct 的定义在main()外部,是全局作用域。这表示Horse类型可以用于源文件中的任何函数。
也可以把该定义放在main()函数体中,这样该类型就是main()的局部类型。
- 将一个结构作为另一个结构的成员
前边讲的结构体类型包含了马的各种数据,比如:名字、身高、年龄、父母亲名字等等;如果我们想要增加一个马的生日信息,该怎么做?
日期处理起来比较麻烦,要用3个数值来表示,还要处理闰年问题。
现准备将一个结构作为另一个结构的成员来处理日期。
可以定义一个用于保存日期的结构类型。下面的语句用标记符名称Date定义了这个结构:
struct Date
{
int day;
int month;
int year;
};
也可以给Date和Horse包含一个typedef语句:
typedef struct Horse Horse;
typedef struct Date Date;
typedef 把 Horse 定义为等价于 struct Horse。
typedef 把 Date 定义为等价于 struct Date。
现在定义 Horse 结构,其中包含出生日期变量,如下所示:
struct Horse
{
Date birthday;
int height;
char name [20];
char dad [20];
char mom [20];
};
现在结构中有一个变量成员Date birthday,它代表马的出生日期,这个成员本身就是一个结构,不需要使用关键字,因为typedef 把 Date 定义为等价于 struct Date。
- 声明结构中的结构
可以在horse结构的定义中声明Date结构,如下:
struct Horse
{
struct Date
{
int day;
int month;
int year;
}birthday;
int height;
char name [20];
char dad [20];
char mom [20];
};
这个声明将Date结构声明放在Horse结构的定义内,因此不能在Horse结构的外部声明Date变量。当然,每个horse类型的变量都包含Date类型的成员birthday,但下面的语句:
struct Date my_Date;
会导致编译错误。错误信息会说明Date结构类型未定义。如果需要在horse结构的外部使用Date,就必须将它定义在Horse结构之外。