2020面向對象程序設計寒假作業1
這個作業屬於哪個課程 | 2020面向對象程序設計 |
---|---|
這個作業要求在哪里 | 2020面向對象程序設計寒假作業1 |
這個作業的目標 | 1.問答題: (1)回答以下問題: 如果你不了解C++請回答以下問題:你認為C語言有什么缺陷(你覺得哪里用的不順手)。 如果你已經了解C++請回答以下問題:你覺得C++和C語言比有什么優點。 (2)查閱相關資料,簡述一下C語言/C++的編譯過程。 2.實踐題: 自己動手,完成以下任務: (1)查看自己的C++編譯器版本。 (2)使用命令行編譯一份C語言/C++代碼。 3.編程題(請使用C語言或者C++完成以下題目): 編程要求 編寫一個程序,輸入滿足以下語法要求的一段文字,輸出運行后的結果。 變量定義:整數 錢包 等於 零 運算(加法):錢包 增加 四 運算(減法):錢包 減少 四 輸出:看看 錢包 |
作業正文 | 問答題與實踐題 編程題 |
其他參考文獻 | C語言編譯過程詳解 靜態鏈接與動態鏈接 |
1.問答題
(1)你認為C語言有什么缺陷(你覺得哪里用的不順手)?
從本人近期C語言使用體驗上來談,我覺得首先C語言對於某些相對固定的功能沒有進行概括封裝成庫函數,相對比較麻煩,例如C語言要實現排序,使用冒泡或者選擇排序的話都要用雙重循環來跑一遍,如果直接用庫函數實現排序功能的話,可能會使代碼來的更加簡潔。還有就是感覺因為C語言靈活性強,自由度高,所以代碼的可讀性較差,對於我們初學者而言,如果碼的太過隨意,一不注意可能自己的代碼就只有自己能看的懂了😂。
(2)簡述一下C語言/C++的編譯過程
c語言編譯(從源代碼到二進制行程序)共經過四個步驟:a.預處理 b.編譯 c.匯編 d.鏈接
a.預處理
首先讀取C語言源代碼,將所有#include頭文件以及宏定義替換成其所包含的實際文件,同時將注釋去掉並進行條件編譯。預處理過程實際上是在為編譯做准備,將不需要的注釋等文件刪去,對C源碼進行擴充和整理,方便在下一步轉化為特定匯編代碼。(通過查閱相關資料了解到在預處理后生成的文件仍為文本文件,但比預處理前的文件要大的多,由此可見頭文件及宏定義,在某種意義上說,除了方便使用外還大大減少了C源代碼的空間占用,節省了空間)
b.編譯
這里的編譯是指將經過預處理之后的程序轉換成特定匯編代碼的過程。該過程會進行語法的檢查,如果語法出現問題,編譯就無法進行,相應編譯器就會報錯。
c.匯編
匯編過程將上一步的匯編代碼轉換成機器碼,產生目標文件,目標文件是二進制格式。機器碼就是能夠直接被計算機理解和接受的語言,但對於人來說不易理解。
d.鏈接
鏈接過程將多個目標文件以及所需的庫文件鏈接成最終的可執行文件(及形成以.exe為拓展名的文件)。鏈接分為靜態鏈接和動態鏈接兩種,靜態鏈接是由鏈接器在鏈接時將庫的內容加入到可執行程序中的做法,而動態鏈接所調用的函數代碼並沒有被拷貝到應用程序的可執行文件中去,而是僅僅在其中加入了所調用函數的描述信息。
2.實踐題
(1)查看自己的C++編譯器版本。
a.查看Dev-C++所帶gcc\g++編譯器版本。
首先快捷鍵win+R打開運行,輸入cmd打開命令提示符,然后可通過cd指令轉換到編譯器的絕對路徑輸入gcc -v進行查看。
或者直接將編譯器的絕對路徑加入到環境變量path中,再查看。(省去輸入絕對路徑的麻煩)
b.查看VS所帶Microsoft C/C++編譯器cl.exe版本。(可用VS自帶命令行,已配置好環境變量可直接查看)
(2)使用命令行編譯一份C語言/C++代碼。
3.編程題
中國文化博大精深,從倉頡造字開始,漢字一直流傳到了今天。我們在感嘆漢字的源遠流長時,也不禁感慨,為什么沒有一門使用漢字編程的語言?
漢字真的不能編程嗎?最近文言文編程火了一把,吾有一數。曰三。名之曰「甲」。這朴實無華的變量定義無疑不是幾千年來中華文化的發展中一朵奇葩。
今天小王同學想,文言文能編程那白話文呢?他找到了你,讓你幫幫他。
編程要求
編寫一個程序,輸入滿足以下語法要求的一段文字,輸出運行后的結果。
變量定義:整數 錢包 等於 零
運算(加法):錢包 增加 四
運算(減法):錢包 減少 四
輸出:看看 錢包
樣例
輸入:
整數 錢包 等於 零
錢包 增加 四
錢包 減少 三
看看 錢包
輸出:
一
注意事項
注意:
1.輸入輸出用例均為GBK編碼,推薦使用vscode把文本切換為GBK編碼。
2.數字只會出現以下 零一二三四五六七八九十 。
操作:
1.讀題,提取出題目的要求。
2.分解需求,把需求分解為幾個你覺得不太相關的模塊。
3.思考每個模塊怎么寫,可以從簡單的模塊開始寫。
4.對於不會的問題進行查閱資料。
5.對於每一個模塊設計測試用例。
(1)題目要求
實現漢字為變量的0~99之間的數值存儲及查詢。
題目要求分為三個部分:
a.實現以輸入“整數”為起始條件的變量定義;
b.實現0~99內數值運算;
c.實現以輸入“看看”為條件的數值查詢功能。
(2)需求分析與模塊分類
首先,依題目及樣例可知,輸入均為漢字,而GBK編碼中漢字占兩個字節且零到十在對應編碼上並沒有明顯可用的關系,所以首先需要將輸入的漢字轉化為數字再進行數值計算,漢字數字識別與轉化可以作為一個相對獨立的模塊來實現。其次,就是初始化后的數值運算,根據相應指令中的加減乘除的命令,對轉化為數字的數值進行運算,也可以作為一個模塊來實現。之后,由於輸出的也是漢字數字,所以需要將計算處理后的數字轉換為漢字后再輸出,這部分也可以作為一個模塊。最后,由於題目在格式以及數值大小上有限定,所以需要考慮出錯的情況,主要是在定義以及運算的時候出現,這也可以作為一個融匯於以上模塊的特殊模塊進行考慮。
總結一下就是:
a.漢字識別轉換模塊
b.條件識別及運算模塊
c.數值轉化輸出模塊
d.錯誤分析模塊(特殊)
(3)模塊實現
a.漢字識別轉換模塊
首先對漢字對應數字類型進行分析,發現共有四種漢字表達類型分別是:零一二等單個漢字表達的數字;十一、十二等以十開頭的兩個漢字表達的數字;二十、三十等以十結尾的數字;以及“幾十幾”類型的數字。因此需要設計分別對應於這四種情況的轉換,代碼如下:
char list[11][5]={"零","一","二","三","四","五","六","七","八","九","十"}; //運用數組下標和漢字對應關系進行查表更方便
int swap(char a[]){
int i;
for(i=0;i<11;i++){
if(strcmp(list[i],a)==0){
return i;
}
}
}
int num(char a[]){
char b[10],c[10];
if(strlen(a)==2){
return swap(a); //對應零一二等單個漢字表達的數字
}
else if(strlen(a)==4){
b[0]=a[2];
b[1]=a[3];
b[2]='\0';
if(swap(b)!=10) return 10+swap(b);//對應十一、十二等以十開頭的兩個漢字表達的數字
else{
b[0]=a[0];
b[1]=a[1];
b[2]='\0';
return 10*swap(b);//對應二十、三十等以十結尾的數字
}
}
else if(strlen(a)==6){
b[0]=a[4];
b[1]=a[5];
b[2]='\0';
c[0]=a[0];
c[1]=a[1];
c[2]='\0';
return swap(b)+swap(c)*10;//對應“幾十幾”類型的數字
}
}
b.條件識別及運算模塊
分別對應識別“增加”、“減少”、“除以”、“乘以”等指令並進行運算。
int judge(int n,char a[],char b[]){
int sum1;
sum1=num(b);
if(strcmp(a,"增加")==0) return n+sum1;
else if(strcmp(a,"減少")==0) return n-sum1;
else if(strcmp(a,"乘以")==0) return n*sum1;
else if(strcmp(a,"除以")==0) return n/sum1;
}
c.數值轉化輸出模塊
該模塊同a模塊需要對應識別四種情況並輸出。
if(sum>=0&&sum<=10){
printf("%s\n",list[sum]);
}
else {
if(sum%10==0){
printf("%s十\n",list[sum/10]);
}
else if(sum<=19){
printf("十%s\n",list[sum%10]);
}
else {
printf("%s十%s\n",list[sum/10],list[sum%10]);
}
}
d.錯誤分析模塊(特殊)
主要在主函數中出現,見完整代碼
(4)完整代碼
#include<stdio.h>
#include<string.h>
char list[11][5]={"零","一","二","三","四","五","六","七","八","九","十"}; //運用數組下標和漢字對應關系進行查表更方便
int swap(char a[]){
int i;
for(i=0;i<11;i++){
if(strcmp(list[i],a)==0){
return i;
}
}
}
int num(char a[]){
char b[10],c[10];
if(strlen(a)==2){
return swap(a); //對應零一二等單個漢字表達的數字
}
else if(strlen(a)==4){
b[0]=a[2];
b[1]=a[3];
b[2]='\0';
if(swap(b)!=10) return 10+swap(b);//對應十一、十二等以十開頭的兩個漢字表達的數字
else{
b[0]=a[0];
b[1]=a[1];
b[2]='\0';
return 10*swap(b);//對應二十、三十等以十結尾的數字
}
}
else if(strlen(a)==6){
b[0]=a[4];
b[1]=a[5];
b[2]='\0';
c[0]=a[0];
c[1]=a[1];
c[2]='\0';
return swap(b)+swap(c)*10;//對應“幾十幾”類型的數字
}
}
int judge(int n,char a[],char b[]){
int sum1;
sum1=num(b);
if(strcmp(a,"增加")==0) return n+sum1;
else if(strcmp(a,"減少")==0) return n-sum1;
else if(strcmp(a,"乘與")==0) return n*sum1;
else if(strcmp(a,"除以")==0) return n/sum1;
}
int main(){
int i,sum;
char a[100],b[100],c[100],d[100];
scanf("%s",a);
if(!strcmp(a,"整數")){
scanf("%s %s %s",a,b,c);
}
else{
printf("輸入格式錯誤\n");
return 0;
}
sum=num(c);//測試點:printf("%d\n",sum);
while(scanf("%s %s",d,b)!=EOF){
if(strcmp(d,"看看")){ //可在運算過程中重復運用查看功能
scanf("%s",c);
if(!strcmp(a,d)){
sum=judge(sum,b,c);//測試點:printf("%d\n",sum);
if(sum>=99||sum<=0){
printf("超出可容納范圍\n");
return 0;
}
}
else {printf("變量不匹配\n");
return 0;
}
}
else{
if(sum>=0&&sum<=10){
printf("%s\n",list[sum]);
}
else {
if(sum%10==0){
printf("%s十\n",list[sum/10]);
}
else if(sum<=19){
printf("十%s\n",list[sum%10]);
}
else {
printf("%s十%s\n",list[sum/10],list[sum%10]);
}
}
}
}
return 0;
}
(5)測試用例
a.基本功能測試
b.運用測試點進行測試(測試點見完整代碼注釋)
由此可知輸入格式正確的情況下輸出基本無誤
c.錯誤分析測試
(6)存在問題及總結
在輸入自己擬定的測試樣例時,還是找出了不少bug,例如判斷條件||打成了&&等等,自我感覺在錯誤分析上還不夠完善,應該還存在一些其他可能出錯的地方,代碼還有可以提升的空間。通過這道題學到了一些關於漢字編碼方面的知識,同時也加深了對於字符運用方面的理解,例如strcmp函數的運用,以及漢字如何存儲。
本人水平有限,如果有發現問題或有更好的建議歡迎大家向我提出😄