准備開始學習C++,對大一所學的C語言一次練習,正好也是趕上老師布置的任務,用C語言寫一個 銷售管理系統 ,就盡可能的把所學的都用上,也就是結構,指針,文件操作,還有數據結構,本次加入了鏈表。
用兩個函數 Load_LinkList() 和 Save_LinkList() 讓鏈表與文件操作結合,除了打印函數,其他都是在內存中操作鏈表,這樣寫更有條理,在創建鏈表時沒有采用書上的用一個中間變量引導,並插入到結點前面,而是直接在鏈表尾的next申請內存,便於理解,操作也方便。
/*首先是文件包含,這裡就不使用 ifndef 那樣常規寫一個頭文件*/ #include <stdio.h> #include <string.h> #include <windows.h> #include <stdlib.h> #include <conio.h>
/*接下來就是結構體*/ /*每一種商品對應一個結點,用鏈表連接起來,統一寫入文件,或者從文件中讀取*/ typedef struct commodity { int data; //頭結點data統計個數,其余為商品編號 char name[20]; //名稱 double price; //價格 int count; //數量 double sum; //總計,頭結點sum為所有商品總計 struct commodity *next; } *LinkList, LNode;
/*定義全局變量,方便使用*/ /*鏈表頭指針*/ LinkList H = NULL; /*文件指針*/ FILE *fp = NULL;
/*函數聲明*/ /***************顯示函數****************/ //歡迎界面 void welcome(); //顯示菜單 void menu();
//打印表格頭 void printf_header();
//顯示單個結點信息 void printf_linklist_info(LinkList pTemp); //延時函數 void delay(); /***********鏈表文件操作函數*****************/ //從文件中讀取到鏈表中 void Load_LinkList(LinkList H); //將鏈表保存到文件中 void Save_LinkList(LinkList H); /***************鏈表函數**********************/ //建立頭結點 void Creat_LinkList(); //添加結點到鏈表尾部 LinkList Add_LinkList(LinkList H); //輸入結點數據 void Scanf_LinkList(LinkList pTemp); //找到符合要求的結點的前驅 LinkList Find_LinkList_Pos(LinkList H,int index); //找到符合要求的結點的地址 LinkList Find_LinkList_Val(LinkList H, char *name); //刪除指定結點 void Del_LinkList(LinkList H, char *name); //修改結點內容 void Modify_LinkList(LinkList H, int index, int data); //順序輸出 void Printf_LinkList(LinkList H); //釋放內存 void Free_LinkList(LinkList H);
/*main函數,沒什麼說的,除了getch函數用的時候會方便一些*/ int main() { LinkList pTemp = NULL; char name[20] = {0}; system("color A"); //welcome(); Creat_LinkList(); Load_LinkList(H); while(1) { system("cls"); menu(); switch(getch()) { case '1': pTemp = Add_LinkList(H); Scanf_LinkList(pTemp); getch(); break; case '2': printf_header(); Printf_LinkList(H); getch(); break; case '3': printf("\n輸入名稱查找:"); scanf("%s", name); pTemp = Find_LinkList_Val(H, name); printf_linklist_info(pTemp); getch(); break; case '4': printf("\n請先輸入名稱查找:"); scanf("%s", name); pTemp = Find_LinkList_Val(H, name); Scanf_LinkList(pTemp); getch(); break; case '5': printf("\n請先輸入名稱查找:"); scanf("%s", name); Del_LinkList(H, name); getch(); break; case '6': Save_LinkList(H); printf("\n成功保存%d條信息!\n", H->data); getch(); break; case '0': printf("\n歡迎下次使用!\n"); exit(0); default : printf("錯誤輸入!"); getch(); } } return 0; }
////////////////////下面是顯示函數實現內容
/*歡迎界面,其實不要也可以*/ void welcome() { int i; for(i=1 ; i<=100 ; i++) { printf("*******************歡迎使用本系統*************************"); printf("\n\n\n\n\n\n\n"); printf(" 加載中"); printf("...\n"); printf(" %3d%%\n",i); printf("**********************************************************"); system("cls"); } return ; }
/*菜單函數*/ void menu() { system("cls"); printf(" 歡迎進入本系統 \n"); printf("\n"); printf("-------------------------------------------------------------------\n"); printf("| 1 添加商品 |\n"); printf("| 2 顯示商品 |\n"); printf("| 3 查找商品 |\n"); printf("| 4 修改商品 |\n"); printf("| 5 刪除商品 |\n"); printf("| 6 保存修改 |\n"); printf("| 0 退出系統 |\n"); printf("-------------------------------------------------------------------\n"); printf(" 提示:退出前請先保存!"); printf("\nchoose(0-8):"); }
/*以表格的形式打印所有商品信息*/ void printf_header() { system("cls"); printf("-------------------------您的所有庫存-------------------------------------\n"); printf("| 編號 | 名稱 | 價格 | 數量 | 總計 |\n"); printf("|----------|---------------|---------------|----------------|------------|\n"); }
/*顯示單個結點信息*/ void printf_linklist_info(LinkList pTemp) { if(pTemp == NULL) { return ; } printf_header(); pTemp->sum = pTemp->price * pTemp->count; printf("|%10d|%15s| %lf |%20d| %lf |\n",pTemp->data, pTemp->name, pTemp->price, pTemp->count, pTemp->sum); printf("|----------|---------------|---------------|----------------|------------|\n"); return ; }
/*延時函數,寫完了發現我一直用的是getch等待按鍵*/ void delay() { long int i,j; for(i=500000 ; i>0 ; i--) { for(j=0 ; j<=2000 ; j++); } }
/*創建頭結點*/ void Creat_LinkList() { H = (LinkList)malloc(sizeof(LNode)); if(H) { H->next = NULL; H->data = 0; } return ; }
/*添加結點,這裡是直接用最後一個節點的next申請內存*/ LinkList Add_LinkList(LinkList H) { LinkList q = H; while(q->next != NULL) q = q->next; q->next = (LinkList)malloc(sizeof(LNode)); q->next->sum = 0; q->next->next = NULL; H->data++; return q->next; }
/*用於添加結點時輸入結點信息,或者修改時輸入*/ void Scanf_LinkList(LinkList pTemp) { if(pTemp == NULL) { return ; } printf("\n輸入編號:"); scanf("%d", &pTemp->data); printf("輸入名稱:"); scanf("%s", pTemp->name); printf("輸入價格:"); scanf("%lf", &pTemp->price); printf("輸入數量:"); scanf("%d", &pTemp->count); pTemp->sum = pTemp->price * pTemp->count; }
/*從文件中讀取並加載到鏈表中,和Save函數一樣,是最關鍵的兩個函數*/ void Load_LinkList(LinkList H) { LinkList p = NULL, pTemp = NULL; pTemp = (LinkList)malloc(sizeof(LNode)); pTemp->next = NULL; fp = fopen("D:/a.txt", "rb"); while(1) { /*這裡用一個中間結點,臨時儲存,fread讀一次才能決定是否添加結點,直接用p添加結點會錯誤,本身就是空文件時會多出一個結點,存的垃圾值,而fread必須有一塊內存才能讀*/ if((fread(pTemp, sizeof(LNode), 1, fp)) != 0) { p = Add_LinkList(H); p->data = pTemp->data; strcpy(p->name, pTemp->name); p->price = pTemp->price; p->count = pTemp->count; H->data++; } else break; } free(pTemp); fclose(fp); return ; }
/*將鏈表保存到文件中*/ void Save_LinkList(LinkList H) { LinkList p = H->next; if(p == NULL) { /*這裡是清空一下,假如鏈表中保存的有數據,調用刪除完之後,不能用fwrite,只是這種情況下用wb清空文件*/ fp = fopen("D:/a.txt", "wb"); H->data = 0; fclose(fp); getch(); return ; } fp = fopen("D:/a.txt", "wb"); while(p != NULL) { fwrite(p, sizeof(LNode), 1, fp); p = p->next; } fclose(fp); return ; }
///////////////接下來的函數就是只在內存裡面操作鏈表
/*通過位置查找,返回結點 前驅結點 地址,計劃是有這個查找的,後來寫菜單也不想用了,就放這裡沒動過*/ LinkList Find_LinkList_Pos(LinkList H,int index) { LinkList p = H; index--; while(index--) { p = p->next; } return p; }
/*通過字符串匹配查找,返回結點地址*/ LinkList Find_LinkList_Val(LinkList H, char *name) { LinkList p = H; while(strcmp(p->name, name) != 0 && p->next != NULL) { p = p->next; } if(p->next == NULL) { printf("沒有此商品!"); return NULL; getch(); } return p; }
/*刪除一個結點,pre是前驅結點,p是要找的結點*/ void Del_LinkList(LinkList H, char *name) { int flag = 0; LinkList p = H->next, pre = H; while(p != NULL) { if(strcmp(p->name, name) == 0) { flag = 1; break; } pre = p; p = p->next; } if(flag == 0) { printf("沒有此商品!\n"); return ; } p = pre->next; pre->next = p->next; free(p); return ; }
/*修改結點信息,也是也可以實現的,和Find_LinkList_Pos()一樣,沒有用過*/ void Modify_LinkList(LinkList H, int index, int data) { LinkList p = Find_LinkList_Pos(H, index+1); if(p) p->data = data; return ; }
/*順序輸出,表格沒有對太齊,應該用 %xd 這樣的,後來也不想改了*/ void Printf_LinkList(LinkList H) { LinkList p = NULL; p = H->next; if(p == NULL) { printf("當前沒有任何商品!"); getch(); return ; } while(p != NULL) { p->sum = p->price * p->count; printf("|%10d|%15s| %lf | %15d | %lf |\n",p->data, p->name, p->price, p->count, p->sum); printf("-------------------------------------------------------------------------------\n"); p = p->next; } printf(" %lf\n", H->sum); return ; }
/*內存總是要釋放的*/ void Free_LinkList(LinkList H) { LinkList pre = NULL, p = H->next; while(pre != NULL) { pre = p->next; free(p); p = p->next; } H->next = NULL; return ; }