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

C語言結構體數組動態管理實戰:創建、輸入、排序、銷毀完整模型

     編輯:關於C語言

本文呈現一個工業級的 C 語言結構體數組管理完整模型,涵蓋動態分配、鍵盤輸入、按姓名排序、格式化輸出、內存銷毀全流程。代碼採用「雙指針傳遞所有權」模式,嚴格區分客戶端與服務端職責,可直接作為項目模板複用。

需求描述

  • 結構體 AdvTeacher:姓名、職稱、年齡、地址、學生列表(動態數組)。
  • 定義結構體數組(大小可配置),從鍵盤輸入數據。
  • 按姓名升序排序(strcmp)。
  • 格式化打印所有字段。
  • 完整釋放所有動態內存,無洩漏。

核心數據結構

#define TEACHER_COUNT 3
#define STUDENT_PER_TEACHER 1

typedef struct AdvTeacher {
    char *name;
    char *title;
    int   age;
    char *addr;
    char **student;  // 動態字符串數組
} AdvTeacher;

關鍵函數接口設計

函數職責參數約定
CreateStructArray分配結構體數組及所有成員內存AdvTeacher **out 雙指針輸出,返回錯誤碼
FreeStructArray遞歸釋放所有成員及數組本體AdvTeacher **inout 釋放後置 NULL
PrintStructArray格式化輸出只讀,不修改
SortStructArray冒泡排序 (教學用),實際建議 qsort原地排序,交換整個結構體

完整實現 (關鍵片段)

1. 創建與雙重指針所有權轉移

int CreateStructArray(AdvTeacher **t, int cnt, int stu_cnt) {
    if (!t) return -1;
    AdvTeacher *arr = malloc(cnt * sizeof(AdvTeacher));
    if (!arr) return -2;
    
    for (int i = 0; i < cnt; ++i) {
        arr[i].name  = malloc(256);
        arr[i].title = malloc(256);
        arr[i].addr  = malloc(256);
        if (!arr[i].name || !arr[i].title || !arr[i].addr) return -3;
        
        arr[i].student = malloc(stu_cnt * sizeof(char*));
        if (!arr[i].student) return -4;
        for (int j = 0; j < stu_cnt; ++j) {
            arr[i].student[j] = malloc(256);
            if (!arr[i].student[j]) return -5;
        }
    }
    *t = arr;  // 所有權轉移給調用者
    return 0;
}

2. 銷毀時的逆序釋放與 NULL 守衛

int FreeStructArray(AdvTeacher **t, int cnt, int stu_cnt) {
    if (!t || !*t) return 0;  // 幂等:重複調用安全
    AdvTeacher *arr = *t;
    
    for (int i = 0; i < cnt; ++i) {
        for (int j = 0; j < stu_cnt; ++j) {
            free(arr[i].student[j]);
            arr[i].student[j] = NULL;
        }
        free(arr[i].student); arr[i].student = NULL;
        free(arr[i].name);    arr[i].name = NULL;
        free(arr[i].title);   arr[i].title = NULL;
        free(arr[i].addr);    arr[i].addr = NULL;
    }
    free(arr);
    *t = NULL;  // 切斷調用者持有的指針
    return 0;
}

3. 排序:交換整個結構體而非逐字段拷貝

int SortStructArray(AdvTeacher *t, int cnt) {
    if (!t) return -1;
    for (int i = 0; i < cnt; ++i) {
        for (int j = i+1; j < cnt; ++j) {
            if (strcmp(t[i].name, t[j].name) > 0) {  // 升序
                AdvTeacher tmp = t[i];  // 結構體賦值 = 所有指針淺拷貝
                t[i] = t[j];
                t[j] = tmp;
            }
        }
    }
    return 0;
}

主函數業務流程

int main(void) {
    AdvTeacher *teachers = NULL;
    int rv = CreateStructArray(&teachers, TEACHER_COUNT, STUDENT_PER_TEACHER);
    if (rv) { fprintf(stderr, "Create failed: %d\n", rv); return rv; }
    
    // 輸入階段
    for (int i = 0; i < TEACHER_COUNT; ++i) {
        printf("第 %d 位老師姓名: ", i+1);  scanf("%255s", teachers[i].name);
        printf("第 %d 位老師年齡: ", i+1);  scanf("%d", &teachers[i].age);
        printf("第 %d 位老師職稱: ", i+1);  scanf("%255s", teachers[i].title);
        printf("第 %d 位老師地址: ", i+1);  scanf("%255s", teachers[i].addr);
        for (int j = 0; j < STUDENT_PER_TEACHER; ++j) {
            printf("  學生 %d 姓名: ", j+1); scanf("%255s", teachers[i].student[j]);
        }
    }
    
    PrintStructArray(teachers, TEACHER_COUNT, STUDENT_PER_TEACHER);
    SortStructArray(teachers, TEACHER_COUNT);
    puts("\n=== 排序後 ===\n");
    PrintStructArray(teachers, TEACHER_COUNT, STUDENT_PER_TEACHER);
    
    FreeStructArray(&teachers, TEACHER_COUNT, STUDENT_PER_TEACHER);
    return 0;
}

工程級優化建議

  1. 排序算法:數據量大時替換為 qsort + 比較函數,O(n log n)。
  2. 輸入安全:scanf("%255s", ...) 限制寬度防溢出;生產環境建議 fgets + 去換行。
  3. 錯誤碼域:定義枚舉 ERR_OK=0, ERR_NULL_PTR=-1, ERR_OOM=-2... 替代魔術數字。
  4. 泛化:用 void* + size_t + 操作函數指針 實現通用動態數組庫。
  5. 測試:Valgrind 驗證 --leak-check=full --show-leak-kinds=all 零洩漏。

這個模型展示了 C 語言手動內存管理的規範範式:誰分配誰釋放、雙指針傳遞所有權、釋放後置 NULL、錯誤路徑完整清理。掌握此模式,即掌握了 C 語言資源管理的精髓。

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