Skip to content

结构体和联合

聚合数据类型能同时存储超过一个的单独数据,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};