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

C語言從文件讀取數據構建鏈表完整實現:文件創建、寫入、讀取、打印全流程

     編輯:關於C語言

完整業務流程

  1. 文件不存在 → 自動創建
  2. 2. 交互式錄入學生信息 → 追加寫入文件 3. 程序啟動 → 讀取文件構建帶哨兵頭節點的單向鏈表 4. 遍歷鏈表打印顯示

數據結構

typedef struct Student {
    char id[12];
    char name[20];
    struct Student *next;
} Student;

1. 文件創建/打開

void ensure_file_exists() {
    FILE *fp = fopen("student.txt", "rb");
    if (!fp) {
        fp = fopen("student.txt", "wb+");
        if (!fp) { perror("創建文件失敗"); exit(1); }
    }
    fclose(fp);
}

2. 交互式錄入並寫入文件

void add_student() {
    FILE *fp = fopen("student.txt", "ab");  // 追加二進位
    if (!fp) { perror("打開文件失敗"); return; }

    Student stu;
    printf("輸入學號: "); scanf("%11s", stu.id);
    printf("輸入姓名: "); scanf("%19s", stu.name);
    stu.next = NULL;  // 文件中不存指針

    fwrite(&stu, sizeof(Student), 1, fp);
    fclose(fp);
    printf("錄入成功\n");
}

3. 讀取文件構建鏈表(關鍵:哨兵頭節點)

Student *build_list_from_file() {
    FILE *fp = fopen("student.txt", "rb");
    if (!fp) return NULL;

    Student *head = calloc(1, sizeof(Student));  // 哨兵頭節點,無數據
    Student *tail = head;
    Student tmp;

    // 逐個讀取結構體塊
    while (fread(&tmp, sizeof(Student), 1, fp) == 1) {
        Student *node = malloc(sizeof(Student));
        strcpy(node->id, tmp.id);
        strcpy(node->name, tmp.name);
        node->next = NULL;

        tail->next = node;  // 掛接到尾部
        tail = node;        // 移動尾指針
    }

    fclose(fp);
    return head;  // 返回哨兵頭
}

關鍵設計:哨兵頭節點

  • `head` 本身不存數據,`head->next` 指向第一個真實節點
  • 統一了「空表」與「非空表」的操作邏輯(無需特判 `head == NULL`)
  • 插入/刪除/遍歷代碼更簡潔健壯

4. 遍歷打印鏈表

void print_list(Student *head) {
    if (!head) { printf("鏈表為空\n"); return; }
    int count = 0;
    for (Student *p = head->next; p; p = p->next) {
        printf("%3d: [%s] %s\n", ++count, p->id, p->name);
    }
    printf("共 %d 條記錄\n", count);
}

5. 完整主程式演示

int main() {
    ensure_file_exists();

    int choice;
    while (1) {
        printf("\n1. 錄入學生\n2. 顯示所有\n0. 退出\n選擇: ");
        scanf("%d", &choice);
        if (choice == 1) add_student();
        else if (choice == 2) {
            Student *head = build_list_from_file();
            print_list(head);
            // 釋放鏈表
            Student *p = head;
            while (p) { Student *n = p->next; free(p); p = n; }
        }
        else if (choice == 0) break;
    }
    return 0;
}

文件格式與二進位讀寫注意事項

項目說明
模式`wb`/`ab`/`rb` 二進位模式,避免換行符轉換
結構體佈局同一編譯器/平台讀寫安全;跨平台需序列化
指針字段**不寫入文件** (`next` 僅內存有效),讀取時重建
字符串固定長度數組 `char id[12]` 直接寫入,含 `\0`
對齊填充結構體可能有填充位,整體 `fwrite` 保持一致

常見錯誤與修正

| 錯誤 | 現象 | 修正 | |------|------|------| | `fread` 判斷條件 `!= 0` | 讀到文件末尾返回 0,正常;但讀取錯誤也返回 0,無法區分 | 用 `== 1` 明確判斷成功讀取 1 項 | | 忘記 `calloc` 初始化頭節點 | `head->next` 野指針 | `calloc` 或手動 `head->next = NULL` | | 讀取後不釋放鏈表 | 記憶體洩漏 | 用完調用 `free_list(head)` | | `scanf` 緩衝區殘留換行符 | 後續 `fgets` 讀空行 | `scanf("%*c")` 清理或統一用 `fgets`+`sscanf` |

擴展:文本模式 (CSV) 版本

// 寫入
fprintf(fp, "%s,%s\n", stu.id, stu.name);

// 讀取
char line[64];
while (fgets(line, sizeof(line), fp)) {
    Student tmp;
    sscanf(line, "%11[^,],%19[^\n]", tmp.id, tmp.name);
    // ... 建節點掛接
}

優點:人類可讀、跨平台、可用 Excel 打開。缺點:解析較慢、需處理逗號轉義。

總結

「文件 ↔ 鏈表」是 C 語言經典持久化模式。核心模板:

// 讀取構建
head = calloc(1, sizeof(Node));
tail = head;
while (fread(&tmp, sizeof(Data), 1, fp) == 1) {
    node = malloc(sizeof(Node));
    copy_data(node, &tmp);
    tail->next = node;
    tail = node;
}

// 寫入同步
fp = fopen(file, "wb");
for (p = head->next; p; p = p->next) fwrite(p, sizeof(Data), 1, fp);

掌握哨兵頭節點、二進位塊讀寫、記憶體管理配對三要素,即可構建健壯的文件型鏈表應用。

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