在电子科大的第一次教学之实验5
问题集萃
简而言之,问题都不是内涵,都是些外围的东西。
附上我试验五完整代码
-
结构化程序设计
-
老师对这个概念已经说过很多次了,但是至今我们还是不理解。像
scanf("%d",&choice); switch (choice){ case 1:Out_Put(); break; case 2:Info_Change(); break; case 3:Info_Insert(); break; case 4:Info_Dele(); break; case 5:Info_Search(); break; case 6:Info_Flush();Free_Info();exit(0); break; default:Free_Info();exit(0); break; }
这种一看就没有做到结构化设计。因为函数的实参是空的,返回值也是空的。这说明什么?函数没有做到高内聚松耦合,这就意味着一个函数做了太多事情。违背了 一个函数只做一件事 的原则。这样函数维护起来的成本就很高了。
-
解决办法:一个函数做一件事,尽量不要在函数里面有scanf和printf。除非是专门的输出函数。
int Search(int searchNumber, GoodsInfoBase *pGoodsInfoBase) { int i, ret = -1; for (i = 0; i < pGoodsInfoBase->partNum; i++) { if (pGoodsInfoBase->pGoodsInfoBase[i]->number == searchNumber) { ret = i; break; } } return ret; } ...... Status PrintInfoOfAPart(int i, GoodsInfoBase *pGoodsInfoBase) {//专门的输出函数 printf(" %d\t\t%s\t\t%d\t\t\t%g\n", pGoodsInfoBase->pGoodsInfoBase[i]->number, pGoodsInfoBase->pGoodsInfoBase[i]->partName, pGoodsInfoBase->pGoodsInfoBase[i]->onHand, pGoodsInfoBase->pGoodsInfoBase[i]->price); return OK; } ...... case 's': printf("Enter part number: "); scanf("%d", &searchNumber); i = Search(searchNumber, &goodsInfoBase); if (i >= 0) { PrintInfoOfAPart(i, &goodsInfoBase); } else { printf("Part not found.\n"); } break;
提示:如果只想及格的话就没有必要做到这么严格,简洁一点反而看着舒服。
-
-
不要有全局变量表示商品的种类数。
原因:这个不太好讲清楚。以我的经验看,以前我也是用的全局变量,
但是在代码完全没报错的情况下,总是会出错。后来不用全局变量后就行了。-
解决办法:再建一个结构,这个结构里面包含 一个包含所有商品信息的结构数组(或指针数组)
和 商品的种类。代码如下所示:typedef struct { int number; char partName[MAX_LEN + 1]; int onHand; float price; } Part; typedef struct { Part *pGoodsInfoBase[MAX_GOODS]; int partNum; } GoodsInfoBase;
提示:就算你要用全局变量,也只需要在代码一开始定义一次就好了,没必要在每个函数中又重复定义
-
要注意语句间的对应关系
- 比如:函数定义和函数调用中的形参和实参的类型要一致,比如不能一个是结构类型,一个是指针类型。如下:
typedef struct goodsBase{ goodInfo goods[MAX]; int numOfGoods; }goodsBase; ...... goodInfo *ReadGoodInfo(FILE *pf){ goodInfo *pGoodInfo = (goodInfo *)malloc(sizeof(goodInfo)); fscanf(pf,"%s",pGoodInfo->producingDate); fscanf(pf,"\t%s",pGoodInfo->name); fscanf(pf,"\t%s",pGoodInfo->price); fscanf(pf,"\t%s",pGoodInfo->discount); return pGoodInfo; } ...... pGoodsBase->goods[j] = ReadGoodInfo(pf);
- 比如:函数定义和函数调用中的形参和实参的类型要一致,比如不能一个是结构类型,一个是指针类型。如下:
-
注意正确找到库函数来使用
- 原因:库函数的意义就在于可以减少我们的开发成本。能熟悉库函数自然对我们十分有帮助。比如:
我们本意是想把一个字符串赋给另一个字符数组,但是这种写法虽然人看得明白,但是机器不明白。既然它是字符串的操作,所以我们应该想到<string.h>这个头文件。当我们去找时,会发现strcpy()这个函数刚好满足需求。productInfoBase.pProductArray[i]->name = newName;
strcpy(productInfoBase.pProductArray[i]->name,newName);
- 原因:库函数的意义就在于可以减少我们的开发成本。能熟悉库函数自然对我们十分有帮助。比如:
-
隐藏的错误(编译器不会报错)
-
文件名不是
GoodsInfoBase.txt
而是应该包含路径。比如:
D:\GoodsIfoBase.txt
除非你的文件和程序文件在同一个目录。
-
对于字符串数组,定义的时候一定要
char name[MAX+1];
这个 +1 一定不要少。这是规范问题,虽然不加而出错的概率比较小。原因我就不解释。
-
scanf、fscanf等时,普通变量(char,int,float等)类型要用&,而数组用数组名就行,指针的话用*p.例如:
fscanf(pProductFile, "%d\t%s\t%f\t", &(productInfoBase.pProductArray[i]->amount), productInfoBase.pProductArray[i]->name, &(productInfoBase.pProductArray[i]->price));
-
申请指针后一定要记得让指针指向一块内存(或变量)
-
原因:很多人都容易犯这样的错误,在申请指针后没让指针指向一块内存(或变量),就马上对指针进行操作。正确做法:
int a=9; int *p; p=&a;//不可缺 printf("%d",*p);
int *p; p=(int*)malloc(sizeof(int));//不可缺 if(p==NULL){ return ERROR; } *p=9; printf("%d",*p);
-
-
-
注意 C89 和 C99 的区别
- Cfree上是只支持C89的,如果在你的电脑上的编译器能运行的程序在cfree上不一定能运行。这里涉及到的最典型的例子就是bool类型。在C99中,只要
就行。但是在C89中,你就必须#include<stdbool.h>
才行。typedef enum{YES=1,NO=0}Bool
- Cfree上是只支持C89的,如果在你的电脑上的编译器能运行的程序在cfree上不一定能运行。这里涉及到的最典型的例子就是bool类型。在C99中,只要
-
实验五具体几个函数的实现小细节
- delete函数不能仅仅对结构free一下就完事了。如果这样的话,你会发现在显示所有商品信息的操作中,显示到你刚刚删除的商品就停止了,还很可能直接退出程序。
- 解决方案:如果是结构数组的话,就把删掉的那个结构后面的结构都向前挪一个位置;如果是指针数组的话,就把从你free的那个指针开始,每一个指针指向后面一个结构,最后一个指针再赋空。
- 在插入函数中,有时候会出现输入完编号后,后面的输入名字操作还没有做就调到下一个操作了。比如:
你输完part number后就直接跳过part name了。原因在于你输完part number读完part number后键盘缓冲区还剩一个 \n .所以下一个scanf就把换行符读了。printf("Enter part number: "); scanf("%d", &NewPart.number); printf("Enter part name: "); gets(NewPart.partName); printf("Enter quantity on hand: "); scanf("%d", &NewPart.onHand); printf("Enter price: "); scanf("%f", &NewPart.price);
- 解决方法: fflush()函数。它可以用来清除键盘缓冲区的内容。对应要使用<io.h>这个头文件。实现如下:
这个函数还有其他用处。比如在printf("Enter part number: "); scanf("%d", &NewPart.number); fflush(stdin); printf("Enter part name: "); gets(NewPart.partName); printf("Enter quantity on hand: "); scanf("%d", &NewPart.onHand); printf("Enter price: "); scanf("%f", &NewPart.price);
中,如果不小心在while(1){ scanf("%d",&choice); switch (choice){ case 1:Out_Put(); break; case 2:Info_Change(); break; case 3:Info_Insert(); break; case 4:Info_Dele(); break; case 5:Info_Search(); break; case 6:Info_Flush();Free_Info();exit(0); break; default:Free_Info();exit(0); break; } }
时输入了一大串东西,就会出现重复多次报错的情况。scanf("%d",&choice);
- 解决方案:
while(1){ scanf("%d",&choice); switch (choice){ case 1:Out_Put(); break; case 2:Info_Change(); break; case 3:Info_Insert(); break; case 4:Info_Dele(); break; case 5:Info_Search(); break; case 6:Info_Flush();Free_Info();exit(0); break; default:Free_Info();exit(0); break; } fflush(stdin); }
- 解决方案:
- 解决方法: fflush()函数。它可以用来清除键盘缓冲区的内容。对应要使用<io.h>这个头文件。实现如下:
- delete函数不能仅仅对结构free一下就完事了。如果这样的话,你会发现在显示所有商品信息的操作中,显示到你刚刚删除的商品就停止了,还很可能直接退出程序。
总结
好了,就先讲到这把,好累了,明天上午还要上课。拜拜。最后送你们一张我老婆的壁纸!哇,精神瞬间充沛!衣带渐宽终不悔,为C消得人憔悴