Skip to content

struct basics.c

文件信息

  • 📄 原文件:01_struct_basics.c
  • 🔤 语言:c

完整代码

c
// ============================================================
//                      结构体、联合体与枚举
// ============================================================
// struct:将不同类型的数据组合成一个整体(类似其他语言的 class)
// union:多个成员共享同一内存空间
// enum:命名整数常量的集合
// typedef:为类型创建别名

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

// ============================================================
//                      结构体定义
// ============================================================

// ----------------------------------------------------------
// 1. 基本结构体
// ----------------------------------------------------------
// 【命名约定】结构体名通常首字母大写或全大写

struct Point {
    double x;
    double y;
};

// typedef 创建别名,使用更方便
typedef struct {
    int year;
    int month;
    int day;
} Date;

// 嵌套结构体
typedef struct {
    char  name[50];
    int   age;
    Date  birthday;         // 嵌套 Date
    char  email[100];
    double salary;
} Employee;

// ----------------------------------------------------------
// 2. 结构体操作函数
// ----------------------------------------------------------

// 创建 Point(返回结构体值)
struct Point make_point(double x, double y) {
    struct Point p = { x, y };
    return p;
}

// 传指针(高效,避免复制大结构体)
double distance(const struct Point *p1, const struct Point *p2) {
    double dx = p1->x - p2->x;
    double dy = p1->y - p2->y;
    return sqrt(dx*dx + dy*dy);
}

// 打印 Employee
void print_employee(const Employee *e) {
    printf("  姓名: %s\n", e->name);
    printf("  年龄: %d\n", e->age);
    printf("  生日: %04d-%02d-%02d\n", e->birthday.year,
           e->birthday.month, e->birthday.day);
    printf("  邮箱: %s\n", e->email);
    printf("  薪资: %.2f\n", e->salary);
}

// ----------------------------------------------------------
// 3. 链表节点(递归结构体)
// ----------------------------------------------------------
typedef struct Node {
    int data;
    struct Node *next;  // 指向同类型的指针(必须用 struct Node*)
} Node;

Node *create_node(int data) {
    Node *node = (Node*)malloc(sizeof(Node));
    if (node) {
        node->data = data;
        node->next = NULL;
    }
    return node;
}

void list_prepend(Node **head, int data) {
    Node *node = create_node(data);
    node->next = *head;
    *head = node;
}

void list_print(const Node *head) {
    printf("[");
    while (head) {
        printf("%d%s", head->data, head->next ? " -> " : "");
        head = head->next;
    }
    printf("]\n");
}

void list_free(Node *head) {
    while (head) {
        Node *tmp = head;
        head = head->next;
        free(tmp);
    }
}

// ----------------------------------------------------------
// 4. 联合体(Union)
// ----------------------------------------------------------
// 所有成员共享同一块内存,大小由最大成员决定
// 【用途】节省内存、类型双关(Type Punning)

typedef union {
    int   i;
    float f;
    char  bytes[4];
} FloatBits;

// 带标签的联合体(Tagged Union / Discriminated Union)
// 模拟多态
typedef enum { SHAPE_CIRCLE, SHAPE_RECT, SHAPE_TRIANGLE } ShapeType;

typedef struct {
    ShapeType type;
    union {
        struct { double radius; } circle;
        struct { double width, height; } rect;
        struct { double base, height; } triangle;
    };
} Shape;

double shape_area(const Shape *s) {
    switch (s->type) {
        case SHAPE_CIRCLE:
            return 3.14159 * s->circle.radius * s->circle.radius;
        case SHAPE_RECT:
            return s->rect.width * s->rect.height;
        case SHAPE_TRIANGLE:
            return 0.5 * s->triangle.base * s->triangle.height;
        default:
            return 0.0;
    }
}

const char *shape_name(ShapeType t) {
    switch (t) {
        case SHAPE_CIRCLE:   return "圆形";
        case SHAPE_RECT:     return "矩形";
        case SHAPE_TRIANGLE: return "三角形";
        default:             return "未知";
    }
}

// ============================================================
//                      主函数
// ============================================================
int main(void) {
    printf("=== 结构体基础 ===\n");

    // ----------------------------------------------------------
    // 结构体初始化
    // ----------------------------------------------------------
    // 按成员顺序初始化
    struct Point p1 = { 0.0, 0.0 };

    // 指定成员初始化(C99,推荐)
    struct Point p2 = { .x = 3.0, .y = 4.0 };

    printf("p1 = (%.1f, %.1f)\n", p1.x, p1.y);
    printf("p2 = (%.1f, %.1f)\n", p2.x, p2.y);
    printf("距离 = %.2f\n", distance(&p1, &p2));

    // 结构体赋值(值语义,完整复制)
    struct Point p3 = p2;
    p3.x = 10.0;
    printf("p2.x = %.1f(未改变)\n", p2.x);
    printf("p3.x = %.1f(独立副本)\n", p3.x);

    // ----------------------------------------------------------
    // Employee 结构体
    // ----------------------------------------------------------
    printf("\n=== Employee 结构体 ===\n");

    Employee emp = {
        .name     = "张三",
        .age      = 30,
        .birthday = { .year = 1994, .month = 6, .day = 15 },
        .email    = "zhangsan@company.com",
        .salary   = 15000.0
    };

    printf("员工信息:\n");
    print_employee(&emp);

    // 通过 -> 访问指针指向的结构体成员
    Employee *pe = &emp;
    pe->age = 31;
    pe->salary *= 1.1;  // 涨薪 10%
    printf("更新后年龄: %d,薪资: %.2f\n", pe->age, pe->salary);

    // ----------------------------------------------------------
    // 结构体数组
    // ----------------------------------------------------------
    printf("\n=== 结构体数组 ===\n");

    Employee team[] = {
        { "李四", 25, {1999, 3, 20}, "lisi@co.com", 10000.0 },
        { "王五", 28, {1996, 7, 10}, "wangwu@co.com", 12000.0 },
        { "赵六", 35, {1989, 1, 5}, "zhaoliu@co.com", 20000.0 },
    };
    int team_size = sizeof(team) / sizeof(team[0]);

    // 找最高薪资
    Employee *highest = &team[0];
    for (int i = 1; i < team_size; i++) {
        if (team[i].salary > highest->salary)
            highest = &team[i];
    }
    printf("最高薪资: %s (%.2f)\n", highest->name, highest->salary);

    // ----------------------------------------------------------
    // 链表
    // ----------------------------------------------------------
    printf("\n=== 链表 ===\n");

    Node *head = NULL;
    for (int i = 5; i >= 1; i--)
        list_prepend(&head, i);

    printf("链表: ");
    list_print(head);
    list_free(head);
    head = NULL;

    // ----------------------------------------------------------
    // 联合体
    // ----------------------------------------------------------
    printf("\n=== 联合体 ===\n");

    FloatBits fb;
    fb.f = 3.14f;
    printf("float  = %f\n", fb.f);
    printf("int    = %d(相同字节的不同解释)\n", fb.i);
    printf("bytes  = %02X %02X %02X %02X\n",
           (unsigned char)fb.bytes[0], (unsigned char)fb.bytes[1],
           (unsigned char)fb.bytes[2], (unsigned char)fb.bytes[3]);

    printf("sizeof(FloatBits) = %zu(共享内存)\n", sizeof(FloatBits));

    // ----------------------------------------------------------
    // 带标签的联合体(多态形状)
    // ----------------------------------------------------------
    printf("\n=== 多态形状(Tagged Union)===\n");

    Shape shapes[] = {
        { .type = SHAPE_CIRCLE,   .circle   = { .radius = 5.0 } },
        { .type = SHAPE_RECT,     .rect     = { .width = 4.0, .height = 6.0 } },
        { .type = SHAPE_TRIANGLE, .triangle = { .base = 3.0, .height = 8.0 } },
    };
    int n_shapes = sizeof(shapes) / sizeof(shapes[0]);

    for (int i = 0; i < n_shapes; i++) {
        printf("%s 面积 = %.2f\n", shape_name(shapes[i].type), shape_area(&shapes[i]));
    }

    // ----------------------------------------------------------
    // 内存对齐
    // ----------------------------------------------------------
    printf("\n=== 内存对齐 ===\n");

    // 编译器会添加填充字节(padding)以满足对齐要求
    struct Padded {
        char  a;    // 1 字节
        // 3 字节填充
        int   b;    // 4 字节
        char  c;    // 1 字节
        // 3 字节填充
    };
    struct Packed {
        int   b;    // 4 字节
        char  a;    // 1 字节
        char  c;    // 1 字节
        // 2 字节填充
    };

    printf("Padded  大小: %zu\n", sizeof(struct Padded));
    printf("Packed  大小: %zu\n", sizeof(struct Packed));
    printf("【技巧】按大小降序排列成员可减少填充\n");

    printf("\n=== 结构体演示完成 ===\n");
    return 0;
}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布