面向對象程序設計寒假作業2編程題


這個作業屬於哪個課程 2020年面向對象程序設計 (福州大學 - 數學與計算機科學學院)
這個作業要求在哪里 面向對象程序設計寒假作業2
這個作業的目標 1.繼續完成編程題。
2.新建一個github倉庫,並把作業推送到該倉庫。
3.發布博客。
作業正文 面向對象程序設計寒假作業2實踐題
面向對象程序設計寒假作業2編程題
Mac下Shell腳本使用學習筆記(一)
Mac下Shell腳本使用學習筆記(二)
其他參考文獻 Macbook中使用Vim和GCC編譯C程序
c語言中所有文件操作函數詳解
C語言命令行參數詳解
freopen()函數的使用

編程題

1.題目要求:

(1)繼續完成作業一的編程題。
(2)優化架構,一般要求每個函數長度不超過15行。
(3)優化規范,尤其是命名規范。
(4)制作一個編譯腳本,運行該腳本可以編譯你的代碼,可選的腳本語言,python(2.7),windows批處理,powershell,shell。
(5)進行單元測試,即測試每一個函數,並制作一個測試腳本,運行該腳本可以進行測試,並顯示測試結果。
(6)添加以下功能:通過命令行讀取一個文件,然后運行這個文件。如我的程序叫lang,lang 1.txt代表我要運行1.txt這個文本中的代碼

2.分解需求:

(1)對代碼進行進一步優化:

①首先,我注意到在上次編程題的代碼中,在一下這兩個函數中,其功能存在重復贅余:

int beginning(int wallet,char d[]){
    if(strcmp(d,"零")==0) return 0;
    else if(strcmp(d,"一")==0) return 1;
    else if(strcmp(d,"二")==0) return 2;
    else if(strcmp(d,"三")==0) return 3;
    else if(strcmp(d,"四")==0) return 4;
    else if(strcmp(d,"五")==0) return 5;
    else if(strcmp(d,"六")==0) return 6;
    else if(strcmp(d,"七")==0) return 7;
    else if(strcmp(d,"八")==0) return 8;
    else if(strcmp(d,"九")==0) return 9;
    else if(strcmp(d,"十")==0) return 10;
    else return -1;
}
int calculate(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

作業一中之所以,將其分為兩個函數是因為,第一個beginning函數其作用在於為變量“錢包”作初始化的作用,而第二個 calculate函數,是執行錢包總額增減的功能。但是,這兩個函數在本質上起的是相同的作用,初始化函數也可以等同於對錢包的總額進行增減,故此我將這兩個函數進行合並,並更名為change,其作用為對錢包總額的變化,代碼如下:

int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

當然,相應的在主函數中,調用函數部分也會有相應的變化(代碼見后)。
②然后,我在想,對於輸出錢包總額時,我原先采用了三分支判斷結構,是否可以進行修改使代碼更簡潔呢?
原如下代碼:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else if(wallet<20){
        a=wallet%10;
        printf("十");
        num(a);
    }
    else{
        a=wallet/10;
        b=wallet%10;
        num(a);
        printf("十");
       if(b!=0) num(b);
    }
}

然后我嘗試把后兩個分支合並,代碼如下:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=0)num(a);//注意修改前的這一步
        printf("十");
       if(b!=0) num(b);
    }
}

我按照我修改后的代碼嘗試了三種情況,如下:



前兩種按照中文習慣是不存在任何問題的,但是第三種出現六問題,因為按照中文習慣,當錢包總額為17時,應該輸出十七,而不是一十七。注意到,我在上一段代碼作出的標記:

if(a!=0)num(a);

所以我改變了,這個判斷語句a的條件,目的是為了當a=1時,其沒有輸出,故代碼為:

void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1)num(a);//注意修改后的這一步
        printf("十");
       if(b!=0) num(b);
    }
}

驗證結果(如下),發現答案正確:

③然后,我開始解決主函數的一些判斷問題:
原代碼如下:

int main() {
    char a[100],b[100],c[100],d[100];
    int wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整數")!=0||strcmp(c,"等於")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                sum(wallet);
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"減少")==0) wallet-=change(wallet,d);
        }
    }
   return 0;
}

當初,由於時間關系,我忽略了一個問題就是,如果我在第一次輸入變量名為錢包后,在進行錢包總額的增減時,如果我輸入的是其他變量名,那其總額仍會進行變化嗎,於是我進行了測試:發現程序會結束,原來之前已經考慮過了這種情況,好吧,有點白費功夫了
④最后,優化規范,我對一些不規范對命名的調整,總代碼如下:

#include <stdio.h>
#include <string.h>
int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}
void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void printf_sum(int wallet){
    int a,b;
    if(wallet<=10) num(wallet);
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1) num(a);
        printf("十");
        if(b!=0) num(b);
    }
}
int main() {
    char a[100],b[100],c[100],d[100];
    int wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整數")!=0||strcmp(c,"等於")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                printf_sum(wallet);//這里重新命名函數,使代碼更加易讀
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"減少")==0) wallet-=change(wallet,d);
        }
    }
   return 0;
}

待解訣問題:仍然只能進行零至十的賦值,將在下一階段進行思考和改進。
由於個人的力量是有限的,所以希望大家,可以對我的代碼提出進一步對改進建議,或者你的看法。

(2)制作一個編譯腳本,運行該腳本編譯代碼(學習筆記已在鏈接標出):

shell代碼如下:

#!/bin/bash

 echo -n "請輸入需要編譯的文件名:"
read compile_file
 gcc $compile_file -o test1.out
 ./test1.out

結果如下:

之后,為了使一運行腳本便可編譯代碼,作出了修改,代碼如下:

#!/bin/bash

 gcc main.c -o test1.out
 ./test1.out

結果如下:

然后,我又參考了沈歡同學的作業,進行進一步完善了腳本,增加了一個判斷,用於辨別是否成功編譯。代碼如下:

#!/bin/bash

 gcc main.c -o test1.out
 if [ $? == 0 ]  # $?顯示最后命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤。
 then
     echo "編譯成功"
     ./test1.out
     if [ $? == 0 ]
     then
         echo "運行結束"
     else
         echo "運行失敗"
     fi
 else
     echo "編譯失敗"
 fi

結果如下:

需要注意的是,當我們在使用腳本編譯代碼的時候,需要將代碼文件與腳本放在一個文件夾中,否則會出現以下情況:

(3)進行單元測試,並制作一個測試腳本,運行並顯示結果:

這個地方,理解了半天,后面參考了提交的同學的博客和詢問了同學,我才明白什么意思(非常感謝)
注意到我的代碼中總共有三個函數,而后面兩個num函數與printf_sum函數皆為輸出函數,負責直接輸出結果,因此這兩個函數的測試我們可以在結果中看到,因此這里只需測試chang函數:

//main.h
#include <stdio.h>
#include <string.h>
int change(char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}

測試部分代碼:

#include "main.h"
void judge_change(int number_actual,int number_example){
    if(number_actual==number_example) printf("Pass\n");
    else printf("Fail\n");
}
void test_change(){
     printf("test_change begins\n");
    judge_change(change("零"),0);
    judge_change(change("一"),1);
    judge_change(change("二"),2);
    judge_change(change("三"),3);
    judge_change(change("四"),4);
    judge_change(change("五"),5);
    judge_change(change("六"),6);
    judge_change(change("七"),7);
    judge_change(change("八"),8);
    judge_change(change("九"),9);
    judge_change(change("十"),10);
    judge_change(change("二十"),-1);
    printf("test_change is over\n");
}

int main() {
    test_change();
   return 0;
}

按照(2)的步驟,我們建立相應的腳本文件,腳本代碼如下:

#!/bin/bash

 gcc main.c -o test2.out
 if [ $? == 0 ]
 then
     echo "編譯成功"
     ./test2.out
     if [ $? == 0 ]
     then
         echo "運行結束"
     else
         echo "運行失敗"
     fi
 else
     echo "編譯失敗"
 fi

打開終端進行測試,結果如下:

Change 函數測試過后,我們來通過結果查看其他兩個函數的正誤:


以上就是測試部分的內容,感謝沈歡同學的幫助。

(4)添加功能:過命令行讀取一個文件,然后運行這個文件

一看到題目疑惑不解,當學完shell后還以為就是Shell 文件包含重定向,后面發現並不是,這樣,查了資料(鏈接已貼出)發現原來在我們c語言課本最后一章中有提到過對文件對操作(當初老師沒教,而且考試也不考,就沒看細看這一章,可是這次放假書放學校了,等回學校的時候再好好看看書)。以下是我的代碼:

//main.h
#include <stdio.h>
#include <string.h>
int change(int wallet,char d[]){
      if(strcmp(d,"零")==0) return 0;
      else if(strcmp(d,"一")==0) return 1;
      else if(strcmp(d,"二")==0) return 2;
      else if(strcmp(d,"三")==0) return 3;
      else if(strcmp(d,"四")==0) return 4;
      else if(strcmp(d,"五")==0) return 5;
      else if(strcmp(d,"六")==0) return 6;
      else if(strcmp(d,"七")==0) return 7;
      else if(strcmp(d,"八")==0) return 8;
      else if(strcmp(d,"九")==0) return 9;
      else if(strcmp(d,"十")==0) return 10;
      else return -1;
}
void num(int i){
    if(i==0) printf("零");
    else if(i==1) printf("一");
    else if(i==2) printf("二");
    else if(i==3) printf("三");
    else if(i==4) printf("四");
    else if(i==5) printf("五");
    else if(i==6) printf("六");
    else if(i==7) printf("七");
    else if(i==8) printf("八");
    else if(i==9) printf("九");
    else if(i==10) printf("十");
}
void printf_sum(int wallet){
    int a,b;
    if(wallet<=10){num(wallet);}
    else{
        a=wallet/10;
        b=wallet%10;
        if(a!=1)num(a);
        printf("十");
       if(b!=0) num(b);
    }
}
void test(){  //注意把原代碼的main函數改名,便於后續引用。
    char a[100],b[100],c[100],d[100];
    int  wallet=0,i,flag=0;
    scanf("%s %s %s %s",a,b,c,d);
    if(strcmp(a,"整數")!=0||strcmp(c,"等於")!=0) flag=1;
    for(i=1;flag==0;i++){
        if(i==1) wallet=change(wallet,d);
        else {
            scanf("%s",a);
            if(strcmp(a,b)!=0&&strcmp(a,"看看")!=0) break;
            scanf("%s",c);
            if(strcmp(a,"看看")==0){
                printf_sum(wallet);
                break;}
            scanf("%s",d);
         if(strcmp(c,"增加")==0) wallet+=change(wallet,d);
         if(strcmp(c,"減少")==0) wallet-=change(wallet,d);
        }
    }
    printf("\n");
}

//main.c
#include "main.h"
//argc:命令行傳入參數的總個數
//argv:*argv[]是一個指針數組,里面存放的指針指向所有的命令行參數,argv[0]指向程序的全局路徑,argv[1]指向在DOS命令行中執行程序名后的第一個字符串,argv[2]指向第二個。
int main(int argc,char * argv[]) {
    if(argc>1){
    //當argc = 1的時候,表示只有一個程序名稱;當argc>1時,說明文本的內容已經輸入其中。
    freopen(argv[1],"r",stdin);
    //FILE *freopen(文件名,文件打開的模式,一個文件,通常使用標准流文件);
    //"r"代表"只讀"
  //准流文件具體是指stdin、stdout和stderr。其中stdin是標准輸入流,默認為鍵盤;stdout是標准輸出流,默認為屏幕;stderr是標准錯誤流,一般把屏幕設為默認。
    test();
    }
    //把緩沖區內最后剩余的數據輸出到內核緩沖區,並釋放文件指針和有關的緩沖區
    return 0;
}

然后通過終端將其編譯為test,然后執行文本(注意在執行文本時需把文本與編譯后的程序放在一個文件夾中):

對應文本內容為:


輸出答案正確,添加功能成功。

3.疑惑及解決

* 本次作業將代碼進行了進一步的優化,但仍存在一個問題待解決:對於錢包總額的變化仍然只能在*零至十*中進行,在下一階段中將着重解決輸入如“二十二”、“三十”的功能等實現 * 本次作業還學習了如何進行函數測試,了解了如何寫腳本。對於單元測試,看到沈歡同學的博客中提到了*單元測試工具CUnit*,准備下一階段中,進行學習。 * 本次作業還學習了github倉庫的使用,將在下一階段中借助作業EX進行深度學習。 * 本次作業還學習了如何通過c語言進行對文件的操作,以后也可將其進一步語言應用。有一個疑問:如果這一題我采用shell腳本中的文件包含重定向功能解決,應該也可以起到相似的功能,那么這兩者有什么區別嗎? * 將在下一階段中學習c++,進一步了解課程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM