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

C 語言結構體完整指南:宣告、初始化、記憶體佈局與進階用法

     編輯:關於C語言

聚合資料類型:結構體的系統性掌握

C 語言提供兩種聚合類型:陣列 (同質元素集合) 與結構體 (異質成員集合)。結構體允許將不同型別的資料組織成邏輯整體,是建立複雜資料模型的基礎。

結構體宣告的三種形式

1. 直接宣告變數 (無標籤,單次使用)

struct {
    int a;
    char b;
    float c;
} x;  // 建立變數 x,型別匿名

2. 具名標籤 (可重複使用型別)

struct SIMPLE {
    int a;
    char b;
    float c;
};

struct SIMPLE x;           // 單一變數
struct SIMPLE y[20], *z;   // 陣列與指標

3. typedef 建立型別別名 (最推薦,語意清晰)

typedef struct {
    int a;
    char b;
    float c;
} Simple;

Simple x;
Simple y[20], *z;
> **跨檔案使用**:將 `typedef` 或 `struct TAG` 宣告放入標頭檔 (`.h`),其他來源檔 `#include` 即可共享型別定義。

成員存取:直接與間接


struct Node { int data; struct Node *next; } node, *ptr = &node;

// 直接存取 (.):物件本身
node.data = 10;
node.next = NULL;

// 間接存取 (->):透過指標
ptr->data = 20;      // 等同 (*ptr).data
ptr->next = &node;

自我引用與不完整宣告

合法:指標自我引用 (鏈表節點標準寫法)

struct SELF_REF {
    int a;
    struct SELF_REF *next;  // 指標大小固定,編譯器可計算結構大小
    int c;
};

非法:完整物件自我包含 (無限遞迴大小)

struct ILLEGAL {
    int a;
    struct ILLEGAL next;  // 錯誤:需要已知大小來計算大小
    int c;
};

typedef 陷阱與正確寫法

// 錯誤:型別名稱在宣告結束前不可見
typedef struct {
    int a;
    SELF_REF *next;  // 編譯錯誤:SELF_REF 尚未定義
    int c;
} SELF_REF;

// 正確:使用標籤前向宣告
typedef struct SELF_REF_TAG {
    int a;
    struct SELF_REF_TAG *next;
    int c;
} SELF_REF;

相互引用:不完整宣告解決循環依賴

struct B;  // 前向宣告 (不完整型別)

struct A {
    struct B *partner;  // 合法:指向不完整型別的指標
    // 其他成員...
};

struct B {
    struct A *partner;  // 此時 A 已完整定義
    // 其他成員...
};

結構體初始化

順序初始化 (C89 風格)

struct INIT_EX {
    int a;
    short b[10];
    Simple c;
} x = {
    10,
    {1, 2, 3, 4, 5},      // 陣列部分初始化,其餘為 0
    {25, 'x', 1.9}        // 巢狀結構初始化
};

指定成員初始化 (C99 指定初始化器,推薦)


struct Point { int x, y; };
struct Point p = { .y = 10, .x = 5 };  // 順序無關,可讀性高
struct Node n = { .data = 42, .next = NULL };

記憶體佈局與對齊


struct ALIGN_DEMO {
    char c;      // offset 0, size 1
    // 3 bytes padding
    int i;       // offset 4, size 4
    double d;    // offset 8, size 8 (8-byte aligned)
    // 總大小 24 bytes (通常)
};
  • 編譯器插入填充位元組以滿足成員對齊需求
  • `#pragma pack(n)` 可調整對齊界限 (如 `#pragma pack(1)` 封裝)
  • `offsetof(TYPE, MEMBER)` 取得成員偏移量 (需 ``)

結構體作為函數參數與傳回值


// 傳值:複製整個結構 (小型結構適用)
struct Point translate(struct Point p, int dx, int dy) {
    p.x += dx; p.y += dy;
    return p;
}

// 傳址:避免複製大型結構,允許修改原物件
void translate_inplace(struct Point *p, int dx, int dy) {
    p->x += dx; p->y += dy;
}

常見錯誤與最佳實務

錯誤模式正確做法原因
`struct Node n; n.next = &n;`動態配置 `malloc` 建立節點區域變數生命週期結束後指標失效
直接比較結構體 `a == b`逐成員比較或 `memcmp`C 不支援結構體直接比較 (含填充位元組不確定)
忽略對齊導致跨平台資料不相容使用固定寬度型別 + `#pragma pack` 或序列化庫不同編譯器/架構對齊規則不同
柔性陣列成員誤用C99: `struct { size_t len; char data[]; }` 末端唯一需配合 `malloc(sizeof(struct) + len)` 使用

結構體是 C 語言建立抽象資料類型的核心機制。掌握宣告語法、記憶體模型、初始化方式與跨模組使用規範,能讓你設計出清晰、高效且可維護的系統級程式碼。

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