题目描述
超市中商品分为四类,分别是食品、化妆品、日用品和饮料。每种商品都包含商品名称、价格、库存量和生产厂家、品牌等信息。
主要完成对商品的销售、统计和简单管理。
功能要求
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语言代码规范》–>传送门
感谢师傅来访,技术不精,请勿吐槽,如有问题请留言。