題目描述
超市中商品分爲四類,分別是食品、化妝品、日用品和飲料。每種商品都包含商品名稱、價格、庫存量和生產廠家、品牌等信息。
主要完成對商品的銷售、統計和簡單管理。
功能要求
1.銷售功能(客戶):購買商品時,先輸入類別,然後輸入商品名稱,並在庫存中查找該商品的相關信息。如果有庫存量,輸入購買的數量,進行相應計算。如果庫存量不夠,給出提示信息,結束購買。
2.商品簡單管理功能(管理員):
(1)添加功能:主要完成商品信息的添加。
(2)查詢功能:可按商品類別、商品名稱、生產廠家進行查詢。若存在相應信息,輸出所查詢的信息,若不存在該記錄,則提示“該記錄不存在!”。
(3)修改功能:可根據查詢結果對相應的記錄進行修改。
(4)刪除功能:主要完成商品信息的刪除。先輸入商品類別,再輸入要刪除的商品名稱,根據查詢結果刪除該物品的記錄,如果該商品不在物品庫中,則提示“該商品不存在”。
(5)統計功能:輸出當前庫存中所有商品的總數及詳細信息;可按商品的價格、庫存量、生產廠家進行統計,輸出統計信息時,要按從大到小進行排序。
(6)商品信息存盤:將當前程序中的商品信息存入文件中。
(7)讀出信息:從文件中將商品信息讀入程序。
設計思路
通過各種自定義函數實現程序模塊化思想,將大問題轉換爲小問題,再逐個解決問題,主要利用自定義函數,結構體和、指針和鏈表。
調用函數
ITEM *Build(); //超市商品初始化
int Choice(void); //第一個選擇菜單
void Purchase(ITEM *items); //實現“客戶”功能
void Contents(ITEM *items, char cc[20]); //實現“客戶”菜單功能
ITEM *Find(char ca[20], char name[], ITEM *head); //按照用戶輸入的“商品名稱”查詢並返回對應查詢結果,否則返回NULL
int Menu(void); //實現“管理員”功能
void Add(ITEM *items); //實現“添加”功能
void Inquire(ITEM *items); //實現“查詢”的框架功能
ITEM *Seek(ITEM *items); //實現“查詢”的核心功能,類似於上Find函數
void Modify(ITEM *items); //實現“修改”功能
ITEM *Delete(ITEM *items); //實現“刪除”功能
ITEM *Statistics(ITEM *items); //實現“統計”的框架功能
ITEM *GetMid(ITEM *items);
ITEM *LinkBy(ITEM *x, ITEM *y, float a, int b);
ITEM *StatisticsBy(ITEM *items, float a, int b); //利用歸併排序
void Print(ITEM *items); //實現“輸出”功能
void Storage(ITEM *items); //實現“文件存盤”功能
ITEM *Open(); //實現“文件讀取”功能
(其中歸併排序函數功能本人並未詳細註釋,可見另一帖子《歸併排序》—>傳送門)
代碼實現
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct item //建立一個結構體儲存超市商品
{
char category[20];
char name[20];
float price;
int stock;
char manufacturer[20];
char brand[20];
struct item *next;
}ITEM;
ITEM *Build(); //超市商品初始化
int Choice(void); //第一個選擇菜單
void Purchase(ITEM *items); //實現“客戶”功能
void Contents(ITEM *items, char cc[20]); //實現“客戶”菜單功能
ITEM *Find(char ca[20], char name[], ITEM *head); //按照用戶輸入的“商品名稱”查詢並返回對應查詢結果,否則返回NULL
int Menu(void); //實現“管理員”功能
void Add(ITEM *items); //實現“添加”功能
void Inquire(ITEM *items); //實現“查詢”的框架功能
ITEM *Seek(ITEM *items); //實現“查詢”的核心功能,類似於上Find函數
void Modify(ITEM *items); //實現“修改”功能
ITEM *Delete(ITEM *items); //實現“刪除”功能
ITEM *Statistics(ITEM *items); //實現“統計”的框架功能
ITEM *GetMid(ITEM *items);
ITEM *LinkBy(ITEM *x, ITEM *y, float a, int b);
ITEM *StatisticsBy(ITEM *items, float a, int b);
void Print(ITEM *items); //實現“輸出”功能
void Storage(ITEM *items); //實現“文件存盤”功能
ITEM *Open(); //實現“文件讀取”功能
int main()
{
ITEM *items;
int c, n;
items = Build();
while(1)
{
c = Choice();
switch(c)
{
case 1:
Purchase(items);
break;
case 2:
n = Menu();
switch(n)
{
case 1:
Add(items);
break;
case 2:
Inquire(items);
break;
case 3:
Modify(items);
break;
case 4:
items = Delete(items);
break;
case 5:
items = Statistics(items);
break;
case 6:
Storage(items);
break;
case 7:
items = Open();
break;
case 0:
printf("\n已退出!\n\n");
break;
default :
printf("\n輸入錯誤!\n\n");
break;
}
break;
case 0:
printf("\n已退出!\n");
exit(0);
default :
printf("\n輸入錯誤!\n\n");
break;
}
}
return 0;
}
ITEM *Build() //超市商品初始化
{
ITEM *head, *it1, *it2, *it3, *it4;
it1 = (ITEM *)malloc(sizeof(ITEM));
if(it1!=NULL)
{
strcpy(it1->category, "食品");
strcpy(it1->name, "紅燒牛肉麪");
it1->price = 3.5;
it1->stock = 48;
strcpy(it1->manufacturer, "河南斯美特");
strcpy(it1->brand, "思源");
}
it2 = (ITEM *)malloc(sizeof(ITEM));
if(it2!=NULL)
{
strcpy(it2->category, "化妝品");
strcpy(it2->name, "男士潤膚霜");
it2->price = 69.9;
it2->stock = 23;
strcpy(it2->manufacturer, "德國進口");
strcpy(it2->brand, "妮維雅");
}
it3 = (ITEM *)malloc(sizeof(ITEM));
if(it3!=NULL)
{
strcpy(it3->category, "日用品");
strcpy(it3->name, "洗髮露");
it3->price = 23.5;
it3->stock = 13;
strcpy(it3->manufacturer, "廣州寶潔");
strcpy(it3->brand, "海飛絲");
}
it4 = (ITEM *)malloc(sizeof(ITEM));
if(it4!=NULL)
{
strcpy(it4->category, "飲料");
strcpy(it4->name, "脈動");
it4->price = 4.0;
it4->stock = 35;
strcpy(it4->manufacturer, "湖北達能");
strcpy(it4->brand, "脈動");
}
head = it1;
it1->next = it2;
it2->next = it3;
it3->next = it4;
it4->next = NULL;
return head;
}
int Choice(void) //第一個選擇菜單
{
int c;
printf("請選擇功能:\n\
1:銷售功能(客戶)\n\
2:商品簡單管理功能(管理員)\n\
0:退出\n");
scanf("%d", &c);
return c;
}
void Purchase(ITEM *items) //實現“客戶”功能
{
int c, m;
ITEM *j;
char name[20], ca[20];
printf("\n當前商品有:\n");
Contents(items, "食品");
Contents(items, "化妝品");
Contents(items, "日用品");
Contents(items, "飲料");
printf("\n請輸入商品類別:\n\
1:食品\n\
2:化妝品\n\
3:日用品\n\
4:飲料\n\
0:退出\n");
scanf("%d", &c);
if(c == 0)
goto E;
if(c == 1)
strcpy(ca, "食品");
else if(c == 2)
strcpy(ca, "化妝品");
else if(c == 3)
strcpy(ca, "日用品");
else
strcpy(ca, "飲料"); //通過數字選擇簡化用戶輸入
printf("\n請輸入商品名稱:\n");
scanf("%s", name);
j = Find(ca, name, items);
if(j == NULL)
printf("\n對不起,無此商品!\n");
else
{
printf("\n請輸入您要購買的數量:\n");
scanf("%d", &m);
if(m > j->stock)
printf("\n對不起,庫存不足!\n\n");
else
{
j->stock -= m;
printf("\n您共需付款%.2f元!\n謝謝購買,祝您購物愉快!\n\n", j->price*m);
}
}
E:printf("\n已退出\n\n");
}
void Contents(ITEM *items, char cc[20]) //實現“客戶”菜單功能
{
ITEM *it = items;
printf("%s:\n\t", cc);
while(it != NULL)
{
if(strcmp(it->category, cc) == 0)
{
printf("%s\t", it->name);
}
it = it->next;
}
printf("\n");
}
ITEM *Find(char ca[20], char name[], ITEM *head) //按照用戶輸入的“商品名稱”查詢並返回對應鏈表節點,否則返回NULL
{
ITEM *p = head;
while(p != NULL)
{
if(strcmp(p->category, ca) == 0 && strcmp(p->name, name) == 0)
{
printf("\n該商品的信息:\n\
價格:%.2f\n\
生產廠家:%s\n\
品牌:%s\n", p->price, p->manufacturer, p->brand);
return p;
}
p = p->next;
}
return NULL;
}
int Menu(void) //實現“管理員”功能
{
int n;
printf("\n請選擇您需要的功能:\n\
1:添加功能\n\
2:查詢功能\n\
3:修改功能\n\
4:刪除功能\n\
5:統計功能\n\
6:商品信息存盤\n\
7:讀出商品信息\n\
0:退出\n");
scanf("%d", &n);
return n;
}
void Add(ITEM *items) //實現“添加”功能
{
ITEM *p, *pr;
p = (ITEM *)malloc(sizeof(ITEM));
if(p != NULL)
{
printf("\n請輸入待添加商品的類別、名稱、價格、庫存量、生產廠家、品牌:\n");
scanf("%s %s %f %d %s %s", p->category, p->name, &p->price, &p->stock, p->manufacturer, p->brand);
}
else
{
printf("\n申請內存失敗!\n");
exit(0);
}
pr = items;
while(pr->next != NULL) //尋找鏈表尾節點
{
pr = pr->next;
}
pr->next = p;
p->next = NULL;
printf("\n已添加!\n\n");
}
void Inquire(ITEM *items) //實現“查詢”的框架功能
{
ITEM *p = Seek(items);
if(p != NULL)
printf("\n該商品的詳細信息爲:\n\
類別:%s\n\
名稱:%s\n\
價格:%.2f\n\
庫存量:%d\n\
生產廠家:%s\n\
品牌:%s\n\n", p->category, p->name, p->price, p->stock, p->manufacturer, p->brand);
else
printf("\n該記錄不存在!\n\n");
}
ITEM *Seek(ITEM *items) //實現“查詢”的核心功能,類似於上Find函數
{
ITEM *p = items, *ca;
ca = (ITEM *)malloc(sizeof(ITEM));
if(ca != NULL)
{
printf("\n請輸入待查商品的類別、名稱、生產廠家:\n");
scanf("%s %s %s", ca->category, ca->name, ca->manufacturer);
}
else
{
printf("\n申請內存失敗!\n");
exit(0);
}
while(p != NULL) //不斷往鏈表尾節點靠近,尋找待查節點
{
if(strcmp(p->category, ca->category) == 0 && strcmp(p->name, ca->name) == 0 && strcmp(p->manufacturer, ca->manufacturer) == 0)
{
return p;
}
p = p->next;
}
return NULL;
}
void Modify(ITEM *items) //實現“修改”功能
{
ITEM *p = Seek(items);
if(p != NULL)
{
printf("\n請依次輸入修改後的信息:類別、名稱、價格、庫存量、生產廠家、品牌:\n");
scanf("%s %s %f %d %s %s", p->category, p->name, &p->price, &p->stock, p->manufacturer, p->brand);
printf("\n已修改!\n\n");
}
else
{
printf("\n對不起,您輸入有誤!\n\n");
}
}
ITEM *Delete(ITEM *items) //實現“刪除”功能
{
ITEM *p = items, *d = items;
char ca[20], na[20];
printf("\n請輸入待刪除商品的類別:\n");
scanf("%s", ca);
printf("\n請輸入待刪除商品的名稱:\n");
scanf("%s", na);
while(p!=NULL)
{
if(strcmp(p->category, ca) == 0 && strcmp(p->name, na) == 0) //尋找待操作節點
break;
p = p->next;
}
/*這裏分爲待刪除節點爲頭結點和非頭結點兩種,分別做處理,本質都爲
將待刪除節點next域傳給其上一節點(頭結點除外),但是並不用考慮
尾節點的問題,因爲如果是尾節點其next域爲NULL傳給其上一節點正對*/
if(p == NULL)
{
printf("\n對不起,您輸入有誤!\n\n");
return items;
}
else if(p == items)
{
free(p);
printf("\n已刪除!\n\n");
return items->next;
}
else
{
while(d != NULL)
{
if(d->next == p)
{
free(p);
printf("\n已刪除!\n\n");
d->next = p->next;
return items;
}
d = d->next;
}
}
return items;
}
ITEM *Statistics(ITEM *items) //實現“統計”的框架功能
{
int n;
ITEM *Pt;
printf("\n請選擇統計方式:\n\
1:按價格統計\n\
2:按庫存量統計\n\
3:直接統計\n\
0:退出\n");
scanf("%d", &n);
if(n == 0)
{
printf("\n已退出!\n\n");
return items;
}
else if(n == 1)
{
Pt = StatisticsBy(items, items->price, 0);
Print(Pt);
return Pt;
}
else if(n == 2)
{
Pt = StatisticsBy(items, 0, items->stock);
Print(Pt);
return Pt;
}
else
{
Print(items);
return items;
}
}
/*下面三個函數爲實現“統計”的核心功能,主要利用“歸併排序”思想,爲本
碼最大的閃光點(手動滑稽),此處不做詳談*/
ITEM *GetMid(ITEM *items)
{
if(items->next == NULL)
return items;
ITEM *q = items, *s = items, *p;
while(q->next != NULL && q->next->next != NULL)
{
q = q->next->next;
s = s->next;
}
p = s->next;
s->next = NULL;
return p;
}
/*下面兩函數有一巧妙之處,即自定義函數參數中有float與int型可以用來
區別是按何種方式統計,省的定義兩個極其相似的函數統計,提高可讀性*/
ITEM *LinkBy(ITEM *x, ITEM *y, float a, int b)
{
ITEM *ret = NULL, *tail = NULL;
while(x!=NULL && y!=NULL)
{
if((x->stock > y->stock && a == 0) ||(x->price > y->price && b == 0))
{
ITEM *temp = x->next;
if(ret == NULL)
{
ret = tail = x;
ret->next = NULL;
}
else
{
tail->next = x;
tail = tail->next;
tail->next = NULL;
}
x = temp;
}
else
{
ITEM *temp = y->next;
if(ret == NULL)
{
ret = tail = y;
ret->next = NULL;
}
else
{
tail->next = y;
tail = tail->next;
tail->next = NULL;
}
y = temp;
}
}
if(x == NULL)
tail->next = y;
else
tail->next = x;
return ret;
}
ITEM *StatisticsBy(ITEM *items, float a, int b)
{
if(items->next == NULL)
return items;
ITEM *p1, *p2, *mid;
mid = GetMid(items);
p1 = StatisticsBy(items, a, b);
p2 = StatisticsBy(mid, a, b);
return LinkBy(p1,p2, a, b);
}
void Print(ITEM *items) //實現“輸出”功能
{
int i=1;
ITEM *p = items;
printf("\n統計商品爲:\n");
while(p != NULL)
{
printf("\t%d:\n\
類別:%s\n\
名稱:%s\n\
價格:%.2f\n\
庫存量:%d\n\
生產廠家:%s\n\
品牌:%s\n", i , p->category, p->name, p->price, p->stock, p->manufacturer, p->brand);
p = p->next;
i++;
}
printf("\n");
}
void Storage(ITEM *items) //實現“文件存盤”功能
{
FILE *fp = fopen("Shop.txt", "w+");
if(fp == NULL)
{
printf("\n操作失敗!\n");
exit(0);
}
else
{
ITEM *p = items;
while(p != NULL)
{
fprintf(fp, "%s\t%s\t%.2f\t%d\t%s\t%s", p->category, p->name, p->price, p->stock, p->manufacturer, p->brand);
if(p->next != NULL)
{
fprintf(fp, "\n");
}
p = p->next;
}
printf("\n儲存成功! \n\n");
fclose(fp);
}
}
/*此處着實爲難我很久,儲存很簡單,但是再按原樣讀取出來就非常難了,
但是最後我還是找到方法了,利用\t就能完美的解決此問題,使儲存的文
件既有可讀性又能使讀取操作簡單*/
ITEM *Open() //實現“文件讀取”功能
{
FILE *fp = fopen("Shop.txt","r");
if (fp == NULL)
{
printf("\n打開失敗,請檢查該文件!\n");
exit(0);
}
else
{
ITEM *p = NULL, *pt = NULL;
while (!feof(fp))
{
pt = (ITEM*)malloc(sizeof(ITEM));
fscanf(fp, "%s%s%f%d%s%s", pt->category, pt->name, &pt->price, &pt->stock, pt->manufacturer, pt->brand);
pt->next = p;
p = pt;
}
pt = NULL;
printf("\n讀取成功!\n\n");
fclose(fp);
return p;
}
}
如果覺得本碼足夠規整而又不清楚規範,可查看另一帖子《C語言代碼規範》–>傳送門
感謝師傅來訪,技術不精,請勿吐槽,如有問題請留言。