c_snake_game

第 6 课:结构体 🏗️

结构体允许你将不同类型的数据组合在一起。这是创建复杂数据结构的基础。


6.1 为什么需要结构体?

问题:如何表示一条蛇?

// ❌ 使用多个独立变量
int snake_x1 = 10, snake_y1 = 10;
int snake_x2 = 9,  snake_y2 = 10;
int snake_x3 = 8,  snake_y3 = 10;
int snake_length = 3;
// ... 很难管理!
// ✅ 使用结构体
typedef struct {
    int x;
    int y;
    int length;
} Snake;

Snake snake = {10, 10, 3};

6.2 结构体的定义

// 定义结构体类型
struct Point {
    int x;
    int y;
};

// 创建结构体变量
struct Point p1;
p1.x = 10;
p1.y = 20;

// 或者初始化
struct Point p2 = {30, 40};

使用 typedef 简化

// 使用 typedef 创建别名
typedef struct {
    int x;
    int y;
} Point;

// 现在可以直接使用 Point,不需要 struct 关键字
Point p = {10, 20};

6.3 访问结构体成员

typedef struct {
    int x;
    int y;
    int length;
    char direction;
} Snake;

Snake snake = {10, 10, 3, 'R'};

// 使用点运算符访问成员
printf("蛇的位置:(%d, %d)\n", snake.x, snake.y);
printf "蛇的长度:%d\n", snake.length);
printf "蛇的方向:%c\n", snake.direction);

// 修改成员
snake.x += 1;
snake.direction = 'D';

6.4 贪吃蛇中的结构体

点结构体

typedef struct {
    int x;
    int y;
} Point;

蛇结构体

typedef struct Snake {
    Point position;      // 位置
    int length;          // 长度
    int direction;       // 方向
    bool alive;          // 是否存活
} Snake;

食物结构体

typedef struct {
    Point position;      // 位置
    int value;           // 分数值
    bool active;         // 是否激活
} Food;

游戏结构体

typedef struct {
    Snake snake;         // 蛇
    Food food;           // 食物
    int score;           // 分数
    int level;           // 等级
    bool running;        // 游戏是否运行
} Game;

6.5 结构体数组

// 定义蛇身段
typedef struct {
    int x;
    int y;
} Segment;

// 创建蛇身数组
Segment body[100];  // 最多 100 段

// 初始化
body[0] = (Segment){10, 10};  // 头部
body[1] = (Segment){9, 10};   // 身体
body[2] = (Segment){8, 10};   // 尾部

// 访问
printf("头部位置:(%d, %d)\n", body[0].x, body[0].y);

6.6 结构体指针

当结构体很大时,传递指针更高效:

typedef struct {
    int x, y, length;
    // ... 很多成员
} Snake;

// 传递结构体(复制整个结构体)
void move_snake(Snake snake) {
    snake.x += 1;  // 只修改了副本
}

// 传递指针(修改原结构体)
void move_snake_ptr(Snake* snake) {
    snake->x += 1;  // 修改原结构体
}

// 使用
Snake s = {10, 10, 3};
move_snake_ptr(&s);  // 传递地址

-> 运算符

Snake* snake_ptr = &snake;

// 两种方式访问成员
snake_ptr->x = 10;   // 推荐,简洁
(*snake_ptr).x = 10; // 等价,但繁琐

6.7 嵌套结构体

结构体可以包含其他结构体:

typedef struct {
    int x;
    int y;
} Point;

typedef struct {
    Point position;    // 嵌套结构体
    Point velocity;
} GameObject;

// 使用
GameObject player;
player.position.x = 100;
player.position.y = 200;
player.velocity.x = 5;
player.velocity.y = 0;

6.8 完整示例:贪吃蛇数据结构

#include <stdio.h>
#include <stdbool.h>

// 方向枚举
typedef enum {
    DIR_UP,
    DIR_DOWN,
    DIR_LEFT,
    DIR_RIGHT
} Direction;

// 点结构体
typedef struct {
    int x;
    int y;
} Point;

// 蛇身段
typedef struct Segment {
    Point position;
    struct Segment* next;  // 指向下一段(链表)
} Segment;

// 蛇
typedef struct {
    Segment* head;      // 头部
    Segment* tail;      // 尾部
    int length;         // 长度
    Direction dir;      // 方向
} Snake;

// 食物
typedef struct {
    Point position;
    int value;
    bool active;
} Food;

// 游戏
typedef struct {
    Snake snake;
    Food food;
    int score;
    int high_score;
    int level;
    bool running;
    bool paused;
} Game;

// 创建新蛇
Snake* snake_create(int start_x, int start_y) {
    Snake* snake = malloc(sizeof(Snake));
    snake->head = malloc(sizeof(Segment));
    snake->head->position = (Point){start_x, start_y};
    snake->head->next = NULL;
    snake->tail = snake->head;
    snake->length = 1;
    snake->dir = DIR_RIGHT;
    return snake;
}

// 移动蛇
void snake_move(Snake* snake) {
    // 根据方向计算新位置
    Point new_head = snake->head->position;
    
    switch (snake->dir) {
        case DIR_UP:    new_head.y -= 1; break;
        case DIR_DOWN:  new_head.y += 1; break;
        case DIR_LEFT:  new_head.x -= 1; break;
        case DIR_RIGHT: new_head.x += 1; break;
    }
    
    // 创建新头部
    Segment* new_segment = malloc(sizeof(Segment));
    new_segment->position = new_head;
    new_segment->next = snake->head;
    snake->head = new_segment;
    snake->length++;
    
    // 移除尾部(除非在生长)
    // ...
}

int main(void) {
    // 创建游戏
    Game game = {0};
    game.snake = *snake_create(10, 10);
    game.score = 0;
    game.level = 1;
    game.running = true;
    
    printf("游戏初始化完成!\n");
    printf("蛇的初始位置:(%d, %d)\n", 
           game.snake.head.position.x, 
           game.snake.head.position.y);
    
    return 0;
}

✅ 本课检查清单


📝 作业

  1. 定义一个 Player 结构体,包含:
    • 名字(字符串)
    • 分数(整数)
    • 等级(整数)
    • 是否存活(布尔)
  2. 定义一个 Rectangle 结构体,包含两个 Point(左上角和右下角)

  3. 编写函数计算矩形的面积和周长

下一课:指针基础