美文网首页
在电子科大的第一次教学之实验5

在电子科大的第一次教学之实验5

作者: crabor | 来源:发表于2018-01-02 00:12 被阅读0次

在电子科大的第一次教学之实验5

问题集萃

简而言之,问题都不是内涵,都是些外围的东西。
附上我试验五完整代码

  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和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;
      
    • 提示:如果只想及格的话就没有必要做到这么严格,简洁一点反而看着舒服。

  2. 不要有全局变量表示商品的种类数。

    • 原因:这个不太好讲清楚。以我的经验看,以前我也是用的全局变量,
      但是在代码完全没报错的情况下,总是会出错。后来不用全局变量后就行了。

    • 解决办法:再建一个结构,这个结构里面包含 一个包含所有商品信息的结构数组(或指针数组)
      和 商品的种类。代码如下所示:

       typedef struct {
       int number;
       char partName[MAX_LEN + 1];
       int onHand;
       float price;
       } Part;
      
       typedef struct {
       Part *pGoodsInfoBase[MAX_GOODS];
       int partNum;
       } GoodsInfoBase;
      
    • 提示:就算你要用全局变量,也只需要在代码一开始定义一次就好了,没必要在每个函数中又重复定义

  3. 要注意语句间的对应关系

    • 比如:函数定义和函数调用中的形参和实参的类型要一致,比如不能一个是结构类型,一个是指针类型。如下:
      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);
      
  4. 注意正确找到库函数来使用

    • 原因:库函数的意义就在于可以减少我们的开发成本。能熟悉库函数自然对我们十分有帮助。比如:
      productInfoBase.pProductArray[i]->name = newName;
      
      我们本意是想把一个字符串赋给另一个字符数组,但是这种写法虽然人看得明白,但是机器不明白。既然它是字符串的操作,所以我们应该想到<string.h>这个头文件。当我们去找时,会发现strcpy()这个函数刚好满足需求。
      strcpy(productInfoBase.pProductArray[i]->name,newName);
      
  5. 隐藏的错误(编译器不会报错)

    1. 文件名不是

      GoodsInfoBase.txt

      而是应该包含路径。比如:

      D:\GoodsIfoBase.txt

      除非你的文件和程序文件在同一个目录。

    2. 对于字符串数组,定义的时候一定要

      char name[MAX+1];
      

      这个 +1 一定不要少。这是规范问题,虽然不加而出错的概率比较小。原因我就不解释。

    3. 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));
      
    4. 申请指针后一定要记得让指针指向一块内存(或变量)

      • 原因:很多人都容易犯这样的错误,在申请指针后没让指针指向一块内存(或变量),就马上对指针进行操作。正确做法:

         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);
        
  6. 注意 C89C99 的区别

    • Cfree上是只支持C89的,如果在你的电脑上的编译器能运行的程序在cfree上不一定能运行。这里涉及到的最典型的例子就是bool类型。在C99中,只要
      #include<stdbool.h>
      
      就行。但是在C89中,你就必须
      typedef enum{YES=1,NO=0}Bool
      
      才行。
  7. 实验五具体几个函数的实现小细节

    1. delete函数不能仅仅对结构free一下就完事了。如果这样的话,你会发现在显示所有商品信息的操作中,显示到你刚刚删除的商品就停止了,还很可能直接退出程序。
      • 解决方案:如果是结构数组的话,就把删掉的那个结构后面的结构都向前挪一个位置;如果是指针数组的话,就把从你free的那个指针开始,每一个指针指向后面一个结构,最后一个指针再赋空。
    2. 在插入函数中,有时候会出现输入完编号后,后面的输入名字操作还没有做就调到下一个操作了。比如:
      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);
      
      你输完part number后就直接跳过part name了。原因在于你输完part number读完part number后键盘缓冲区还剩一个 \n .所以下一个scanf就把换行符读了。
      • 解决方法: 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);
          }
          

总结

衣带渐宽终不悔,为C消得人憔悴

好了,就先讲到这把,好累了,明天上午还要上课。拜拜。最后送你们一张我老婆的壁纸!哇,精神瞬间充沛! 我老婆

相关文章

网友评论

      本文标题:在电子科大的第一次教学之实验5

      本文链接:https://www.haomeiwen.com/subject/kwwxnxtx.html