(C語言)超市管理系統 (正式版)(指針)(數據結構)(清屏操作)(文件讀寫)

目錄

前言:

源代碼:

product.h

?product.c

?fileio.h

?fileio.c

?main.c

代碼解析:

一、程序結構概述

二、product.c 函數詳解

1. 初始化商品列表?Init_products

2. 添加商品?add_product

3. 顯示商品?display_products

4. 修改商品?mod_product

5.刪除函數?del_product

6.查詢函數?que_product

三、main.c 主函數詳解

1. 主函數?main

2. 輔助函數?clear_screen

四、fileio.c 文件詳解

1. 保存數據到文件?save_to_file

2. 加載數據?load_from_file

3. main.c 主函數協同工作

4.聯合調試示例

五、核心知識點總結

1. 動態內存管理

2. 結構體的使用

3. 輸入輸出安全

4. 文件操作

相關運行截圖:


前言:

當前這篇博客是測試版,教大家相關添加單個商品,顯示所有商品,修改單個商品知識點;

看之前建議先看上篇博客:

(C語言)超市管理系統(測試版)(指針)(數據結構)(二進制文件讀寫)-CSDN博客

共6個文件(加上二進制文件);

源代碼:

product.h

//product.h
#pragma once //防止頭文件重復定義#define NAME_LEN 50 //商品名稱最大容量//單個商品結構體
typedef struct {int id;//商品編號char name[NAME_LEN];//商品名字float price;//商品單價int stock;//商品庫存
}Product;//商品列表表結構體
typedef struct {Product* Data;//指向單個商品數組的指針int count;//當前商品數量
}ProductList;// 函數原型
void Init_products(ProductList* list);//初始化商品列表結構體
void add_product(ProductList* list,Product* product);//添加單個商品
void display_products(ProductList* list);//顯示所有商品
void mod_product(ProductList* list, Product* product);//修改單個商品

?product.c

//product.c
#include "product.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//初始化商品列表結構體
void Init_products(ProductList* list) {list->Data = NULL;//指針置空,防止野指針list->count = 0;//商品數量歸0
}//添加單個商品
void add_product(ProductList* list,Product* product) {//1.擴展空間Product* listnew_Data = realloc(list->Data, (list->count + 1) * sizeof(Product));if (listnew_Data==NULL) {printf("內存分配失敗!\n");exit(EXIT_FAILURE);}list->count++;list->Data = listnew_Data;//依然用老數組表示描述//2.ID自動生成list->Data[list->count - 1].id = list->count;printf("商品ID:%d\n",list->count);//3.商品信息錄入printf("請輸入商品名稱:");scanf("%49s", list->Data[list->count-1].name);printf("請輸入單價:");scanf("%f", &list->Data[list->count-1].price);printf("請輸入庫存:");scanf("%d", &list->Data[list->count-1].stock);printf("添加成功!\n");
}//顯示所有商品
void display_products(ProductList* list) {//1.判斷列表是否為空if (list->count == 0) {printf("庫存為空\n");return;}//2.打印表頭printf("\n%5s %-20s %10s %6s\n", "ID", "名稱", "單價", "庫存");printf("--------------------------------------------\n");//3.打印商品信息for (int i = 0; i < list->count; i++) {printf("%5d %-20s %10.2f %5d\n",list->Data[i].id,list->Data[i].name,list->Data[i].price,list->Data[i].stock);}
}//修改單個商品
void mod_product(ProductList* list, Product* product) {//1.判斷列表是否為空if (list->count == 0) {printf("庫存為空\n");return;}//2.輸入要修改的IDint id_0;printf("請輸入要修改的ID:");scanf("%d", &id_0);//3.判斷ID是否存在if (id_0 > list->count) {printf("ID不存在!\n");return;}//4.找要修改商品的IDint i=0;for (i; i < list->count; i++) {if (id_0 == list->Data[i].id) {break;}}//5.修改商品printf("\n%5s %-20s %10s %6s\n", "ID", "名稱", "單價", "庫存");printf("--------------------------------------------\n");printf("%5d %-20s %10.2f %5d\n",list->Data[i].id,list->Data[i].name,list->Data[i].price,list->Data[i].stock);printf("--------------------------------------------\n");printf("修改商品名稱:");scanf("%49s", list->Data[i].name);printf("修改單價:");scanf("%f", &list->Data[i].price);printf("修改庫存:");scanf("%d", &list->Data[i].stock);printf("修改成功!\n");
}

?fileio.h

//fileio.h
#pragma once
#include "product.h"// 文件操作函數原型
void save_to_file(const char* filename, const ProductList* list);
void load_from_file(const char* filename, ProductList* list);

?fileio.c

//fileio.c
//引用頭文件
#include <stdio.h>
#include <stdlib.h>
#include "product.h"// 保存數據到文件(二進制寫入)
void save_to_file(const char* filename, const ProductList* list) {//1.打開文件(二進制寫入模式)FILE* fp = fopen(filename, "wb");// "wb":二進制寫入模式,會清空原文件內容// 若文件不存在則創建新文件if (!fp) { // fp == NULL 表示打開失敗perror("保存失敗"); // 輸出錯誤信息(包含具體原因,如權限不足)exit(EXIT_FAILURE); // 終止程序,EXIT_FAILURE 表示異常退出}//2.先寫入商品數量(int 類型)fwrite(&list->count,sizeof(int),1,fp);// &list->count:取商品數量的內存地址// sizeof(int):每個元素的大小(4字節)// 1:寫入1個元素// fp:文件指針//3.再寫入所有商品數據(Product 結構體數組)fwrite(list->Data, sizeof(Product), list->count, fp);// list->Data:商品數組首地址// sizeof(Product):每個商品占用的字節數// list->count:要寫入的商品數量//4.關閉文件fclose(fp);
}// 從文件加載數據(二進制讀取)
void load_from_file(const char* filename, ProductList* list) {//1.初始化結構體(防御性編程)Init_products(&list);//初始化商品列表結構體//2.嘗試打開文件(二進制讀取模式)FILE* fp = fopen(filename, "rb");// "rb":二進制讀取模式,文件不存在時返回 NULLif (!fp) {//文件打開失敗處理return; // 保持 list 的初始狀態(count=0, Data=NULL)}//3.讀取商品數量(int 類型)fread(&list->count,sizeof(int),1,fp);// 從文件中讀取4字節到 list->count//4.根據數量分配內存list->Data = malloc(list->count * sizeof(Product));// 計算總字節數 = 商品數量 × 單個商品大小//檢查是否分配成功if (list->Data == NULL) { // list->Data == NULL 表示失敗printf("內存分配失敗\n");exit(EXIT_FAILURE); // 終止程序}//5.讀取所有商品數據fread(list->Data, sizeof(Product), list->count, fp);// 將文件內容直接讀入 Data 數組//6.關閉文件fclose(fp);
}

?main.c

//mian.c#include <stdio.h>
#include <stdlib.h>
#include "product.h"
#include "fileio.h"#define FILENAME "products.dat"//宏定義文件名//清屏操作
void clear_screen() {//判斷是否為Windows系統
#ifdef _WIN32system("cls");//其他系統
#elsesystem("clear");
#endif
}// 顯示主菜單(用戶界面)
void display_menu() {printf("\n超市管理系統\n");printf("1. 添加商品\n");printf("2. 顯示所有商品\n");printf("3. 修改商品信息\n");printf("4. 刪除商品\n");printf("5. 搜索商品\n");printf("6. 保存并退出\n");printf("請選擇操作:");
}int main() {//1.創建結構體并初始化Product product;//創建單個商品結構體ProductList list;//創建商品列表結構體Init_products(&list);//初始化//2.讀文件load_from_file(FILENAME, &list);//讀文件//3.選擇模塊int choice;//選擇選項while (1) {display_menu();//顯示菜單scanf("%d", &choice);//輸入選項switch (choice) {case 1:clear_screen();add_product(&list,&product);printf("--------------------------------------------\n");break;case 2:clear_screen();display_products(&list);printf("--------------------------------------------\n");break;case 3:clear_screen();mod_product(&list,&product);printf("--------------------------------------------\n");break;case 6:save_to_file(FILENAME, &list); // 保存數據free(list.Data); // 釋放動態內存printf("系統已退出\n");return 0; // 正確退出default:printf("無效輸入\n");}}
}

代碼解析:

一、程序結構概述

整個程序分為三個核心模塊:

  1. 數據管理模塊?(product.c):處理商品的增刪改查

  2. 文件操作模塊?(fileio.c):負責數據保存與加載

  3. 主控模塊?(main.c):協調程序流程和用戶交互


二、product.c 函數詳解


1. 初始化商品列表?Init_products
void Init_products(ProductList* list) {list->Data = NULL;  // 指針置空,防止野指針list->count = 0;    // 商品數量歸0
}

功能

  • 初始化商品列表結構體,確保程序啟動時處于干凈狀態。

實現步驟

  1. Data = NULL:將動態數組指針置空,避免指向隨機內存。

  2. count = 0:商品數量初始化為0。

為什么這樣寫

  • 防御性編程:確保程序啟動時沒有殘留數據。

  • 動態內存安全Data?初始為?NULLrealloc?在首次調用時會自動分配內存。

如何使用

ProductList list;      // 聲明一個商品列表
Init_products(&list);  // 初始化列表(必須調用)

2. 添加商品?add_product
void add_product(ProductList* list, Product* product) {// 1. 擴展內存Product* listnew_Data = realloc(list->Data, (list->count + 1) * sizeof(Product));if (listnew_Data == NULL) {printf("內存分配失敗!\n");exit(EXIT_FAILURE);}list->count++;list->Data = listnew_Data;// 2. 自動生成IDlist->Data[list->count - 1].id = list->count;printf("商品ID:%d\n", list->count);// 3. 錄入商品信息printf("請輸入商品名稱:");scanf("%49s", list->Data[list->count-1].name);printf("請輸入單價:");scanf("%f", &list->Data[list->count-1].price);printf("請輸入庫存:");scanf("%d", &list->Data[list->count-1].stock);printf("添加成功!\n");
}

功能

  • 動態擴展內存,添加新商品并自動生成ID。

實現步驟

  1. 內存擴展:使用?realloc?將數組大小增加1個商品位置。

  2. 錯誤處理:檢查內存是否分配成功,失敗則終止程序。

  3. 生成ID:新商品ID = 當前商品總數 + 1(例如第一個商品ID=1)。

  4. 輸入信息:依次輸入名稱、單價、庫存。

為什么這樣寫

  • 動態內存管理realloc?自動處理內存擴展,無需手動復制數據。

  • 簡單ID生成:直接使用?count?作為ID,但存在刪除商品后ID不連續的問題(后續改進點)。

如何使用

ProductList list;
Init_products(&list);
add_product(&list, NULL);  // 添加第一個商品

輸入示例

請輸入商品名稱:蘋果
請輸入單價:5.5
請輸入庫存:20

注意事項

  • 輸入緩沖區問題:連續使用?scanf?可能導致殘留換行符,需清空緩沖區(代碼未處理)。

  • 名稱輸入限制%49s?防止溢出,但無法輸入帶空格的名稱(如“紅富士蘋果”)。


3. 顯示商品?display_products
void display_products(ProductList* list) {if (list->count == 0) {printf("庫存為空\n");return;}printf("\n%5s %-20s %10s %6s\n", "ID", "名稱", "單價", "庫存");printf("--------------------------------------------\n");for (int i = 0; i < list->count; i++) {printf("%5d %-20s %10.2f %5d\n",list->Data[i].id,list->Data[i].name,list->Data[i].price,list->Data[i].stock);}
}

功能

  • 以表格形式打印所有商品信息,處理空列表情況。

實現步驟

  1. 空列表檢查:直接返回提示信息。

  2. 打印表頭:使用格式化字符串對齊標題。

  3. 遍歷打印:循環輸出每個商品的字段。

為什么這樣寫

  • 用戶體驗:清晰的表格布局提升可讀性。

  • 格式控制符

    • %5d:ID占5字符寬度,右對齊。

    • %-20s:名稱左對齊,占20字符。

    • %10.2f:單價保留兩位小數,總寬度10。

如何使用

display_products(&list);  // 顯示當前所有商品

輸出示例

   ID 名稱                 單價    庫存
--------------------------------------------1 蘋果               5.50    202 香蕉               3.80    15

4. 修改商品?mod_product
void mod_product(ProductList* list, Product* product) {if (list->count == 0) {printf("庫存為空\n");return;}int id_0;printf("請輸入要修改的ID:");scanf("%d", &id_0);if (id_0 > list->count) {printf("ID不存在!\n");return;}int i=0;for (i; i < list->count; i++) {if (id_0 == list->Data[i].id) {break;}}// 顯示原信息并修改printf("\n%5s %-20s %10s %6s\n", "ID", "名稱", "單價", "庫存");printf("--------------------------------------------\n");printf("%5d %-20s %10.2f %5d\n",list->Data[i].id,list->Data[i].name,list->Data[i].price,list->Data[i].stock);printf("--------------------------------------------\n");printf("修改商品名稱:");scanf("%49s", list->Data[i].name);printf("修改單價:");scanf("%f", &list->Data[i].price);printf("修改庫存:");scanf("%d", &list->Data[i].stock);printf("修改成功!\n");
}

功能

  • 根據用戶輸入的ID查找商品,修改其信息。

實現步驟

  1. 空列表檢查:直接返回提示。

  2. 輸入目標ID:用戶指定要修改的商品。

  3. ID存在性檢查:錯誤判斷邏輯不嚴謹(id_0 > count?可能漏判)。

  4. 遍歷查找:找到對應商品的數組索引。

  5. 顯示并修改:打印原信息,逐項修改。

為什么這樣寫

  • 直觀交互:先展示原信息再修改,減少誤操作。

  • 直接修改內存:通過指針直接修改數組元素。

如何使用

mod_product(&list, NULL);  // 修改ID為2的商品

輸入示例

請輸入要修改的ID:2
...(顯示原信息)...
修改商品名稱:香蕉
修改單價:4.5
修改庫存:25

5.刪除函數?del_product
//刪除單個商品
void del_product(ProductList* list) {//1.顯示所有商品display_products(list);printf("--------------------------------------------\n");//2.輸入要刪除的IDint id_0;printf("請輸入要刪除的ID:");scanf("%d", &id_0);//3.判斷ID是否存在if (id_0 > list->count) {printf("ID不存在!\n");return;}//4.找要刪除商品的IDint i = 0;for (i; i < list->count; i++) {//此時的i+1就是當前商品IDif (id_0 == list->Data[i].id) {break;}}//5.刪除商品for (int j = i; j < list->count - 1; j++) {list->Data[j] = list->Data[j + 1];}printf("刪除成功!\n");list->count--;//商品數量減一//6.重新生成商品IDif (list->count == 1) {list->Data[0].id = 1;}else{list->Data[list->count - 1].id = list->Data[list->count - 2].id + 1;}
}

功能

根據用戶輸入的ID刪除指定商品,并調整商品列表以保持數據連續性,最后重新生成所有商品的ID以確保ID連續。


實現步驟

  1. 顯示所有商品

    • 調用?display_products?顯示當前所有商品信息,供用戶參考。

  2. 輸入要刪除的ID

    • 用戶輸入目標商品的ID。

  3. 判斷ID是否存在

    • 檢查輸入的ID是否超過當前商品總數(id_0 > list->count),若超過則提示不存在。

  4. 查找目標商品的索引

    • 遍歷商品列表,找到與輸入ID匹配的商品索引?i

  5. 刪除商品并調整數組

    • 將索引?i?之后的商品依次前移一位,覆蓋目標商品。

  6. 更新商品數量

    • 減少?list->count?以反映刪除后的商品總數。

  7. 重新生成所有商品的ID

    • 若刪除后僅剩一個商品,將其ID設為1;否則,將最后一個商品的ID設為前一個ID加1。


為什么這樣寫

  • 顯示商品列表:幫助用戶確認要刪除的商品ID。

  • 簡單ID存在性檢查:假設商品ID是連續遞增的(ID = 1, 2, 3...),通過比較輸入ID與?list->count?快速判斷是否存在。

  • 數組前移覆蓋:通過循環將后續元素前移,邏輯簡單但效率較低(時間復雜度為O(n))。

  • 強制ID連續:刪除后重新生成所有ID,確保ID連續,避免出現空缺(如刪除ID=2后,原ID=3變為ID=2)。


如何使用

del_product(&list);  // 刪除ID為2的商品

輸入示例

(顯示所有商品)
--------------------------------------------
請輸入要刪除的ID:2
刪除成功!

6.查詢函數?que_product
//查詢單個商品
void que_product(ProductList* list) {//1.判斷列表是否為空if (list->count == 0) {printf("庫存為空\n");return;}//2.輸入要搜索的IDint id_0;printf("請輸入要搜索的ID:");scanf("%d", &id_0);//3.判斷ID是否存在if (id_0 > list->count) {printf("ID不存在!\n");return;}//4.找要搜索商品的IDint i = 0;for (i; i < list->count; i++) {if (id_0 == list->Data[i].id) {//此時的i+1就是當前商品IDbreak;}}//5.顯示商品printf("搜索成功!\n");printf("\n%5s %-20s %10s %6s\n", "ID", "名稱", "單價", "庫存");printf("--------------------------------------------\n");printf("%5d %-20s %10.2f %5d\n",list->Data[i].id,list->Data[i].name,list->Data[i].price,list->Data[i].stock);
}

功能

根據用戶輸入的ID查找并顯示指定商品的詳細信息。


實現步驟

  1. 判斷列表是否為空

    • 若商品數量為0,直接提示庫存為空。

  2. 輸入要查詢的ID

    • 用戶輸入目標商品的ID。

  3. 判斷ID是否存在

    • 檢查輸入的ID是否超過當前商品總數(id_0 > list->count),若超過則提示不存在。

  4. 查找目標商品的索引

    • 遍歷商品列表,找到與輸入ID匹配的商品索引?i

  5. 顯示商品信息

    • 以表格形式輸出該商品的ID、名稱、單價和庫存。


為什么這樣寫

  • 快速存在性檢查:假設ID連續,通過比較輸入ID與?list->count?快速過濾無效ID。

  • 直接遍歷查找:線性搜索整個數組,邏輯簡單但效率較低(時間復雜度為O(n))。

  • 格式化輸出:保持與?display_products?一致的表格布局,提升用戶體驗。


如何使用

que_product(&list);  // 查詢ID為3的商品

輸入示例

請輸入要搜索的ID:3
搜索成功!ID 名稱                 單價    庫存
--------------------------------------------3 面包               5.50    30

三、main.c 主函數詳解


1. 主函數?main
int main() {Product product;     // 單個商品(未實際使用)ProductList list;    // 商品列表Init_products(&list); // 初始化列表load_from_file(FILENAME, &list); // 加載數據int choice;while (1) {display_menu();  // 顯示菜單scanf("%d", &choice);switch (choice) {case 1: add_product(&list, &product); break;case 2: display_products(&list); break;case 3: mod_product(&list, &product); break;case 6: save_to_file(FILENAME, &list); // 保存數據free(list.Data); // 釋放內存printf("系統已退出\n");return 0;default: printf("無效輸入\n");}}
}

功能

  • 程序入口,管理整個生命周期:初始化→加載數據→循環處理用戶操作→退出保存。

實現步驟

  1. 初始化:創建商品列表并初始化。

  2. 加載數據:從文件讀取歷史數據。

  3. 主循環

    • 顯示菜單,獲取用戶選擇。

    • 調用對應功能函數。

  4. 退出處理:保存數據并釋放內存。

關鍵設計

  • 循環結構while(1)?保持程序持續運行。

  • 內存釋放:退出前必須?free(list.Data),否則內存泄漏。

  • 模塊化調用:通過?switch-case?調用各功能函數。

用戶交互流程

graph TD
A[啟動程序] --> B[加載數據]
B --> C{顯示菜單}
C --> D[用戶選擇]
D -->|1-5| E[執行操作]
E --> C
D -->|6| F[保存并退出]

2. 輔助函數?clear_screen
void clear_screen() {
#ifdef _WIN32system("cls");   // Windows清屏
#elsesystem("clear"); // Linux/Mac清屏
#endif
}

功能

  • 清空控制臺屏幕,提升界面整潔度。

為什么這樣寫

  • 跨平臺兼容:通過預編譯指令區分系統。

  • 簡單調用system?函數直接執行系統命令。

如何使用

clear_screen();  // 清空屏幕后顯示新內容

四、fileio.c 文件詳解


1. 保存數據到文件?save_to_file
void save_to_file(const char* filename, const ProductList* list) {// 1. 打開文件(二進制寫入模式)FILE* fp = fopen(filename, "wb");if (!fp) {perror("保存失敗");exit(EXIT_FAILURE);}// 2. 寫入商品數量fwrite(&list->count, sizeof(int), 1, fp);// 3. 寫入所有商品數據fwrite(list->Data, sizeof(Product), list->count, fp);// 4. 關閉文件fclose(fp);
}

功能
將商品列表數據保存到二進制文件中,確保程序退出后數據不丟失。

逐行解析

  1. 打開文件

    • "wb":二進制寫入模式,清空原文件內容。若文件不存在則新建。

    • fopen?失敗時,perror?輸出具體錯誤(如權限不足),exit?終止程序。

  2. 寫入商品數量

    • fwrite(&list->count, ...):將商品數量(int?類型)寫入文件開頭。

    • 作用:后續讀取時,根據此值分配內存。

  3. 寫入商品數組

    • fwrite(list->Data, ...):將整個商品數組寫入文件。

    • 二進制優勢:直接寫入內存數據,無需格式轉換,高效且保留浮點精度。

  4. 關閉文件

    • fclose:確保數據從緩沖區寫入磁盤。

關鍵知識點

  • 二進制文件格式
    文件內容為原始內存數據,不可直接閱讀,但讀寫速度快。

  • 數據持久化:程序退出后,數據通過文件保存,下次啟動可恢復。

使用示例

ProductList list;
// ...添加商品...
save_to_file("data.dat", &list); // 保存數據

注意事項

  • 跨平臺問題:不同系統可能結構體內存對齊不同,導致文件不兼容。

  • 文件損壞風險:若寫入過程被中斷(如程序崩潰),文件可能損壞。


2. 加載數據?load_from_file
void load_from_file(const char* filename, ProductList* list) {// 1. 初始化結構體Init_products(list);// 2. 打開文件(二進制讀取模式)FILE* fp = fopen(filename, "rb");if (!fp) return;// 3. 讀取商品數量fread(&list->count, sizeof(int), 1, fp);// 4. 分配內存list->Data = malloc(list->count * sizeof(Product));if (!list->Data) {printf("內存分配失敗\n");exit(EXIT_FAILURE);}// 5. 讀取商品數據fread(list->Data, sizeof(Product), list->count, fp);// 6. 關閉文件fclose(fp);
}

功能
從二進制文件加載商品數據到內存,恢復程序上次運行狀態。

逐行解析

  1. 初始化列表
    Init_products?清空現有數據,防止殘留值干擾。

  2. 打開文件
    "rb":二進制讀取模式,文件不存在時返回?NULL,跳過加載。

  3. 讀取數量
    fread(&list->count, ...):從文件開頭讀取商品數量。

  4. 分配內存
    malloc?根據商品數量分配足夠內存,失敗時終止程序。

  5. 讀取數據
    fread?將文件中的商品數據直接讀入?Data?數組。

  6. 關閉文件
    釋放文件資源。

關鍵知識點

  • 防御性編程:加載前初始化列表,避免臟數據。

  • 內存管理:動態分配的內存需在退出時通過?free?釋放。

使用示例

ProductList list;
load_from_file("data.dat", &list); // 加載數據

注意事項

  • 文件驗證缺失:若文件被篡改(如數量與實際數據不符),程序會崩潰。

  • 字節序問題:跨平臺時需處理大小端差異(如從Windows寫,Linux讀)。

3. main.c 主函數協同工作

1. 主函數代碼片段

int main() {ProductList list;Init_products(&list);load_from_file(FILENAME, &list); // 啟動時加載數據while (1) {// ...菜單處理...switch (choice) {case 6:save_to_file(FILENAME, &list); // 退出前保存free(list.Data); // 釋放內存return 0;}}
}

2. 數據生命周期管理

  1. 啟動流程

    • Init_products:初始化空列表。

    • load_from_file:嘗試加載數據,文件不存在則保持空列表。

  2. 運行期間

    • 用戶通過菜單操作增刪改查,所有變動僅在內存中。

  3. 退出流程

    • save_to_file:將內存數據保存到文件。

    • free(list.Data):釋放動態數組內存,防止泄漏。

3. 關鍵設計思想

  • 數據持久化:通過文件實現“記憶功能”,關閉程序不丟數據。

  • 資源管理

    • 加載時分配內存,退出時釋放,遵循“誰分配誰釋放”原則。

    • 文件操作封裝為獨立函數,提高代碼可維護性。


4.聯合調試示例

1. 正常流程驗證

  1. 第一次運行

    添加商品:名稱=蘋果,單價=5.5,庫存=20
    保存退出 → 生成data.dat文件
  2. 文件內容

    • 前4字節:01 00 00 00(數量1)

    • 后續內容:01 00 00 00(ID=1) + 名稱、單價、庫存的二進制數據。

  3. 第二次運行

    • 自動加載文件,顯示已有商品。

    • 修改庫存為30后保存退出。

2. 異常場景處理

  • 文件被刪除:啟動時加載失敗,列表為空。

  • 文件損壞:若手動修改文件導致數據錯亂,程序可能崩潰。

五、核心知識點總結


1. 動態內存管理
  • realloc?的作用:動態調整內存大小,首次調用時等效于?malloc

  • 錯誤處理:必須檢查返回值是否為?NULL

  • 內存釋放free?必須與?malloc/realloc?配對使用。


2. 結構體的使用
  • 數據封裝:將商品信息打包為?Product?結構體。

  • 列表管理ProductList?封裝動態數組和長度,提升代碼可維護性。


3. 輸入輸出安全
  • 緩沖區溢出防護scanf("%49s")?限制輸入長度。

  • 格式化輸出printf?的格式控制符對齊數據。


4. 文件操作
  • 二進制模式"wb"?和?"rb"?確保數據精確存儲。

  • 數據序列化:直接讀寫結構體內存,高效但需注意平臺兼容性。

相關運行截圖:?

?

?注:該代碼是本人自己所寫,可能不夠好,不夠簡便,歡迎大家指出我的不足之處。如果遇見看不懂的地方,可以在評論區打出來,進行討論,或者聯系我。上述內容全是我自己理解的,如果你有別的想法,或者認為我的理解不對,歡迎指出!!!如果可以,可以點一個免費的贊支持一下嗎?謝謝各位彥祖亦菲!!!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81032.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81032.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81032.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[服務器面板對比] 寶塔、aaPanel、Plesk、cPanel 哪家強?功能、性能與價格橫評 (2025)

對于很多 Linux 服務器用戶來說&#xff0c;直接面對黑乎乎的命令行界面 (CLI) 進行各種操作&#xff0c;雖然強大靈活&#xff0c;但也確實有一定的學習門檻和操作復雜度。特別是當你需要管理多個網站、數據庫、FTP賬戶&#xff0c;或者進行日常的軟件安裝、安全配置、日志查看…

WebGL圖形編程實戰【7】:變換流水線 × 坐標系與矩陣精講

變換流水線 #mermaid-svg-Omabd9LSNCdIvWqB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Omabd9LSNCdIvWqB .error-icon{fill:#552222;}#mermaid-svg-Omabd9LSNCdIvWqB .error-text{fill:#552222;stroke:#552222;…

電力電容器故障利用沃倫森(WARENSEN)工業設備智能運維系統解決方案

行業工況背景 當配電室報警顯示“電容器故障”時&#xff0c;管理者可能會感到焦慮。沃倫森&#xff08;WARENSEN&#xff09;憑借十多年的電力補償設備服務經驗&#xff0c;提供了科學的故障應對流程&#xff0c;幫助避免大部分二次損失。 一、五大常見故障現象快速識別 溫度…

星海智算云平臺部署GPT-SoVITS模型教程

背景 隨著 GPT-SoVITS 在 AI 語音合成領域的廣泛應用&#xff0c;越來越多的個人和團隊開始關注這項前沿技術。你是否也在思考&#xff0c;如何快速、高效地部署并體驗這款強大的聲音克隆模型&#xff1f;遺憾的是&#xff0c;許多本地部署方案不僅配置復雜&#xff0c;而且對…

高吞吐與低延遲的博弈:Kafka與RabbitMQ數據管道實戰指南

摘要 本文全面對比Apache Kafka與RabbitMQ在數據管道中的設計哲學、核心差異及協同方案。結合性能指標、應用場景和企業級實戰案例,揭示Kafka在高吞吐流式處理中的優勢與RabbitMQ在復雜路由和低延遲傳輸方面的獨特特點;介紹了使用Java生態成熟第三方庫(如Apache Kafka Clie…

Python零基礎入門到高手8.4節: 元組與列表的區別

目錄 8.4.1 不可變數據類型 8.4.2 可變數據類型 8.4.3 元組與列表的區別 8.4.4 今天彩票沒中獎 8.4.1 不可變數據類型 不可變數據類型是指不可以對該數據類型進行原地修改&#xff0c;即只讀的數據類型。迄今為止學過的不可變數據類型有字符串&#xff0c;元組。 在使用[]…

無人機數據處理與特征提取技術分析!

一、運行邏輯 1. 數據采集與預處理 多傳感器融合&#xff1a;集成攝像頭、LiDAR、IMU、GPS等傳感器&#xff0c;通過硬件時間戳或PPS信號實現數據同步&#xff0c;確保時空一致性。 邊緣預處理&#xff1a;在無人機端進行數據壓縮&#xff08;如JPEG、H.265&#xff09;…

LeetCode 熱題 100 105. 從前序與中序遍歷序列構造二叉樹

LeetCode 熱題 100 | 105. 從前序與中序遍歷序列構造二叉樹 大家好&#xff0c;今天我們來解決一道經典的二叉樹問題——從前序與中序遍歷序列構造二叉樹。這道題在 LeetCode 上被標記為中等難度&#xff0c;要求根據給定的前序遍歷和中序遍歷序列&#xff0c;構造并返回二叉樹…

CSS- 1.1 css選擇器

本系列可作為前端學習系列的筆記&#xff0c;代碼的運行環境是在HBuilder中&#xff0c;小編會將代碼復制下來&#xff0c;大家復制下來就可以練習了&#xff0c;方便大家學習。 HTML系列文章 已經收錄在前端專欄&#xff0c;有需要的寶寶們可以點擊前端專欄查看&#xff01; 系…

MongoClient和AsyncIOMotorClient的區別和用法

示例代碼&#xff1a; from motor.motor_asyncio import AsyncIOMotorClient from pymongo import MongoClient&#x1f50d; 這兩個庫分別是&#xff1a; 名字說明舉個例子pymongo.MongoClient同步版 的 MongoDB 客戶端&#xff08;常規阻塞式操作&#xff09;你在主線程里一…

5.15打卡

浙大疏錦行 DAY 26 函數專題1 知識點回顧&#xff1a; 1. 函數的定義 2. 變量作用域&#xff1a;局部變量和全局變量 3. 函數的參數類型&#xff1a;位置參數、默認參數、不定參數 4. 傳遞參數的手段&#xff1a;關鍵詞參數 5. 傳遞參數的順序&#xff1a;同時出現三種參數…

針對面試-mysql篇

1.如何定位慢查詢? 1.1.介紹一下當時產生問題的場景(我們當時的接口測試的時候非常的慢&#xff0c;壓測的結果大概5秒鐘))&#xff0c;可以監測出哪個接口&#xff0c;最終因為是sql的問題 1.2.我們系統中當時采用了運維工具(Skywalking就是2秒&#xff0c;一旦sql執行超過2秒…

window 顯示驅動開發-報告圖形內存(三)

圖形內存報告示例 示例 1&#xff1a;筆記本電腦上的 128 MB 專用板載圖形內存 以下屏幕截圖顯示了使用 Intel Iris 離散圖形適配器運行 Windows 11 的 Surface 筆記本電腦的計算圖形內存數。 適配器的可用內存總數為 16424 MB&#xff0c;用于圖形用途&#xff0c;細分如下&…

極簡主義現代商務風格PPT模版6套一組分享下載

現代商務風格PPT模版下載https://pan.quark.cn/s/12fbc52124d9 第一張PPT模版&#xff0c;簡約風&#xff0c;橄欖綠背景&#xff0c;黑色豎條裝飾&#xff0c;文字有中英文標題和占位符。需要提取關鍵元素&#xff1a;簡約、橄欖綠、對稱布局、占位文本的位置。 風格?&#…

SpringBoot中10種動態修改配置的方法

在SpringBoot應用中&#xff0c;配置信息通常通過application.properties或application.yml文件靜態定義&#xff0c;應用啟動后這些配置就固定下來了。 但我們常常需要在不重啟應用的情況下動態修改配置&#xff0c;以實現灰度發布、A/B測試、動態調整線程池參數、切換功能開…

嵌入式自學第二十二天(5.15)

順序表和鏈表 優缺點 存儲方式&#xff1a; 順序表是一段連續的存儲單元 鏈表是邏輯結構連續物理結構&#xff08;在內存中的表現形式&#xff09;不連續 時間性能&#xff0c; 查找順序表O(1)&#xff1a;下標直接查找 鏈表 O(n)&#xff1a;從頭指針往后遍歷才能找到 插入和…

高并發內存池(三):TLS無鎖訪問以及Central Cache結構設計

目錄 前言&#xff1a; 一&#xff0c;thread cache線程局部存儲的實現 問題引入 概念說明 基本使用 thread cache TLS的實現 二&#xff0c;Central Cache整體的結構框架 大致結構 span結構 span結構的實現 三&#xff0c;Central Cache大致結構的實現 單例模式 thr…

Ubuntu 安裝 Docker(鏡像加速)完整教程

Docker 是一款開源的應用容器引擎&#xff0c;允許開發者打包應用及其依賴包到一個輕量級、可移植的容器中。本文將介紹在 Ubuntu 系統上安裝 Docker 的步驟。 1. 更新軟件源 首先&#xff0c;更新 Ubuntu 系統的軟件源&#xff1a; sudo apt update2. 安裝基本軟件 接下來…

【深度學習】數據集的劃分比例到底是選擇811還是712?

1 引入 在機器學習中&#xff0c;將數據集劃分為訓練集&#xff08;Training Set&#xff09;、驗證集&#xff08;Validation Set&#xff09;和測試集&#xff08;Test Set&#xff09;是非常標準的步驟。這三個集合各有其用途&#xff1a; 訓練集 (Training Set)&#xff…

Mysql刷題 day01

LC 197 上升的溫度 需求&#xff1a;編寫解決方案&#xff0c;找出與之前&#xff08;昨天的&#xff09;日期相比溫度更高的所有日期的 id 。 代碼&#xff1a; select w2.id from Weather as w1 join Weather as w2 on DateDiff(w2.recordDate , w1.recordDate) 1 where…