C语言-------销售管理系统
一.需求分析
A.功能需求
很多商品销售机构都需要用到销售管理系统,商品信息包含的字段很多,比如包括:商品编号、商品名称、商品类别(普通电视机、DVD、带DVD的电视机,带DVD的电视机的售价为普通电视机和DVD单价之和的80%)、商品进货价格、商品销售价格、商品数量、供应商名称等。对系统的具体要求如下:
销售商品信息增删改查。
销售商品退货管理。
销售商品进货价格管理。
销售商品销售价格管理。
销售商品统计功能。
销售商品排序(价格)功能。
B.技术要求:
(1)能够运用C语言知识和结构化编程思想,对实际问题进行分析,设计具有一定创新性的实现方案,并能够对相关方案进行筛选;
(2)必须遵守软件工程的相关职业道德和规范,培养良好的编码规范和习惯。例如变量、函数命名必须做到见名知义,代码必须有必要的注释等;
(3)所有的数据存储必须采用文件的形式,可以采用文本文件或者二进制文件;
(4)工程结构尽量采用多文件结构,且文件结构必须合理;
(5)必须采用标准的C语言输入输出;
(6)能够通过相应的软件测试保证所编写代码的质量。
二. 概要设计
⒈ 设计商品信息的抽象数据类型定义:struct woodinfo{}
⒉ 重要的基本函数模块:
基本操作 操作结果
struct Node* list = NULL; 创建全局链表
struct Node* createHead() 创建表头
struct Node* createNode() 创建节点:为插入做准备
void printList() 打印链表函数(仓库数据)
void printListSimple() 打印链表函数(商品数据)
void insertNodeByHead() 链表插入函数Push(&S,e)
struct Node* searchByName 指定位置查找
void deleteNodeByData 指定位置删除
void menu() 菜单模块
void saveInforFormFile 文件存操作
void readInfoFromFile 文件读操作
void bubbleSortList() 冒泡排序法
void keyDown() 交互模块
int main() 主函数
⒊ 商品的抽象数据类型定义:
struct woodinfo
{
int num;//商品编号
char name[20];//商品名称
char type[20];//商品种类(DVD)
float inprice;//进价
float outprice;//售价
int many;//数量
char soldmane[20];//供应商
} ;
基本操作:
void saveInforFormFile--------------------------------文件存操作
初始条件:利用FILE函数在程序运行时自动创建出一个woodinfo(商品信息)的文档(.txt),之后在利用链表依次讲链表中的信息填入文档中,并实行保存。
操作结果:输入完毕后,文件夹中会自动生成一个woodinfo(.txt)文件,并存储着链表内信息。
void readInfoFromFile--------------------------------文件读操作
初始条件:已存储在FILE中的数据待读阅。
操作结果:利用遍历的方式依次输出链表中包含的内容,并打印出来。
void bubbleSortList()--------------------------------冒泡排序法
初始条件:利用冒泡排序法的算法对链表中的每件商品的价格进行排序,并储存在FILE文件内,实行实时更新。
操作结果:商品会因价格的高低排序表示出来。
struct Node* searchByName
操作结果:通过遍历自定义结构体中的商品名字进行查找,并将查找的结果反馈到桌面,如果找到则直接显示出商品的相关信息,为找到则输出“未找到该商品!”。
void deleteNodeByData-------------------------------指定位置删除
操作结果:过遍历自定义结构体中的商品名字进行查找,并将查找的结果从链表中删除并将删除后的信息保存于文档中。
三.详细设计
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//自定义结构体(商品信息)
struct woodinfo
{
int num;//商品编号
char name[20];//商品名称
char type[20];//商品种类(DVD)
float inprice;//进价
float outprice;//售价
int many;//数量
char soldmane[20];//供应商
} ;
struct Node
{
struct woodinfo data;
struct Node* next;
};
struct Node* list = NULL;//创建全局链表
//创建表头
struct Node* createHead()
{
//动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
//创建节点:为插入做准备
struct Node* createNode(struct woodinfo data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data= data;
newNode->next= NULL;
return newNode;
}
//打印链表函数(仓库数据)
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
printf("商品编号\t名称\t类别\t进价\t售价\t数量\t供应商名字:\n");
while(pMove)
{
printf("%d\t\t%s\t%s\t%.1f\t%.1f\t%d\t%s\n",pMove->data.num,pMove->data.name,pMove->data.type,pMove->data.inprice,pMove->data.outprice,pMove->data.many,pMove->data.soldmane);
pMove = pMove->next;
}
}
//打印链表函数(商品数据)
void printListSimple(struct Node* headNode)
{
struct Node* pMove = headNode->next;
printf("名称\t类别\t售价\t数量\t供货商\n");
while(pMove)
{
printf("%s\t%s\t%.1f\t%d\t%s\n",pMove->data.name,pMove->data.type,pMove->data.outprice,pMove->data.many,pMove->data.soldmane);
pMove = pMove->next;
}
}
//链表插入函数
void insertNodeByHead(struct Node* headNode,struct woodinfo data)
{
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
//指定位置查找
struct Node* searchByName(struct Node* headNode,char* woodname)
{
struct Node* posNode = headNode->next;
while(posNode!=NULL&&strcmp(posNode->data.name,woodname))
{
posNode=posNode->next;
}
return posNode;
}
//指定位置删除
void deleteNodeByData(struct Node* headNode,char *name)
{
struct Node* posLeftNode = headNode;
struct Node*posNode = headNode->next;
//商品名称是字符串,字符串比较函数
while (posNode !=NULL && strcmp(posNode->data.name,name))
{
posLeftNode = posNode;
posNode = posLeftNode->next;
}
if(posNode ==NULL)
return;
else//删除代码
{
printf("删除成功!\n");
posLeftNode->next = posNode->next;
free(posNode);
posNode = NULL;
}
}
//菜单模块
void menu()
{
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("~~~~~~~~~~~~~销售管理系统~~~~~~~~~~~~~~~~~~~\n");
printf("0.退出销售管理系统\n");
printf("1.进货\n");
printf("2.退货\n");
printf("3.仓库详细信息展示\n");
printf("4.商品列表\n");
printf("5.商品列表2.0(按价格高低)\n");
printf("6.查找商品\n");
printf("请输入(0~6):");
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
}
//文件存操作
void saveInforFormFile(const char* fileName, struct Node* headNode)
{
FILE* fp = fopen(fileName,"w");
struct Node* pMove = headNode->next;
while(pMove !=NULL)
{
fprintf(fp,"%d\t%s\t%s\t%.1f\t%.1f\t%d\t%s\n",pMove->data.num,pMove->data.name,pMove->data.type,pMove->data.inprice,pMove->data.outprice,pMove->data.many,pMove->data.soldmane);
pMove = pMove->next;
}
fclose(fp);
}
//文件读操作
void readInfoFromFile(const char* fileName,struct Node* headNode)
{
FILE* fp=fopen(fileName,"r");//第一次开始无文件创建文件
if (fp==NULL)//创建文件
{
fp = fopen(fileName,"w+");
}
struct woodinfo tempdata;
while(fscanf(fp,"%d\t%s\t%s\t%f\t%f\t%d\t%s",tempdata.num,tempdata.name,tempdata.type,tempdata.inprice,tempdata.outprice,tempdata.many,tempdata.soldmane)!=EOF)
{
insertNodeByHead(list,tempdata);
}
fclose(fp);
}
//冒泡排序法
void bubbleSortList(struct Node* headNode)
{
for(struct Node* p = headNode->next;p!=NULL;p=p->next)
{
for(struct Node* q=headNode->next;q->next!=NULL;q=q->next)
{
if(q->data.outprice>q->next->data.outprice)
{
//交换值
struct woodinfo tempdata = q->data;
q->data=q->next->data;
q->next->data=tempdata;
}
}
}
printListSimple(list);
}
//交互模块
void keyDown ()
{
int userKey = 0;
struct woodinfo tempwood;//产生一个临时的变量存储商品信息
struct Node* result =NULL;
scanf("%d",&userKey);
switch (userKey)
{
case 0:
printf("[退出]\n");
printf("退出成功!\n");
system("pause");
exit(0);
break;
case 1:
printf("[进货ing]\n");
printf("请依次输入:\n");
printf("商品编号 名称 类别 进价 售价 数量 供应商名字:\n");
scanf("%d%s%s%f%f%d%s",&tempwood.num,tempwood.name,tempwood.type,&tempwood.inprice,&tempwood.outprice,&tempwood.many,&tempwood.soldmane);
insertNodeByHead(list, tempwood);
saveInforFormFile("woodinfo.txt",list);
break;
case 2:
printf("[退货ing]\n");
printf("请输入需要退货的商品名称:\n");
scanf("%s",tempwood.name);
deleteNodeByData(list,tempwood.name);
saveInforFormFile("woodinfo.txt",list);
printf("退货成功!\n");
break;
case 3:
printf("[仓库详细信息展示]\n");
printList(list);
break;
case 4:
printf("[商品列表]\n");
printListSimple(list);
break;
case 5:
printf("[商品列表2.0(按价格高低)]\n");
bubbleSortList(list);
break;
case 6:
printf("[查找商品ing]\n");
printf("请输入需要查找的商品名称:\n");
scanf("%s",tempwood.name);
result = searchByName(list,tempwood.name);
if(result==NULL)
{
printf("未找到相关商品!\n");
}
else
{
printf("商品编号 名称 类别 进价 售价 数量 供应商名字:\n");
printf("%d\t\t%s\t%s\t%.1f\t%.1f\t%d\t%s\n",result->data.num,result->data.name,result->data.type,result->data.inprice,result->data.outprice,result->data.many,result->data.soldmane);
}
}
}
//主函数
int main()
{
list = createHead();//初始化全局链表
readInfoFromFile("woodinfo.txt",list);
while(1)
{
menu();
keyDown();
system("pause");//防止闪屏
system("cls");//清屏
}
system("pause");
return 0;
}
四.调试分析
⒈. 开始输入代码写为scanf(“%.1f”,&a),发现程序运行到该步骤总是自动退出,最后得知scanf的用法这样用会引起错误,修改为(“%f”),输出格式可以为printf(“%.f”)。
⒉. 自定义函数名在引用该函数时引用名发生错误,导致编译器无法识别,并提示需要定义改该函数,修改后即可正确运行。
⒊. 进行数据输出运用了格式符依旧无法进行数据的对齐,直到在未对齐的数据后多加了了个\t才实现数据的对齐。
⒋.Scanf()输入的%s时不需要取地址符&;
⒌.一开始引用FILE文件时,第一次运行皆正常,而一旦txt内存有数据后,再运行程序时会导致程序无法打开,无法正常运行。多次检测后发现为文档写操作中的fscanf中非字符未加取地址符号&,导致光标无法到达EOF,进入了死循环。重新加入&后,一切正常。
⒍.自定义函数放在了该函数调用的后面,导致从上而下的程序编译时报错显示未声明该函数,将自定义函数放在所有调用函数之前,即可正常编译运行。
五.总结分析
1.采用自定义函数按照模块的方式,一个模块一个模块的逐个针对,使整个程序会显得更加简洁,并会让主函数变得十分简洁,其余的步骤交个各个小函数模块进行操作。
2. 采用链表进行数据的储存可以使文件的删除更加方便,这是链表相较于数组的优越性,同时对于查找删除的操作也是更加方便,无需数组的逐个遍历。
3. 采用File文件对链表中的数据进行存储可以使得程序对于已填入的数据可更加方便的进行后续操作,无需重新输入,并可在原来存储的数据中进行增删查改的操作,使得程序的简便性更加强大。
4. 采用system(“pause”);语句可以防止闪屏,使得程序进行更加流畅;
5. 采用system(“cls”);语句可以在一次交互操作后清空屏幕(但会保留菜单项),使得程序的界面更加简洁明了,便于操作。
六.运行展示
详细信息展示功能:
菜单界面
查找商品演示