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

C語言結構體完全指南:從聲明到嵌套的系統性實戰

     編輯:C 語言入門

結構體:異構數據的有序容器

數組要求元素類型統一,而結構體(struct)打破此限制,允許將不同類型的數據(成員)組合成單一實體。結構體變量屬於標量,支持整體賦值、取址、函數傳遞等操作,是構建復雜數據模型的基石。

四種聲明方式的優劣權衡

1. 標準聲明 + 獨立定義

struct Date {
    int month;
    int day;
    int year;
};
struct Date d1, d2;  // 必須帶 struct 關鍵字

最通用,便於跨文件復用,推薦作為默認選擇。

2. 匿名結構體

struct {
    int month, day, year;
} d1, d2, *ptr;

無標籤名,無法在別處復用類型,適用於一次性、局部場景。注意:即使成員相同,兩個匿名結構體也被視為不同類型,變量間不可互賦。

3. 聲明同時定義

struct Date { int m, d, y; } d1, d2;

緊湊但降低可讀性,不推薦大型項目使用。

4. typedef 別名化(最佳實踐)

typedef struct Date {
    int month, day, year;
} Date;  // 新類型名

Date today = {8, 15, 2024};  // 直接使用 Date,無需 struct

配合匿名結構更簡潔:typedef struct { ... } Date;。這是現代C代碼的主流風格。

初始化:靈活多樣的賦值策略

  • 完全初始化:Date today = {8, 15, 2024}; 按聲明順序
  • 指定成員初始化(C99):Date today = {.month=8, .year=2024}; 未指定成員自動歸零
  • 複合字面量臨時賦值:today = (Date){9, 1, 2024};

局部結構體變量若不初始化,值不可預測,務必顯式賦值。

成員訪問:點運算符與箭頭運算符

結構體變量用 .,指針用 ->(p->member 等價於 (*p).member)。

Date today = {8, 15, 2024};
Date *p = &today;
printf("%d-%d-%d\n", today.month, p->day, today.year);

結構體運算:整體複製與傳遞

結構體支持整體賦值(逐成員淺拷貝)、取址(&)、作為函數參數/返回值。這與數組「退化為指針」形成鮮明對比,使結構體行為更像基本類型。

函數傳參:值傳遞 vs 指針傳遞

  • 值傳遞:函數內創建副本,修改不影響原值,適合小型結構體
  • 指針傳遞:傳遞地址,函數可修改原值,避免大結構體拷貝開銷,也是實現「輸出參數」的標準方式

輸入函數模式推薦:

// 模式1:返回結構體副本
Date getDate() {
    Date d; scanf("%d%d%d", &d.month, &d.day, &d.year); return d;
}

// 模式2:傳出參數指針(鏈式調用友好)
Date* getDatePtr(Date *p) {
    scanf("%d%d%d", &p->month, &p->day, &p->year); return p;
}
int main() { Date d; printDate(getDatePtr(&d)); }

進階佈局:嵌套結構與結構體數組

嵌套結構

typedef struct { int x, y; } Point;
typedef struct { Point p1, p2; } Rectangle;

Rectangle r = {{1,2}, {3,4}};
printf("%d %d\n", r.p1.x, r.p2.y);  // 多級點運算符訪問

若有指針 Rectangle *rp = &r;,則 rp->p1.x、(rp->p1).x 均合法,但 rp->p1->x 錯誤(p1 非指針)。

結構體數組

Date schedule[5] = {{1,1,2024}, {2,14,2024}, ...};
for (int i=0; i<5; i++) 
    printf("%.2d/%.2d/%d\n", schedule[i].month, schedule[i].day, schedule[i].year);

自引用結構:鏈表節點的基石

結構體不能直接包含自身類型成員(無限遞歸),但可包含指向自身類型的指針:

// 錯誤
struct Node { int data; struct Node next; };

// 正確:自引用指針
struct Node { int data; struct Node *next; };

// 配合 typedef 需前向聲明標籤
typedef struct Node {
    int data;
    struct Node *next;  // 必須用 struct Node,因為 Node 別名尚未生效
} Node;

這正是鏈表、樹等動態數據結構的核心定義模式。

作用域與存儲期:聲明位置決定可見性

結構體類型聲明若在函數內部,則僅該函數可見;通常應置於文件頂層或頭文件,供多模塊共享。結構體變量遵循標準塊作用域規則。

總結:結構體工程化檢查清單

  1. 優先使用 typedef struct Tag { ... } TypeName; 模式
  2. 初始化採用 C99 指定成員語法,避免順序依賴
  3. 大型結構體傳參必用指針,並加 const 保護只讀參數
  4. 嵌套結構體優先按值包含,指針僅用於遞歸/動態結構
  5. 自引用結構體必須使用指針成員,並正確處理前向聲明
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved