剛剛進入大二,准備開始學習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 ;
}