C结构体的几种定义形式 + typedef结合使用的好处
struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:
struct tag
{
member-list
member-list
member-list
...
} variable-list ;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。以下为实例:
C 结构体 | 菜鸟教程(<----摘抄了一部分菜鸟的C教程,这里链接给一下)
一、基本的结构体定义 (不使用 typedef
)
1. 声明了 结构体标签;不声明结构体变量。(方式1)
struct 结构体标签 {数据类型 成员1;数据类型 成员2;// ... 更多成员
};
这种是结构体最常用也是最基本的定义方式。
struct
: 关键字,表示定义一个结构体。
结构体标签
: 给这个结构体类型起的名字 (类似于盒子的名字)。 你以后可以靠这个标签来声明这个类型的变量。
{ ... }
: 花括号里定义一个个“成员”(类似于盒子里的每一个积木)。每个成员都有自己的数据类型(比如 int
, float
, char
)和名称。
//使用举例:
struct Point
{ int x; int y;
}; // 声明一个Point类型的变量(创建了一个盒子)
struct Point p1; //每次声明变量的时候,都需要加上 struct 关键字。
p1.x = 10; // 访问成员
p1.y = 20; // 访问成员
特点: 每次声明变量的时候,都需要加上 struct
关键字。
2. 声明了 结构体变量;不声明 结构体标签。(方式2)
struct {数据类型 成员1;数据类型 成员2;// ...
} 变量名;
这种方式 没有结构体标签,它直接定义一个匿名结构体的变量。 创建一个盒子,并给这个盒子装上东西,但是没有给盒子起名字。
//使用举例:
struct {int x;int y;
} p5; // 定义了一个匿名的结构体变量 p5p5.x = 70;
p5.y = 80;// 再次定义会报错,因为结构体“长相”不同
// struct {
// int x;
// int y;
// } p6; // 错误!
特点: 只能在定义的时候创建变量。 无法再创建同类型的其他变量,因为没有结构体标签来指示类型。 通常很少使用。
3. 同时声明了 结构体变量 和 结构体标签。(方式3)
struct 结构体标签
{ 数据类型 成员1; 数据类型 成员2; // ... 更多成员
}变量名;
解释: 同时定义了结构体标签P2和结构体变量S2。后续可以再通过结构体标签 P2,再定义S3,S4之类的结构体变量(struct P2 S3,S4;),可以理解其走了两步,第一步为:struct P2
{ int a; char b; double c; }; 第二步为:struct P2 S2;
1. .h 文件中直接定义这种形式,在编译中不通过,这种形式同时完成了结构体声明和结构体定义,想象一下,如果你把 struct P2 S2; 放在一个 .h 文件里,并被多个 .c 文件 #include 了。 那么,每个包含这个 .h 文件的 .c 文件都会试图创建变量 S2。 这会导致 重复定义错误 (编译器会报错,因为同一个变量被多次定义了)。
2.可以放在某个.c文件中编译通过;
二、与 typedef联合使用
1. 使用 typedef
定义结构体 (带标签)(方式4)
typedef struct 结构体标签 {数据类型 成员1;数据类型 成员2;// ...
} 新的类型名;/*typedef
struct 结构体标签 {数据类型 成员1;数据类型 成员2;// ...
}
别名;*/
typedef
: 关键字,用于给一个数据类型(包括结构体)起个别名。
新的类型名
: 你给这个结构体类型新起的名字 (类似于给盒子起个外号)。 以后可以用这个新的名字来声明变量,而不需要写 struct
了。
typedef struct Point { // 这个结构体叫 Point,并且起了一个"别名" MyPointint x;int y;
} MyPoint;// 声明一个Point类型的变量(创建了一个盒子)
MyPoint p2; // 不需要写 "struct" 了!
p2.x = 30;
p2.y = 40;
特点:以后声明变量时,可以直接使用新起的类型名。更简洁,更方便。 推荐使用 typedef
来定义结构体。
2. 使用 typedef
定义匿名结构体 (无标签)(方式5)
typedef struct {数据类型 成员1;数据类型 成员2;// ...
} 新的类型名;
这种定义方式 没有结构体标签。 这样定义的结构体只能通过 typedef
赋的别名来使用。
//使用举例:
typedef struct { // 没有 "结构体标签"int x;int y;
} MyPoint; // 定义结构体的时候同时定义了别名MyPoint p3;
p3.x = 50;
p3.y = 60;// 错误,因为没有定义结构体名称
// struct { int x; int y; } p4; // 错误!
特点: 只能使用 typedef
定义的别名来声明变量。 因为没有结构体标签,所以无法再用 struct { ... } 变量名;
这种方式定义变量。
3.在结构体定义时就进行初始化 (配合 typedef 与否均可)
解释: 在定义结构体变量的同时,给它的成员赋值。
3.1使用 typedef
typedef struct Point {int x;int y;
} MyPoint;MyPoint p1 = {100, 200}; // 直接初始化
3.2不使用 typedef
struct Point {int x;int y;
};struct Point p2 = {300, 400};
总结:
-
推荐: 使用
typedef
结合结构体标签。 这样既可以给结构体起别名,又方便以后阅读和维护代码。 -
一般避免: 直接定义匿名结构体变量(方式2)。 因为你很难重复使用这个类型。
-
匿名结构体: 适合在定义后立即使用,并且不希望再定义同类型结构体的情况。 比较少见。