C语言程序设计进阶_浙江大学

32 阅读3分钟

一、结构体与联合体的概念与区别

在C语言中,结构体(struct)和联合体(union)是两种重要的复合数据类型,它们都能将不同类型的数据组合在一起,但在内存使用和访问方式上有显著差异。

结构体是将不同类型的数据项组织在一起的数据结构,每个成员拥有独立的内存空间。例如:

struct Student {
    char name[20];
    int age;
    float score;
};

联合体则是所有成员共享同一块内存空间,同一时间只能存储一个成员的值。例如:

union Data {
    int i;
    float f;
    char str[20];
};

关键区别:

  1. 内存分配:结构体成员占用独立空间,联合体成员共享空间
  2. 大小计算:结构体大小为各成员之和(考虑对齐),联合体大小为最大成员大小
  3. 使用方式:结构体可同时访问所有成员,联合体同一时间只能有效访问一个成员

二、结构体的高级特性

1. 结构体嵌套

结构体可以嵌套其他结构体,构建更复杂的数据结构:

struct Address {
    char city[20];
    char street[50];
};

struct Employee {
    char name[20];
    struct Address addr;
    int salary;
};

2. 结构体指针与动态分配

结构体指针常用于动态内存分配和函数参数传递:

struct Student *p = malloc(sizeof(struct Student));
p->age = 20;  // 使用箭头运算符访问成员

3. 位域结构体

位域允许按位分配结构体成员,节省内存空间:

struct {
    unsigned int flag1 : 1;
    unsigned int flag2 : 3;
    unsigned int flag3 : 4;
} status;

三、联合体的特殊应用

1. 类型转换

联合体可用于实现不同类型数据的转换:

union Converter {
    float f;
    unsigned int i;
} conv;

conv.f = 3.14;
printf("Float as int: %x\n", conv.i);

2. 变体记录

联合体常用于实现变体记录,存储不同类型但互斥的数据:

struct Variant {
    int type;
    union {
        int i;
        float f;
        char *s;
    } value;
};

3. 硬件寄存器映射

在嵌入式系统中,联合体常用于映射硬件寄存器:

union ControlReg {
    unsigned int raw;
    struct {
        unsigned int enable : 1;
        unsigned int mode : 3;
        unsigned int reserved : 28;
    } bits;
};

四、实战案例分析

案例1:学生成绩管理系统

使用结构体数组管理学生信息:

struct Student {
    int id;
    char name[20];
    float scores[3];  // 三门课成绩
    float average;
};

void calculateAverage(struct Student *s) {
    s->average = (s->scores[0] + s->scores[1] + s->scores[2]) / 3;
}

案例2:网络协议解析

使用联合体解析网络数据包:

union IPAddress {
    unsigned int address;
    unsigned char octet[4];
};

void printIP(union IPAddress ip) {
    printf("%d.%d.%d.%d", ip.octet[0], ip.octet[1], ip.octet[2], ip.octet[3]);
}

五、性能与内存优化建议

  1. 结构体对齐:合理安排成员顺序减少填充字节
  2. 结构体大小:对于大型结构体数组,考虑使用指针数组
  3. 联合体使用:在需要节省内存且数据互斥时优先考虑
  4. 内存布局:了解平台的对齐要求,优化数据访问速度

六、总结

结构体和联合体是C语言中强大的数据组织工具。结构体适合组织相关联的数据,而联合体则适合处理互斥数据或需要类型转换的场景。深入理解它们的内存布局和使用方式,能够帮助开发者编写出更高效、更灵活的代码。在实际应用中,应根据具体需求选择合适的数据结构,并注意内存使用和性能优化。