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

C語言指針與結構體實戰:從文件解析到員工信息管理

     編輯:關於C語言

前言:指針與結構體——C語言的雙子星

指針是 C 語言的靈魂,也是初學者最大的攔路虎;結構體則讓我們能將異構數據聚合為邏輯實體。兩者結合,構成了系統級開發的基石。本文通過一個「員工信息文件解析」的完整案例,演示指針操作記憶體、結構體封裝數據、函數指針回調等核心技法。

一、 核心概念速覽

1. 指針:間接訪問的藝術

指針本質是存儲記憶體地址的變量。通過地址「間接訪問」數據,是實現動態內存管理、高效參數傳遞、鏈表樹圖等複雜數據結構的前提。

指針操作示意圖

圖1 指針間接訪問示意圖

2. 結構體:自定義數據類型

打破陣列「同類型」限制,將工號、姓名、年齡等不同類型字段封裝為一個邏輯整體 T_EmployeeInfo。

二、 程式流程與數據準備

程式 Pointer.c 讀取同目錄下的 EmployeeInfo.ini,每行格式為 工號|姓名|年齡,解析後輸出到控制台。

程序流程圖

圖2 程序流程圖

文件內容示例

圖3 文件內容存放示例

三、 核心代碼深度解析

1. 結構體定義與命名規範

typedef struct {
    UINT8 szEmployeeID[1024];   // 字串字段以 sz 開頭
    UINT8 szEmployeeName[1024];
    UINT32 iEmployeeAge;        // 整型字段以 i 開頭
} T_EmployeeInfo;

最佳實踐: 統一命名前綴(sz/i)提升可讀性;字串緩衝區大小設為 1024,配合 MAX_RET_BUF_LEN 防止溢出。

2. 通用字段提取函數 GetValueFromStr

這是本案例的精華:一個能根據分隔符、字段序號、目標類型,從源字串中提取並類型轉換的通用解析器。

BOOL GetValueFromStr(UINT16 iSerialNum, UINT8 iContentType,
                     UINT8 *pSourceStr, UINT8 *pDstStr,
                     UINT8 cIsolater, UINT32 iDstStrSize) {
    // 步驟1:指針防護
    if (pSourceStr == NULL) return FALSE;

    // 步驟2:定位字段首尾指針 (strchr 查找分隔符)
    UINT8 *pStrBegin = pSourceStr;
    while (--iSerialNum != 0) {
        pStrBegin = strchr(pStrBegin, cIsolater);
        if (!pStrBegin) return FALSE;
        pStrBegin++;
    }
    UINT8 *pStrEnd = strchr(pStrBegin, cIsolater);
    if (!pStrEnd) return FALSE;

    // 步驟3:長度保護與拷貝
    UINT32 iFieldLen = pStrEnd - pStrBegin;
    if (iFieldLen >= MAX_RET_BUF_LEN) iFieldLen = MAX_RET_BUF_LEN - 1;
    memcpy(szRetBuf, pStrBegin, iFieldLen);

    // 步驟4:根據類型轉換存儲 (switch + atoi)
    switch (iContentType) {
        case MML_STR_TYPE: strncpy(pDstStr, szRetBuf, iDstStrSize); break;
        case MML_INT32_TYPE: *(UINT32*)pDstStr = (UINT32)atoi(szRetBuf); break;
        // ... 其他類型
        default: return FALSE; // 必須有 default 防禦
    }
    return TRUE;
}

關鍵技術點:

  • 指針運算:pStrEnd - pStrBegin 直接得字段長度,零拷貝定位。
  • 類型擦除與還原:統一用 UINT8* 傳遞目標地址,內部根據 iContentType 強轉回 UINT32* 等寫入,實現泛型效果。
  • 異常保護:空指標檢查、長度截斷、default 分支,工業級代碼必備。

3. 主函數文件操作三部曲

FILE *hFile = fopen("EmployeeInfo.ini", "r");  // 只讀模式,防誤寫
while (fgets(szContentLine, sizeof(szContentLine), hFile)) {
    // 逐行解析,調用 GetValueFromStr 填充結構體
    // 注意:年齡為整型,傳址需 & 且強轉 (UINT8*)&t_EmployeeInfo.iEmployeeAge
}
fclose(hFile);  // 必須配對關閉,釋放資源

fgets 自動處理換行符與 EOF,是行讀取的首選。

4. 關鍵調用解析:年齡字段提取

GetValueFromStr(3, MML_INT32_TYPE, szContentLine,
                (UINT8 *)&(t_EmployeeInfo.iEmployeeAge), '|',
                sizeof(t_EmployeeInfo.iEmployeeAge))
  • 第3字段 → iSerialNum=3
  • 目標類型整型 → MML_INT32_TYPE
  • 源字串 → szContentLine (字串名即首地址)
  • 目標地址 → &iEmployeeAge 取址 + (UINT8*) 強轉匹配參數類型
  • 分隔符 → '|' (單引號字符,非雙引號字串)

四、 測試驗證:正常與異常雙軌制

1. 正常測試

按圖3準備文件,運行程式,正確輸出三位員工信息,驗證指針與結構體操作無誤。

正常測試輸出

圖4 正常測試輸出結果

2. 異常測試(工程師的分水嶺)

  • 文件缺失:fopen 失敗,輸出錯誤並退出。
  • 格式錯誤:第二行缺少 | 分隔符,strchr 返回 NULL,函數返回 FALSE,主流程捕獲並報錯。
  • 空文件:fgets 直接返回 NULL,循環不進入,程式靜默退出。

文件不存在

圖5 文件不存在時的輸出

分隔符缺失

圖6 分隔符缺失時的輸出

空文件

圖7 空文件時的輸出

五、 總結:從會用到用好

  1. 指針防護是紅線:任何指針使用前必判 NULL。
  2. 結構體封裝業務邏輯:數據與操作綁定,降低耦合。
  3. 通用解析器思想:GetValueFromStr 這類組件化設計,可復用於多種協議解析場景。
  4. 測試要想得美:正常案例只需幾個,異常案例要能舉一反三。

「冰凍三尺,非一日之寒」。指針與結構體的熟練,來自於無數次「Segmentation Fault」後的反思與重構。願此文為你的 C 語言進階之路添一磚加一瓦。

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