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

C語言實戰:基於鏈表與文件操作的銷售管理系統

     編輯:關於C語言

C語言實戰:基於鏈表與文件操作的銷售管理系統

大二伊始,為鞏固大一 C 語言知識並預習 C++,我設計了一個「銷售管理系統」,綜合運用**結構體、指針、鏈表、文件讀寫、模塊化函數設計**,實現商品信息的增刪改查與持久化存儲。

系統架構

  • 數據結構:單向鏈表,頭結點存儲總商品數與總金額;
  • 持久化:Load_LinkList() 讀取二進制文件重建鏈表,Save_LinkList() 將鏈表寫入文件;
  • 內存操作:除讀寫文件外,所有增刷改查均在內存鏈表上完成,邏輯清晰;
  • 菜單驅動:while(1) + switch(getch()) 實現交互式控制台菜單。

核心數據結構

typedef struct Commodity {
    int id;              // 商品編號(頭結點用於統計總數)
    char name[20];       // 名稱
    double price;        // 單價
    int count;           // 數量
    double sum;          // 總價(price * count,頭結點存總金額)
    struct Commodity *next;
} *LinkList, LNode;

關鍵函數實現精要

1. 鏈表初始化與尾插法創建節點

void Creat_LinkList() {
    H = malloc(sizeof(LNode));
    H->next = NULL; H->data = 0;  // 頭結點
}

LinkList Add_LinkList(LinkList H) {
    LinkList q = H;
    while (q->next) q = q->next;      // 找到尾節點
    q->next = malloc(sizeof(LNode));  // 尾部直接申請內存
    q->next->next = NULL;
    q->next->sum = 0;
    H->data++;                        // 總數+1
    return q->next;                   // 返回新節點指針
}

採用**尾插法**而非教科書常見的頭插法,順序與輸入一致,更符合直覺。

2. 文件讀寫:二進制整體存取

void Load_LinkList(LinkList H) {
    LinkList tmp = malloc(sizeof(LNode));
    fp = fopen("D:/a.txt", "rb");
    while (fread(tmp, sizeof(LNode), 1, fp)) {
        LinkList p = Add_LinkList(H);
        p->data = tmp->data;
        strcpy(p->name, tmp->name);
        p->price = tmp->price;
        p->count = tmp->count;
        H->data++;
    }
    free(tmp); fclose(fp);
}

void Save_LinkList(LinkList H) {
    LinkList p = H->next;
    fp = fopen("D:/a.txt", "wb");
    if (!p) { H->data = 0; fclose(fp); return; } // 空鏈表清空文件
    while (p) {
        fwrite(p, sizeof(LNode), 1, fp);
        p = p->next;
    }
    fclose(fp);
}

利用 fread/fwrite 直接按結構體大小讀寫,**避免了格式化解析的麻煩**,但要求結構體不含指針成員(本項目滿足)。

3. 關鍵業務函數

函數功能核心邏輯
Find_LinkList_Val按名稱查找strcmp 遍歷匹配,未找到返回 NULL
Del_LinkList刪除節點雙指針 pre/p 定位前驅,斷鏈 free
Modify_LinkList修改信息查找後重新 Scanf_LinkList 覆蓋
Printf_LinkList表格輸出遍歷打印,累加頭結點 sum
Free_LinkList退出釋放遍歷 free 每個節點,防內存洩漏

主循環邏輯

int main() {
    system("color A"); Creat_LinkList(); Load_LinkList(H);
    while (1) {
        system("cls"); menu();
        switch (getch()) {
            case '1': Scanf_LinkList(Add_LinkList(H)); break;  // 添加
            case '2': printf_header(); Printf_LinkList(H); break; // 顯示
            case '3': /* 查找 */ break;
            case '4': /* 修改 */ break;
            case '5': /* 刪除 */ break;
            case '6': Save_LinkList(H); printf("保存成功!"); break;
            case '0': exit(0);
        }
        getch(); // 暫停查看結果
    }
}

心得與改進方向

  1. 鏈表尾插法 代碼簡潔,但頻繁遍歷到尾部 O(n);引入尾指針可優化至 O(1);
  2. 二進制文件存取 依賴結構體內存佈局,跨平台/跨編譯器不可移植;生產環境建議改用文本格式或序列化庫;
  3. 輸入驗證缺失:scanf 直接讀取易導致緩衝區殘留,建議改用 fgets+sscanf;
  4. 錯誤處理:文件操作、內存分配均需檢查返回值,當前代碼為教學演示省略部分檢查。

這個專案讓我真正體會到「數據結構是程序的骨架,文件操作是持久化的橋樑」。下一步將嘗試用 C++ 重構:引入 std::list、fstream、RAII 管理資源,體會面向對象與泛型編程的威力。

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