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

C與指針精讀第十章:結構體與聯合(下)習題解析——電話簿與銷售記錄建模

     編輯:關於C語言

C與指針精讀第十章:結構體與聯合(下)習題解析——電話簿與銷售記錄建模

《C和指針》第十章習題聚焦結構體嵌套、聯合類型節省空間、位域優化的實戰建模。本文詳細解析兩道核心習題:電話號碼結構體層次設計與銷售記錄多態數據建模,展示 C 語言無繼承機制下的組合復用藝術。

習題 1:電話簿結構體設計

需求分析

  • 電話號碼三段式:區號、交換台號、站號
  • 通話記錄:日期、時間、雙方號碼(主叫/被叫/使用者)

標準解法:組合嵌套

// 電話號碼三段式
typedef struct Phone {
    char *area_code;      // 區號
    char *exchange;       // 交換台號
    char *station;        // 站號
} Phone;

// 通話記錄
typedef struct Call {
    char *date;           // 日期
    char *time;           // 時間
    Phone *used;          // 使用者號碼
    Phone *self;          // 自機號碼
    Phone *called;        // 對方號碼
} Call;

設計要點

  1. 指針語義:char* 指向動態分配字符串,支持可變長度
  2. 所有權:Call 持有 Phone*,需明確誰負責 free
  3. 擴展性:新增字段(如國際碼)只需修改 Phone

習題 2:銷售記錄多態建模(聯合類型核心應用)

需求分析

銷售記錄包含公共字段(姓名、地址、型號)與互斥的交易細節:

  • 現金交易:零售價、實際價、稅、許可費
  • 貸款交易:上述 + 首付、期限、利率、月供、銀行名
  • 租賃交易:上述 + 首付、押金、月供、租期

標準解法:聯合 + 標籤字段

// 現金交易細節
typedef struct Cash {
    float retail_price;
    float actual_price;
    float sales_tax;
    float licensing_fee;
} Cash;

// 貸款交易細節
typedef struct Loan {
    float retail_price;
    float actual_price;
    float sales_tax;
    float licensing_fee;
    float down_payment;
    float loan_duration;
    float interest_rate;
    float monthly_payment;
    char *bank_name;  // 動態字符串
} Loan;

// 租賃交易細節
typedef struct Lease {
    float retail_price;
    float actual_price;
    float down_payment;
    float security_deposit;
    float monthly_payment;
    int lease_term;
} Lease;

// 銷售記錄:公共字段 + 聯合體
typedef struct Sale {
    char name[20];
    char address[40];
    char model[20];
    int type;  // 標籤:1=Cash, 2=Loan, 3=Lease
    union {
        Cash cash;
        Loan loan;
        Lease lease;
    } details;
} Sale;

聯合體核心機制

  • 空間共享:sizeof(Sale) = 公共字段 + max(sizeof(Cash), sizeof(Loan), sizeof(Lease))
  • 同一時刻僅一成員有效:由 type 標籤決定解析哪個成員
  • 對齊:聯合體大小按最大成員對齊,地址對齊滿足最嚴格成員

使用模式:類型安全訪問

void print_sale(const Sale *s) {
    printf("Customer: %s\nModel: %s\n", s->name, s->model);
    
    switch (s->type) {
        case 1:  // Cash
            printf("Cash Sale: $%.2f (tax $%.2f)\n", 
                   s->details.cash.actual_price, s->details.cash.sales_tax);
            break;
        case 2:  // Loan
            printf("Loan: $%.2f/mo for %.0f months @ %.2f%%\n",
                   s->details.loan.monthly_payment,
                   s->details.loan.loan_duration,
                   s->details.loan.interest_rate);
            break;
        case 3:  // Lease
            printf("Lease: $%.2f/mo for %d months\n",
                   s->details.lease.monthly_payment,
                   s->details.lease.lease_term);
            break;
        default:
            printf("Unknown sale type %d\n", s->type);
    }
}

進階優化:公共字段提取 + 匿名聯合 (C11)

// 提取公共交易字段
typedef struct CommonDeal {
    float retail_price;
    float actual_price;
    float sales_tax;
    float licensing_fee;
} CommonDeal;

typedef struct SaleV2 {
    char name[20];
    char address[40];
    char model[20];
    CommonDeal common;  // 所有類型共享
    int type;
    union {
        struct {  // Cash 無額外字段
        } cash;
        struct {  // Loan 額外字段
            float down_payment;
            float loan_duration;
            float interest_rate;
            float monthly_payment;
            char *bank_name;
        } loan;
        struct {  // Lease 額外字段
            float down_payment;
            float security_deposit;
            float monthly_payment;
            int lease_term;
        } lease;
    };
} SaleV2;

位域優化(補充)

// 壓縮標誌位
typedef struct Flags {
    unsigned int is_valid : 1;
    unsigned int is_paid  : 1;
    unsigned int is_shipped : 1;
    unsigned int reserved : 29;
} Flags;  // 僅佔 4 字節 vs 3×bool 可能 12 字節

常見錯誤避坑

錯誤後果修正
訪問非活躍聯合成員未定義行為(讀取垃圾值)嚴格按 type 標籤分支訪問
未初始化聯合成員內容不定賦值時完整賦值整個聯合或目標成員
指針成員淺拷貝雙重釋放/洩漏實現深拷貝函數或用引用計數
聯合體大小誤判緩衝區分配不足用 sizeof(UnionType) 而非手算

工程化建議:C 模擬多態模式

// 虛函數表模式
typedef struct SaleVTable {
    void (*print)(const void *self);
    void (*calculate_tax)(const void *self, float *tax);
    void (*destroy)(void *self);
} SaleVTable;

typedef struct SaleBase {
    const SaleVTable *vtable;
    // 公共字段...
} SaleBase;

// 各具體類型實現 vtable 並鑄造
void cash_print(const void *self) { ... }
const SaleVTable cash_vtable = {cash_print, cash_tax, cash_destroy};

// 使用
SaleBase *sale = create_cash_sale(...);
sale->vtable->print(sale);

結構體組合與聯合體互斥共享,構成了 C 語言「組合優於繼承」數據建模的雙支柱。電話簿展示「遞歸組合」建模層次結構;銷售記錄展示「標籤+聯合」實現類型安全的變體記錄。掌握這兩種模式,即可在無類、無繼承的 C 語言中構建任意複雜的領域模型。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved