面向對象程序設計2020第一次作業
這個作業屬於哪個課程 | 2020面向對象程序設計張棟班 |
---|---|
這個作業要求在哪里 | 寒假作業2 |
這個作業的目標 | 完善代碼、新建GitHub倉庫並上傳代碼、制作編譯腳本、進行單元測試並制作測試腳本、添加文件讀取功能 |
作業正文 | 第二次作業 |
其它參考文獻 | git教程 |
shell教程 | |
執行腳本的三種方式 | |
C語言命令行參數的使用 | |
C語言文件操作 | |
git和GitHub教程 |
注: 系統是Mac OS
實踐題
-
創建SSH Key
-
新建倉庫
-
clone到本地
-
其中倉庫地址從這里復制
- 創建.gitignore文件,配置后傳到倉庫(具體配置到gitignore模版找自己需要的,再復制組合到自己的.gitignore文件中)
- 將代碼放到該文件夾后傳到倉庫
- push時如果出現問題,可參考下圖
編程題
一、優化代碼
- 能夠輸入兩位數三位數,如“二十”,“三十三”。具體實現在processStringToInt函數。
- 分為幾個函數,使含義更清晰,可讀性提高
int convertToInt(char str[]);// 中文轉為數字
char* convertToString(int n);// 數字轉為中文
void error(void);//輸出錯誤
void execute(void);// 執行
int processStringToInt(char number[]);// 在convertToInt函數的基礎上,實現處理兩位數和三位數中文
void printResult(int n); // 輸出結果
- 優化后完整代碼
//main.h
#ifndef UNTITLED_MAIN_H
#define UNTITLED_MAIN_H
#include <stdio.h>
#include <string.h>
typedef struct variable
{
char name[1000];
int value;
} var;
int convertToInt(char str[]);// 中文轉為數字
char* convertToString(int n);// 數字轉為中文
void error(void);//輸出錯誤
void execute(void);// 執行
int processStringToInt(char number[]);// 在convertToInt函數的基礎上,實現處理兩位數和三位數中文
void printResult(int n); // 輸出結果
#endif //UNTITLED_MAIN_H
// main.c
#include "main.h"
int main()
{
char integer[6];
scanf("%s",integer);
if(strcmp(integer,"整數")){ // 判斷第一個詞是否為“整數”
error();
}
else{
execute();//執行
}
return 0;
}
//error.c
#include "main.h"
void error()
{
printf("格式錯誤\n");
}
// convertToInt.c
#include "main.h"
int convertToInt(char str[])
{
if(!strcmp(str,"零")) return 0;
else if(!strcmp(str,"一")) return 1;
else if(!strcmp(str,"二")) return 2;
else if(!strcmp(str,"三")) return 3;
else if(!strcmp(str,"四")) return 4;
else if(!strcmp(str,"五")) return 5;
else if(!strcmp(str,"六")) return 6;
else if(!strcmp(str,"七")) return 7;
else if(!strcmp(str,"八")) return 8;
else if(!strcmp(str,"九")) return 9;
else if(!strcmp(str,"十")) return 10;
else return -1;
}
//convertToString.c
char* convertToString(int n)
{
if(n == 0) return "零";
else if(n == 1) return "一";
else if(n == 2) return "二";
else if(n == 3) return "三";
else if(n == 4) return "四";
else if(n == 5) return "五";
else if(n == 6) return "六";
else if(n == 7) return "七";
else if(n == 8) return "八";
else if(n == 9) return "九";
else if(n == 10) return "十";
else return "Error";
}
//execute.c
#include "main.h"
void execute()
{
var a;
char name[1000],operator[6],number[8];
scanf("%s%s%s",a.name,operator,number);
if(strcmp(operator,"等於")){
error();
}
else{
if(processStringToInt(number) == -1) error();
else {
a.value = processStringToInt(number); //賦初始值
scanf("%s", name);
//循環執行到某行首個字符串不是變量名
while (!strcmp(name, a.name)) {
scanf("%s%s", operator, number);
if (!strcmp(operator, "增加")) {
a.value += processStringToInt(number);
} else if (!strcmp(operator, "減少")) {
a.value -= processStringToInt(number);
} else {
error();
break;
}
scanf("%s", name);
}
if (!strcmp(name, "看看")) {
scanf("%s", name);
if (!strcmp(name, a.name))//“看看”后面輸入的內容得和前面的變量名稱相同
{
printResult(a.value);
} else {
printf("不存在此變量\n");
}
}
}
}
}
//processStringToInt.c
#include "main.h"
int processStringToInt(char number[])
{
char str1[3],str2[3],str3[3];
int sum = 0;
strncpy(str1,number,2);
str1[2] = '\0';
sum = convertToInt(str1);
if(strlen(number) == 4)//輸入兩位數中文
{
strncpy(str2,number+2,2);//從number字符串的第三個字符number[2]開始復制
str2[2] = '\0'; //結尾要加\0,否則會出錯
if(convertToInt(str2) == 10)
sum = convertToInt(str2) * convertToInt(str1);//大於10且為十的整數倍
else if(convertToInt(str2) != -1)
sum = convertToInt(str2) + convertToInt(str1); //十一到十九
else
sum = -1;
}
if(strlen(number) == 6)//輸入三位數中文
{
strncpy(str3,number+4,2);
str3[2] = '\0';
sum = convertToInt(str1)*10 + convertToInt(str3); // 二十一~九十九(不包括十的整數倍)
}
return sum;
}
//printResult.c
#include "main.h"
void printResult(int n)
{
if(n <= 10)
{
printf("%s",convertToString(n));
}
else if(n % 10 == 0 && n < 100)
{
printf("%s十",convertToString(n/10));//十的整數倍輸出為幾十而不是幾零
}
else if(n < 20)
{
n %= 10;
printf("十%s",convertToString(n));//輸出十幾而不是一十幾
}
else if(n < 100)
{
printf("%s十%s",convertToString(n/10),convertToString(n%10));
}
else
{
printf("變量數值超出范圍");
}
}
二、編譯腳本
- 代碼如下,所使用腳本語言為shell
#!/bin/bash
fileName=$1 #注意不能有空格 #$0指此文件名 $1指運行此文件時的第一個參數名,也就是要編譯的文件名
echo "開始編譯......"
gcc $fileName -o result.out # 使用一個定義過的變量,只要在變量名前面加美元符號$即可
if [ $? == 0 ] # $? 顯示最后命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤。
then #注意中括號周圍的空格
echo "編譯成功......"
echo "開始運行......"
./result.out
if [ $? == 0 ]
then
echo "運行結束......"
else
echo "運行失敗......"
fi
else
echo "編譯失敗......"
fi
- 實現效果
三、 單元測試
- 一開始理解錯意思了,花了好長時間學了個單元測試工具CUnit,直到助教在群里說才知道是我想多了,
當場死亡
- 首先測試三個轉換函數(test.c作了修改,感謝分享)
//test.c
#include "main.h"
void assert_str_equals(const char *actual, const char *expected)
{
if (!strcmp(actual, expected))
printf("Pass\n");
else
printf("Failed. actual: %s, expected: %s\n", actual, expected);
}
void assert_int_equals(int actual, int expected)
{
if (actual == expected)
printf("Pass\n");
else
printf("Failed. actual: %d, expected: %d\n", actual, expected);
}
void test_convertToString()
{
printf("test_convertToString 開始----------\n");
assert_str_equals(convertToString(0),"零");
assert_str_equals(convertToString(1),"一");
assert_str_equals(convertToString(2),"二");
assert_str_equals(convertToString(3),"三");
assert_str_equals(convertToString(4),"四");
assert_str_equals(convertToString(5),"五");
assert_str_equals(convertToString(6),"六");
assert_str_equals(convertToString(7),"七");
assert_str_equals(convertToString(8),"八");
assert_str_equals(convertToString(9),"九");
assert_str_equals(convertToString(10),"十");
assert_str_equals(convertToString(11),"Error");
assert_str_equals(convertToString(21),"Error");
printf("test_convertToString 結束----------\n");
}
void test_convertToInt()
{
printf("test_convertToInt 開始----------\n");
assert_int_equals(convertToInt("零"), 0);
assert_int_equals(convertToInt("一"), 1);
assert_int_equals(convertToInt("二"), 2);
assert_int_equals(convertToInt("三"), 3);
assert_int_equals(convertToInt("四"), 4);
assert_int_equals(convertToInt("五"), 5);
assert_int_equals(convertToInt("六"), 6);
assert_int_equals(convertToInt("七"), 7);
assert_int_equals(convertToInt("八"), 8);
assert_int_equals(convertToInt("九"), 9);
assert_int_equals(convertToInt("十"), 10);
assert_int_equals(convertToInt("百"), -1);
assert_int_equals(convertToInt("十一"), -1);
printf("test_convertToInt 結束----------\n");
}
void test_pcocessStringToInt()
{
printf("test_pcocessStringToInt開始----------\n");
assert_int_equals(processStringToInt("零"), 0);
assert_int_equals(processStringToInt("六"), 6);
assert_int_equals(processStringToInt("十一"), 11);
assert_int_equals(processStringToInt("二十"), 20);
assert_int_equals(processStringToInt("七十"), 70);
assert_int_equals(processStringToInt("四十二"), 42);
assert_int_equals(processStringToInt("九十九"), 99);
assert_int_equals(processStringToInt("六十六"), 66);
assert_int_equals(processStringToInt("五十三"), 53);
assert_int_equals(processStringToInt("一百"), -1);
assert_int_equals(processStringToInt("三百"), -1);
printf("test_pcocessStringToInt結束----------\n");
}
int main()
{
test_convertToInt();
test_convertToString();
test_pcocessStringToInt();
}
- 測試腳本
#!/bin/bash
echo "開始編譯......"
gcc test.c excute.c convertToInt.c convertToString.c error.c printResult.c processStringToInt.c
if [ $? == 0 ]
then
echo "編譯成功......"
echo "開始運行......"
./a.out
if [ $? == 0 ]
then
echo "運行成功......"
else
echo "運行失敗......"
fi
else
echo "編譯失敗"
fi
- 運行結果
- 運行方法:在終端cd進入文件夾,然后輸入 bash filename.sh(filename指的是腳本的文件名)
- 上面兩個函數測試過了以后,其他幾個函數由運行結果來驗證
四、 添加以下功能
- 通過命令行讀取一個文件,然后運行這個文件。
- 完成這題真是坎坷,一直理解錯題目的意思。題目改完后才知道是要把1.txt 的內容作為輸入
- 首先要知道命令行參數的使用和文件的相關知識,main函數如下
//argc是參數的個數,argv[0]是執行的程序名,argv[1]是第一個參數(參考文章在開頭有注明)
int main(int argc,char const* argv[])
{
FILE* fp = fopen(argv[1],"r"); //打開1.txt “r”指的是只讀
if(fp) //fopen:如果文件順利打開,返回指向該流的文件指針。如果文件打開失敗則返回NULL
{
char integer[6];
fscanf(fp,"%s", integer); //與scanf的區別只是加了第一個參數,是文件指針 //如果要從文件中輸入,就得用該方式,而不是普通的scanf
if (strcmp(integer, "整數"))
{
error();
}
else
{
execute(fp);//該函數還要用到該文件,所以fp得傳進該函數
}
fclose(fp);
}
else
{
printf("can't open the file\n");
}
return 0;
}
- 運行
- 首先cd進入文件夾,然后將程序編譯成 lang
- 然后如下圖
- 上圖對應的1.txt是
整數 錢包 等於 零
錢包 增加 四
錢包 減少 三
看看 錢包
- 如果將1.txt改為
整數 錢包 等於 十一
錢包 增加 二十六
錢包 減少 三
錢包 減少 二十
看看 錢包
- 結果還是正確的
寫在最后
- 不得不說通過第二次作業學到的東西還是很多的,很多都是之前不會的,只能現學,關鍵是有時候題目都不知道什么意思,不但要弄懂概念還要學很多新知識(
分分鍾自閉) - 順便記錄一下重定向(一開始以為第四部分的功能是這樣做)
- 在第一部分代碼的情況下,在終端運行方式如下
文件重定向的定義:將原來**從標准輸入讀取數據**的文件操作重新定向為**從向其他文件讀取數據**;將原來要輸出到**標准輸出**的內容,重新定向輸出到**指定的其他文件**
< // 標准輸入重定向
> // 標准輸出重定向 清空原先的內容后添加新的內容
>> // 標准輸出重定向 在原來內容換行下方添加新的內容