当前位置: 首页 > news >正文

大一C语言课设 服装销售系统 代码实现与项目总结

问题分析

服装信息管理及销售管理系统。方便对库存服装的信息管理和添加新服装数据,同时兼具库存数量管理功能。

功能实现

1、建立服装信息库,包括:服装代码、型号、规格、面料、颜色、单价、数量;
2、建立销售信息库,包括:服装代码,数量,日期,售价,小记
3、程序分为两大模块:库存模块和销售模块。库存模块主要用于对服装信息的增加、删除、修改。销售模块主要用于管理库存数量;
4、浏览:管理员可以查询库存信息和销售信息。
5、查找或修改:可以通过编号查找服装。可以根据编号进行修改、删除信息;
6、登记:可以通过编号登记库存情况、销售情况,同时改变库存信息。

现在来看,这个项目最大的难点就是利用c语言的文件系统实现同时修改多个文件,例如服装下单时,要先检查剩余库存;购买时不仅要扣减库存,还要写入购买记录。在没有数据库时实现这一功能比较麻烦。

代码实现

/*该程序运行编译器为Dev-C++ 5.4.0 ,64位系统*/ 
#include<stdio.h>
#include<string.h>
typedef struct _clothes{
	int nu;			//nu as number,服装代码 
	char name[30];	
	char si[10];		//si as size
	char ma[20];	//ma as material
	char co[10];	//co as color
	float pr;		//pr as prize
	int qu;			//qu as quantity
}Clothes;			//建立clothes结构类型,方便进行读写
typedef struct _sale{
	int rn;			//rn as real number,means the sequence of infomation
	int nu;			//nu as number,服装代码 
	int qu;			//qu as quantity
	char da[9];		//da as date,save by 8 bytes char;
	float pr;		//pr as prize
	char note[20]; 
}Sale;				//建立sale结构类型,方便进行读写 
//键盘输入新的库存信息
void cgetlist(Clothes aClo[],int number,int innumber){				 
	int i;
	for(i=0;i<number;i++,innumber++){								//输入number个数据 
		printf("服装代码为(系统自动分配):%d\n",innumber+1);
		aClo[i].nu=innumber;
		printf("\t输入型号:");
		scanf("%29s",aClo[i].name);
		printf("\t输入规格:");
		scanf("%9s",aClo[i].si); 
		printf("\t输入面料:");
		scanf("%19s",aClo[i].ma);
		printf("\t输入颜色:");
		scanf("%9s",aClo[i].co);
		printf("\t输入单价:");
		scanf("%f",&aClo[i].pr);
		printf("\t输入库存数量:");
		scanf("%d",&aClo[i].qu);
	}
}
//键盘输入新的销售信息 
int sgetlist(Sale aSal[],int number,int innumber){					
	int i;
	for(i=0;i<number;i++,innumber++){
		printf("销售记录代码为:%d\n",innumber+1); 
		aSal[i].rn=innumber;
		printf("\t输入服装代码:");
		scanf("%d",&aSal[i].nu);
		printf("\t输入销售数量:");
		scanf("%d",&aSal[i].qu);
		if(reducecheck(aSal[i].nu,aSal[i].qu)==-1)	{return -1;}	//检查库存是否足够,不够就返回,中止后面的输入 
		printf("\t输入日期:");
		scanf("%s",aSal[i].da); 
		printf("\t输入售价:");
		scanf("%f",&aSal[i].pr);
		printf("\t小记:");
		scanf("%s",aSal[i].note);
	}
	return 0;														//不然就不返回值 
}
//将cgetlist输入的信息写入文件,与文件直接通信
int save(Clothes aClo[],int number){								 
	int ret=-1;														//作为是否成功写入的标记值 
	FILE*fp=fopen("clothes.data","a");								//尝试用追加打开,用w打开的话会把之前的数据全部清除 
	if(!fp){														//如果打开失败(假设是由于没有可打开的文件) 
		fclose(fp);													//就关闭文件指针 
		FILE*fp=fopen("clothes.data","w");							//再用w打开来建立文件 
		fclose(fp);													//然后关闭指针 
		FILE*fpc=fopen("clothes.data","a");							//再用追加打开 
		ret=fwrite(aClo,sizeof(Clothes),number,fpc);				//写入aClo结构体数组,同时给ret一个值 
		fclose(fpc);												//关闭指针 
	}
	else if(fp){													//如果用追加方式打开了 
		ret=fwrite(aClo,sizeof(Clothes),number,fp);					//就直接写入 
		fclose(fp);
	}
	return ret==number;												//返回number 
}
//将sgetlist输入的信息写入文件,与文件直接通信 
int ssave(Sale aSal[],int number){									
	int ret=-1;													//作为是否成功写入的标记值
	FILE*fp=fopen("sale.data","a");								//同save,用w或a打开 
	if(!fp){
		fclose(fp);
		FILE*fp=fopen("sale.data","w");
		fclose(fp);
		FILE*fpc=fopen("sale.data","a");
		ret=fwrite(aSal,sizeof(Sale),number,fpc);
		fclose(fpc);
	}
	else if(fp){
		ret=fwrite(aSal,sizeof(Sale),number,fp);
		fclose(fp);
	}
	return ret==number;
}
//读取打印库存数据 
void read(FILE*fp,int index){										
	fseek(fp,index*sizeof(Clothes),SEEK_SET);						//fp指针移动到指定数据的位置 
	Clothes clo;													//建立结构体用来接受文件里的数据 
	if(fread(&clo,sizeof(Clothes),1,fp)==1){						//从文件读取数据,如果不成功的话就不输出到控制台 
		printf("服装代码:%d",index+1);								//用printf输出clo里的数据 
		printf("\t型号:%s\n",clo.name);
		printf("\t规格:%s\n",clo.si);
		printf("\t面料:%s\n",clo.ma);
		printf("\t颜色:%s\n",clo.co);
		printf("\t单价:%.2f\n",clo.pr);
		printf("\t数量:%d\n",clo.qu);
	}
}
//read函数的封装,无形参,操作界面里调用 
void reads(){														
	FILE*fp=fopen("clothes.data","r");								//只读方式打开库存信息 
	if(fp){															//如果成功打开 
		fseek(fp,0L,SEEK_END);										//移动到文件末位 
		long size=ftell(fp);										//读取文件末位的数据量 
		int number=size/sizeof(Clothes);							//计算有几条数据 
		int index=0;												//让用户输入查找的服装编号 
		printf("共有%d条数据,输入要检查的服装代码:",number);		
		scanf("%d",&index);											//输入服装编号 
		read(fp,index-1);											//系统分配服装编号为了不出现0号,加了一,因此这里减一 
		fclose(fp);
	}
	getchar();														//scanf后输入了回车,这里接收掉 
	screen();														//回到操作界面 
}
//这里和read基本一样,但是打印的是销售数据 
void sread(FILE*fp,int index){										
	fseek(fp,index*sizeof(Sale),SEEK_SET);
	Sale sal;
	if(fread(&sal,sizeof(Sale),1,fp)==1){
		printf("销售记录编号:%d\n",index+1);
		printf("\t服装代码:%d\n",sal.nu);
		printf("\t销售数量:%d\n",sal.qu);
		printf("\t日期:%s\n",sal.da);
		printf("\t售价:%.2f\n",sal.pr);
		printf("\t小记:%s\n",sal.note);
	}
}
//sread的封装,和reads基本一样 
void sreads(){														
	FILE*fp=fopen("sale.data","r");
	if(fp){
		fseek(fp,0L,SEEK_END);
		long size=ftell(fp);
		int number=size/sizeof(Sale);
		int index=0;
		printf("共有%d条数据,输入要检查的销售记录编号:",number);
		scanf("%d",&index);
		sread(fp,index-1);
		fclose(fp);
	}
	getchar();
	screen();
}
//库存信息添加函数
void add(){															
	int number=0,innumber=0;										//number是用来遍历输入数据的,innumber是系统分配的代码 
	printf("要添加的服装种类数量:");
	scanf("%d",&number);
	Clothes aClo[number];											//建立number个aClo结构体 
	FILE*fp=fopen("clothes.data","r");								//以只读打开库存数据,以下这段代码是为了分配服装代码 
	if(fp){																	
		fseek(fp,0L,SEEK_END);										//移动到文件末尾 
		long size=ftell(fp);										//读取文件长度 
		innumber=size/sizeof(Clothes);								//计算已有的结构体数量 
		fclose(fp);													//关闭文件 
	}
	cgetlist(aClo,number,innumber);									//用getlist获取新库存信息 
	if(!save(aClo,number)){											//保存文件,如果返回-1的话 
		printf("服装入库失败\n");									//打印失败 
	}
	else printf("服装入库成功\n");									//否则打印成功 
	getchar();														//接受scanf输入的回车 
	screen();														//返回操作界面 
}
//销售信息添加函数,和add的实现方式基本一样 
void sadd(){														
	int number=0,innumber=0;
	printf("要添加的销售记录条数:");
	scanf("%d",&number);
	Sale aSal[number];												//建立number个aSal结构体 
	FILE*fp=fopen("sale.data","r");
	if(fp){
		fseek(fp,0L,SEEK_END);										//这段代码作用是读取有多少个数据 
		long size=ftell(fp);										//这样就可以由系统自动分配下一个编号 
		innumber=size/sizeof(Sale);
		fclose(fp);
	}
	if(sgetlist(aSal,number,innumber)==-1){							//如果sgetlist返回-1,说明库存不足 
		printf("^销售信息写入失败\n");
	}
	else{															//如果没有返回-1,调用ssave尝试保存 
		if(!ssave(aSal,number)){									//保存sgetlist输入的aSal结构体 
			printf("*销售信息添加失败\n");							
		}
		else printf("^销售信息添加成功\n");
	} 
	getchar();														//接受scanf输入的回车
	screen();
}
//检查库存是否足够和修改库存,x是服装编号,y是销售数量
int reducecheck(int x,int y){
	FILE*fpr=fopen("clothes.data","r+");							//只读方式打开库存信息 
	if(fpr){						 								//如果成功打开
		Clothes clo[1];												//建立结构体用来接受文件里的数据			 
 		fseek(fpr,(x-1)*sizeof(Clothes),SEEK_SET);					//fp指针移动到指定数据的位置								 
		fread(&clo,sizeof(Clothes),1,fpr);							//读取文件中的数据 
		if(clo[0].qu<y){											//如果库存不足 
			printf("库存不足 ");
			return -1;												//返回-1到getlist,getlist会返回-1到sadd 
		}
		else {									
			printf("\t^^^库存充足\n");			
			clo[0].qu=clo[0].qu-y;									//将clo中的数量值修改为销售后的数量 
			fseek(fpr,(x-1)*sizeof(Clothes),0);						//移动到数据位置 
			fwrite(clo,sizeof(Clothes),1,fpr);						//用aclo覆盖原来的数据 
			fclose(fpr);											//关闭clothes.data,此时sale.data依然打开 
		}
	}													
}
//库存信息修改函数的实现,有形参
void change(FILE*fp,int index){
	Clothes aClo[1];												//建立临时结构体aClo接收数据 
	cgetlist(aClo,1,index);											//用cgetlist写入数据 到aClo 
	fseek(fp,index*sizeof(Clothes),0);								//指针移动到数据位置 
	fwrite(aClo,sizeof(Clothes),1,fp);								//保存aClo到文件中 
}
//库存信息修改函数的封装,无形参
void changes(){
	FILE*fp=fopen("clothes.data","r+");								//只读方式打开库存信息 
	if(fp){															//如果成功打开 
		fseek(fp,0L,SEEK_END);										//移动到文件末位 
		long size=ftell(fp);										//读取文件末位的数据量 
		int number=size/sizeof(Clothes);							//计算有几条数据 
		int index=0;												//让用户输入修改的服装编号 
		printf("共有%d条数据,输入要修改的服装代码:",number);		
		scanf("%d",&index);											//输入服装编号 
		change(fp,index-1);											//调用修改函数,系统分配服装编号时为了不出现0号,加了一,因此这里减一 
		fclose(fp);
	}
	getchar();														//scanf后输入了回车,这里接收掉 
	screen();
}
//删除函数用的getlist
void dcgetlist(Clothes aClo[],int innumber){
	aClo[0].nu=innumber;
	strcpy(aClo[0].name,"此处数据已删除"); 							//为了查找系统正常工作,不清空数据,而是替换为空 
	strcpy(aClo[0].si,"");
	strcpy(aClo[0].ma,"");
	strcpy(aClo[0].co,"");
	aClo[0].pr=0;
	aClo[0].qu=0;
}
//删除函数
void del(FILE*fp,int index){
	Clothes aClo[1];												//建立临时结构体aClo 
	dcgetlist(aClo,index-1);										//将aClo变为删除后的特殊结构体 
	fseek(fp,index*sizeof(Clothes),0);								//指针移动到数据位置 
	fwrite(aClo,sizeof(Clothes),1,fp);								//把aClo写入文件 
}
//删除函数的封装,无形参,操作界面里调用
void dels(){
	FILE*fp=fopen("clothes.data","r+");								//只读方式打开库存信息 
	if(fp){															//如果成功打开 
		fseek(fp,0L,SEEK_END);										//移动到文件末位 
		long size=ftell(fp);										//读取文件末位的数据量 
		int number=size/sizeof(Clothes);							//计算有几条数据 
		int index=0;												//让用户输入删除的服装编号 
		printf("共有%d条数据,输入要删除的服装代码:",number);		
		scanf("%d",&index);											//输入服装编号 
		del(fp,index-1);											//系统分配服装编号为了不出现0号,加了一,因此这里减一 
		fclose(fp);
	}
	getchar();														//scanf后输入了回车,这里接收掉 
	screen();
}
//操作界面函数
int screen(){
	char a;
	printf("N-服装信息登记,M-服装信息修改,R-服装信息查找\n");
	printf("D-服装信息删除,S-服装销售登记,G-销售信息查找\n");
	printf("Q-退出系统\n");
	printf("输入字母来决定操作:");
	scanf("%c",&a);
	switch(a){
		case'N':
			add();
			break;
		case'M':
			changes();
			break;
		case'R':
			reads();
			break;
		case'D':
			dels();
			break;
		case'S':
			sadd();
			break;
		case'G':
			sreads();
			break;
	}																		
}
int main(){
	screen();
}

项目总结(大一时所写原文,未改动)

首先,从结果来看,整个程序并不复杂,结构很简单,但是设计过程中依然碰到了很多问题并严重延长了开发周期,这一方面时体现了对c语言仍然不够熟练,另一方面也表明对程序设计难度的低估。
先来说说几个遇到的问题。首先在还没开始时就犯了难。要如何能够把数据写进文件,还能按原样一个一个读出来呢?又要如何实现查找呢?最早还没开始做时,设想过用链表和二叉树来写,但实际操作才发现文件里实现不了。后来想过用“#”等符号作为分隔符,但是这样好像也很难实现按型号、规格等一条条输出,而且修改很困难。后来通过进一步学习才发现用二进制写入可以实现写入结构体和链表。现在写入的问题解决了,接下来就要解决查找的问题。一开始想法是把文件里内容全部读进内存再用strstr找,但这里也有问题,一是strstr查找精度不高,比如要查找Tom,函数可能找到Toma就返回了。其次,找到之后,要输出接下来的数据也比较难。最终决定,由系统自动分配专门编号,再由这一编号来进行查找、修改和删除等。这一决定也使得之后的销售系统对库存进行修改的操作变得更加简单。
开始的添加和查找函数都比较简单,所以遇到的困难不多。这里有一点,增加函数要么用“w”打开,要么用“a”打开,用w的话,之后再打开文件夹添加库存时,会直接清空以前的文件;而用a打开的话,则无法创建文件夹。最后是设置了一个if语句来判断是否存在文件。修改就有些麻烦了。考虑到删除也可以看作修改,就先从删除函数开始。因为要按照上文的按编号查找的话,是不能直接清空一个结构体的,这样会直接导致后面的编号全部乱掉。所以采取了把数据替换为空字符的做法。这样虽然不能直接减少空间,但考虑到本身就是数据量很小的纯字符数据,所以这样影响也不大。然后就是删除函数的实现。首先肯定不能用w方法打开,这样一打开就什么都没了。然后用过用a打开,结果即使用fseek把指针移动到指定位置,也只能写到文件末尾。最后发现,用“r+”方法打开就可以实现覆盖到指定位置。之后还犯了一个小错误,直接把新字符串=原字符串,结果出现了乱码。然后才发现要用strcpy函数。解决了删除函数之后,修改函数也就不难了,只需要把删除里面的空白结构体换成用户输入结构体即可。
然后是销售管理部分。添加和查找销售记录都比较简单,和上面一样,只要修改一下结构体就可以。但涉及到和库存函数的通信,就有些麻烦了。当我们输入完服装编号和销量后,就应该立刻判断是否库存不够,如果不够就立即弹出信息并返回;同时输入的数据也要及时清除,防止混进下一次输入造成乱码。于是这里用了一个检测函数,并且可以直接return退出。但是这个检测函数也没那么简单,碰到了很多麻烦。同时检测函数也要担负把销售后剩余库存信息写进库存文件的功能。最终的解决办法是,再检测函数里用另一个文件指针打开库存文件,读取这里的信息,检测是否库存足够,足够的话就把原有信息修改后,覆盖到原来的位置。
最后是操作界面函数。以上的函数都能正常工作,但是放到switch里面时,要么不能打开,要么直接退出,要么显示两次操作界面。最后发现,每个函数都要用scanf输入数据,这个过程会往缓冲区里写入一个回车符,随后它就直接输入到了操作界面,这就引发了上面的诸多问题。最后的解决办法是往每个函数末尾添加了一个getchar()来接收回车符。
通过这个项目的编写,认识到了以下几个点:

  1. 对C语言的很多操作,尤其是对文件的操作,其实还并不了解。此外,用等号给字符数组赋值的错误操作也出现了。
  2. C++的确是对C语言的非常重要的扩展。例如String类,就可以直接用等号赋值;更重要的是,上面的服装信息系统和销售信息系统本质上非常相似,其实完全可以用类来实现。以及一些函数,只是一些参数有变化,应该也可以用模板函数实现。
  3. 数据库是非常伟大的发明。用C自带的文件通讯还是比较麻烦的,而且经常会有一些错误操作导致数据损坏。用数据库的话,不仅可以方便的储存一些更高级的数据结构,同时在一些方面也更安全。

相关文章:

  • 深入探讨分布式ID生成方案
  • ES脚本启动报错修改
  • 新能源汽车推行精益生产:绿色动力下的效率革命
  • Java常规题技术分享
  • 单实例11.2.0.4迁移到11.2.0.4RAC_使用rman异机恢复
  • 新手教程之使用LLaMa-Factory微调LLaMa3
  • 【MATLAB】概述1
  • 富格林:揭露黑幕平台保障安全
  • C++ 混合运算的类型转换
  • 读书-《蛤蟆先生去看心理医生》
  • 从1.0到4.0,看看你公司的费控模式是第几代?
  • Vitis HLS 学习笔记--控制驱动与数据驱动混合编程
  • 常见排序算法之选择排序
  • python之生成器表达式
  • 数字水印 | 附彩色图像论文:盲式水印嵌入的方法
  • 汽车软件单元测试分析
  • 当没用git工具是怎么快速下载项目
  • 2024年5月个人工作生活总结
  • Mac电脑重置网络命令
  • 多语言for循环遍历总结
  • 公示!17个新职业、42个新工种亮相
  • 明查|这是“C919迫降在农田”?实为飞机模型将用于科普体验
  • 湖北奥莱斯轮胎公司逃避监管排放大气污染物被罚25万元
  • 经济日报:落实落细更加积极的财政政策
  • 人民日报评论:莫让“胖东来们”陷入“棒杀”“捧杀”泥潭
  • 国际上首次,地月空间卫星激光测距试验在白天成功实施