Appearance
结构体和联合
聚合数据类型能同时存储超过一个的单独数据,C语言提供了两种,数组和结构。
元素数组可以通过下标访问,结构体不能。
结构体名不能当成指针来使用
结构体属于标量类型,可以作为函数参数,相互之间可以相互赋值
结构体声明
C
struct tag{number-list}variable-list;
必须列出所有的成员,就算两个结构体的成员完全一样,最后的结构体也是两种不同的结构体
C
struct {
int a;
char b;
float c;
}x;//声明一个结构体
struct {
int a;
char b;
float c;
}y[20], *z;//声明一个结构体的数组以及一个指针
和typedef一块使用
C
tyoedef struct{
int a;
char b;
float c;
}Simple;//重命名为Simple
结构体成员的直接访问
不同结构体可以拥有名字相同的结构体成员
- 通过( .)直接访问
((comp.sa)[4]).c <===> comp.sa[4].c
间接访问
有一个结构体的指针cp,访问他的成员
(*cp).c
==> ( .)的优先级要比*的优先级要高,所以要加括号- cp->c
结构体的自引用
C
struct SELF_REF1{
int a;
struct SELF_REF1 b;
int c;
};//错误的引用,会生成无限多的结构体
struct SELF_REF2{
int a;
struct SELF_REF1 *b;
int c;
};//正确的使用方法
typedef struct{
int a;
SELF_REF3 *b;
int c;
}SELF_REF3;//错误,使用的结构体声明还没有定义
typedef struct SELF_REF3_TAG{
int a;
SELF_REF3_TAG *b;
int c;
}SELF_REF3;//正确
不完整的声明
C
struct B;
struct A{
struct B *partner;
...
};
struct B{
struct A *partner;
...
};
初始化类
似于多维数组
结构、指针和成员
C
typedef struct {
int a;
short b[2];
}Ex2;
typedef struct EX{
int a;
char b[3];
Ex2 c;
struct EX *d;
}Ex;
Ex x = {10, "Hi",{5, {-1, 25}}, 0};
Ex *px = &x;
访问指针
px+1
:不合法,会指向下一个相邻的结构体大小的内存
*px->c.b
:直接访问数组的第一个变量
结构体的存储分配
编译器禁止结构体的起始位置跳过几个字节,所以结构体的对齐是按照最严格的成员对齐的
每一个成员都必须对齐
- 在创建结构体的时候对齐要求严格的数据先出现
C
1 #include <stdio.h>
2 #include <stddef.h>
3 struct A{
4 int a;
5 short b;
6 char c;
7 }a;
8
9 int main(void)
10 {
11 printf("%d\n", offsetof(struct A, a));
12 printf("%d\n", offsetof(struct A, b));
13 printf("%d\n", offsetof(struct A, c));
14 }
result:
0
4
6
可以使用stddef.h中的offsetof(type, nember);
查看每一个元素的偏移
作为函数参数的结构体
- 直接把结构体作为参数:占用的空间大,不适合多次调用,效率低
- 指针传递:必须用间接访问来访问参数
位段
声明和结构体类似但是成员是一个或者多多个位的字段,不同长度的字段实际存储于一个或者多个整形之中
注意
- 在意可移植性的程序少使用
- 是有符号数还是无符号数
- 位段的最大值
- 位段成员分配方向
联合
存储在内存的相同位置
当一个数据有好几种可能性的时候就可以使用,可以和结构体联合使用,定义不同的成员
C
struct A1{
...
};
struct A2{
...
};
struct B{
enmu {A1, A2} type;
union{
struct A1;
struct A2;
}info;
}
联合体的长度是成员的最大值
初始化
它的初始化必须初始化第一个成员,并且位于一个大括号之中
C
union {
int a;
float b;
char c[4];
}x = {5};