首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言結構體與聯合體實戰大全:從基礎定義到複雜嵌套設計

     編輯:關於C

前言

結構體(struct)與聯合體(union)是 C 語言構建複雜數據模型的核心工具。本文通過 9 道遞進式例題,系統講解結構體定義、初始化、指針操作、函數封裝、數組管理、嵌套聯合體設計、動態輸入輸出及排序算法集成,幫助開發者建立完整的結構體編程思維。

例題 1:圖書信息結構體基礎操作

結構體定義與多種初始化方式


struct Books {
    char title[100];
    char author[20];
    double price;
};

// 1. 順序初始化
struct Books doyle = {"My life as a budgie", "Mack Tom", 14.6};

// 2. 變量定義時初始化
struct Books dicken = {"Thinking in C++", "Stephen Prata", 78};

// 3. C99 指定初始化器 (推薦,順序無關、可讀性強)
struct Books panshin = {
    .title = "C++ Primer",
    .author = "Stanley Lippman",
    .price = 92.5
};

結構體成員訪問與修改


printf("Title: %s\nAuthor: %s\nPrice: %.1f\n", 
       dicken.title, dicken.author, dicken.price);

// 修改價格
dicken.price = 85;

例題 2-4:模塊化設計——封裝顯示、初始化、輸入函數

設計原則:單一職責、指針傳遞、錯誤處理


#include 
#include 

struct Library {
    char title[50];
    char author[30];
    double price;
};

// 顯示函數:const 指針承諾不修改
void show(const struct Library *book) {
    printf("Title: %s\nAuthor: %s\nPrice: %.1f\n",
           book->title, book->author, book->price);
}

// 初始化函數:靜態默認值
void init(struct Library *book) {
    strcpy(book->title, "Unknown");
    strcpy(book->author, "Anonymous");
    book->price = 0.0;
}

// 輸入函數:返回狀態碼,處理輸入錯誤
int input(struct Library *book) {
    printf("Enter title: ");
    if (scanf("%49s", book->title) != 1) return 0;
    printf("Enter author: ");
    if (scanf("%29s", book->author) != 1) return 0;
    printf("Enter price: ");
    if (scanf("%lf", &book->price) != 1) return 0;
    return 1;
}

int main() {
    struct Library books[3];
    for (int i = 0; i < 3; i++) {
        init(&books[i]);
        if (!input(&books[i])) {
            fprintf(stderr, "Input error for book %d\n", i+1);
            return EXIT_FAILURE;
        }
    }
    for (int i = 0; i < 3; i++) show(&books[i]);
    return 0;
}

例題 5:結構體數組管理與排序

圖書館系統:動態數量、按出版日期排序


#include 
#include 
#include 

struct Date { int year, month, day; };

struct Book {
    char title[100];
    char author[50];
    struct Date pub_date;
    char publisher[100];
    int lent_count;
    int stock_count;
};

// 比較函數:按年月日升序
int cmp_books(const void *a, const void *b) {
    const struct Book *pa = a, *pb = b;
    if (pa->pub_date.year != pb->pub_date.year)
        return pa->pub_date.year - pb->pub_date.year;
    if (pa->pub_date.month != pb->pub_date.month)
        return pa->pub_date.month - pb->pub_date.month;
    return pa->pub_date.day - pb->pub_date.day;
}

int main() {
    int n;
    printf("Number of books: ");
    scanf("%d", &n);
    
    struct Book *books = malloc(n * sizeof(struct Book));
    if (!books) { perror("malloc"); return 1; }

    for (int i = 0; i < n; i++) {
        printf("Book %d:\n", i+1);
        scanf("%99s %49s %d %d %d %99s %d %d",
              books[i].title, books[i].author,
              &books[i].pub_date.year, &books[i].pub_date.month, &books[i].pub_date.day,
              books[i].publisher,
              &books[i].lent_count, &books[i].stock_count);
    }

    qsort(books, n, sizeof(struct Book), cmp_books);

    for (int i = 0; i < n; i++) {
        printf("%s | %s | %04d-%02d-%02d | %s | Lent:%d | Stock:%d\n",
               books[i].title, books[i].author,
               books[i].pub_date.year, books[i].pub_date.month, books[i].pub_date.day,
               books[i].publisher, books[i].lent_count, books[i].stock_count);
    }
    free(books);
    return 0;
}

例題 6-7:學生信息系統——結構體指針函數族

同例題 2-4 模式,定義 Student 結構,實現 show()、init()、input(),主函數驅動流程。關鍵點:

  • 使用 const struct Student* 保護只讀操作。
  • 輸入函數檢查 scanf 返回值,防止格式錯誤導致數據破損。
  • 字符數組輸入限制寬度(%19s)防止緩衝區溢出。

例題 8:聯合體實現多態數據存儲

汽車信息:私有/租賃兩種模式互斥


struct Owner {
    char name[50];
    char gender; // 'M'/'F'
    char buy_date[20];
};

struct Company {
    char name[50];
    char phone[20];
};

union OwnerInfo {
    struct Owner owner;
    struct Company company;
};

struct CarData {
    char make[30];
    int status; // 0=私有, 1=租賃
    union OwnerInfo info;
};

// 使用示例
struct CarData mycar = {
    .make = "Volvo",
    .status = 0,
    .info.owner = {"Robert Carter", 'M', "2008-11-21"}
};

// 訪問:必須先檢查 status
if (mycar.status == 0) {
    printf("Owner: %s\n", mycar.info.owner.name);
}

例題 9:聯合體實現簡易計算器(教學演示)

注意:此例僅演示聯合體語法,實際計算器不應使用聯合體(數值並非互斥)。


union Calc {
    int a, b;
} reg;

int add(int a, int b) {
    reg.a = a; reg.b = b;
    return reg.a + reg.b; // 等價於 a + b
}
// sub, mul, div 同理

正確設計應直接使用參數運算,聯合體適用於「同一時刻僅一種數據有效」的場景(如協議解析、異構數據存儲)。

最佳實踐總結

  1. 優先使用指定初始化器(C99),增強可讀性與維護性。
  2. 函數傳遞結構體指針,避免大結構體值拷貝開銷;只讀操作加 const。
  3. 封裝操作函數(init/input/show),實現數據與行為的邏輯聚合。
  4. 動態分配結構體數組處理不定數量數據,配合 qsort 實現高效排序。
  5. 聯合體用於互斥字段,配合標籤字段(status/type)區分活動成員,實現類多態。
  6. 輸入邊界檢查:scanf("%49s", buf)、檢查返回值、清理輸入緩衝區。
  7. 內存對齊意識:合理排列成員順序(大類型優先)減少填充,必要時用 #pragma pack。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved