第6章 结构

1. 结构体基础

1.1 结构体的定义

  • 使用 struct 关键字定义复合数据类型:
    struct point {
        int x;
        int y;
    };
    
  • 结构体可以包含不同类型的成员(int, float, char 等)。
  • 结构体变量声明方式:
    struct point pt; // 声明一个point结构体变量pt
    

1.2 结构体成员的访问

  • 使用 . 运算符访问成员:
    pt.x = 10;
    pt.y = 20;
    
  • 结构体可以嵌套(成员可以是另一个结构体)。

重点难点

  • 结构体定义不分配内存,只有声明变量时才分配。
  • 结构体不能直接比较(如 pt1 == pt2 是错误的),必须逐成员比较。

2. 结构体操作

2.1 结构体赋值

  • 结构体可以整体赋值(按值拷贝):
    struct point p1 = {1, 2};
    struct point p2 = p1; // p2是p1的副本
    

2.2 结构体数组

  • 可以定义结构体数组:
    struct point points[10];
    points[0].x = 100;
    

2.3 结构体作为函数参数

  • 可以传值(拷贝整个结构体):
    void printPoint(struct point p) {
        printf("%d, %d", p.x, p.y);
    }
    
  • 也可以传指针(更高效):
    void printPoint(struct point *p) {
        printf("%d, %d", p->x, p->y);
    }
    

重点难点

  • 传值 vs 传指针
    • 传值:安全但效率低(大结构体拷贝开销大)。
    • 传指针:高效但可能修改原数据(可加 const 防止修改)。

3. 结构体指针

3.1 指向结构体的指针

  • 声明方式:
    struct point *pp; // 指向point结构体的指针
    
  • 使用 -> 访问成员:
    pp = &pt;
    printf("%d", pp->x); // 等价于 (*pp).x
    

3.2 动态内存分配

  • 结构体指针常用于动态数据结构(如链表):
    struct node *np = (struct node *)malloc(sizeof(struct node));
    

重点难点

  • 指针访问 vs 直接访问
    • (*pp).xpp->x 是等价的,但 -> 更简洁。
  • 内存管理
    • 动态分配的结构体必须手动释放(free),否则内存泄漏。

4. 类型定义(typedef)

4.1 typedef 简化结构体类型

  • 使用 typedef 定义新类型名:
    typedef struct {
        int x;
        int y;
    } Point; // 现在可以直接用 Point 代替 struct point
    
  • 使用方法:
    Point p = {1, 2};
    

重点难点

  • typedef 只是别名,不创建新类型,编译时仍视为原类型。

5. 联合(union)

5.1 联合的定义

  • 联合(union)的所有成员共享同一块内存:
    union data {
        int i;
        float f;
        char c;
    };
    
  • 同一时间只能存储一个成员的值(修改一个会影响其他)。

5.2 联合的用途

  • 节省内存(如存储不同类型但不同时使用的数据)。
  • 实现变体数据类型(如解析网络协议数据)。

重点难点

  • 联合的大小:由最大成员决定(如 union data 大小是 float 的大小)。
  • 类型安全:读取错误的成员会导致未定义行为(如存 intfloat)。

6. 位字段(Bit Fields)

6.1 位字段的定义

  • 允许按位定义结构体成员:
    struct {
        unsigned int is_keyword : 1; // 1位
        unsigned int is_extern  : 1;
        unsigned int is_static  : 1;
    } flags;
    

6.2 位字段的用途

  • 节省内存(如标志位存储)。
  • 直接操作硬件寄存器(如嵌入式开发)。

重点难点

  • 可移植性问题
    • 位字段的存储方式(从左到右还是从右到左)由编译器决定。
  • 位字段不能取地址(如 &flags.is_keyword 是错误的)。

7. 应用实例

7.1 单词计数程序

  • 使用结构体存储单词及其出现次数:
    struct key {
        char *word;
        int count;
    } keytab[NKEYS];
    

7.2 链表实现

  • 动态结构体指针构建链表:
    struct node {
        int data;
        struct node *next;
    };
    

重点难点

  • 链表操作
    • 插入、删除节点时要注意指针的正确维护,否则会导致内存错误。

8. 总结

8.1 重点回顾

  1. 结构体:用于组织复杂数据,支持 .-> 访问。
  2. 结构体指针:提高效率,用于动态数据结构。
  3. typedef:简化类型名,提高代码可读性。
  4. 联合:共享内存,节省空间,但需谨慎使用。
  5. 位字段:精确控制内存,但可移植性差。

8.2 难点总结

  • 结构体传参:大结构体应传指针而非值。
  • 动态内存管理mallocfree 必须配对使用。
  • 位字段的可移植性:不同编译器可能有不同实现。

本章是C语言高级数据组织的核心内容,掌握结构体和指针的使用是后续学习数据结构(链表、树、图)的基础。

posted @ 2025-05-12 10:10  MachineGaming  阅读(19)  评论(0)    收藏  举报