一、PTA實驗作業
題目1 水果價格
1.本題PTA提交列表
2.設計思路
- 第一步:定義變量number,表示輸入的編號
- 第二步:定義變量i,用來記錄編號數目
- 第三步:輸出菜單:[1] apple
[2] pear
[3] orange
[4] grape
[0] exit - 第四步:輸入number
- 第五步:如果number==0,結束程序
- 第六步:如果number1,輸出price3.00;如果number2,輸出price2.50;如果number3,輸出price4.10;如果number4,輸出price10.20;若都不是,輸出0.00;
- 第七步:再次輸入number
- 第八步:重復五,六,七步,直到i>5,結束程序
3.本題調試過程碰到問題及解決辦法
問題:沒有在輸入0后結束程序
問題代碼:
int number;
int i;
printf("[1] apple\n[2] pear\n[3] orange\n[4] grape\n[0] exit\n");
scanf("%d",&number);
if(number==0){
return 0;
}
if(number>=0){
for(i=1;i<=5;i++){
switch(number)
{
case 1:
printf("price=3.00\n") ;
break;
case 2:
printf("price=2.50\n");
break;
case 3:
printf("price=4.10\n");
break;
case 4:
printf("price=10.20\n");
break;
}
scanf("%d",&number);
}
if(i>5){
printf("price = 0.0");
}
}
if(number>4){
printf("price = 0.0");
調試:
可以看到輸入0后發生錯誤,我們想要的是它進入number==0這個分支然后結束程序,但是實際上進的依然是循環體,會不會是因為等於0這個分支執行位置不對?還是因為下一次輸入是在循環體里面進行的導致不能執行0這一分支?
初步改正:將number的判斷全部移入循環體
運行結果:
可以看到答案與題目不符,所以之前的分支number==0執行結果應該是先輸出0,0再結束程序
微調后:
修正代碼:
int number;
int i;
printf("[1] apple\n[2] pear\n[3] orange\n[4] grape\n[0] exit\n");
scanf("%d",&number);
for(i=1;i<=5;i++){
if(number==0){
printf("price = 0.0");
return 0;
}
if(number>4){
printf("price = 0.0");
}
if(number>0&&number<4){
switch(number)
{
case 1:
printf("price = 3.00\n") ;
break;
case 2:
printf("price = 2.50\n");
break;
case 3:
printf("price = 4.10\n");
break;
case 4:
printf("price = 10.20\n");
break;
}
}
scanf("%d",&number);
}
if(i>5){
return 0;
}
另外根據輸出結果發現循環條件錯誤,少循環一次,還有輸入超過5次結束程序而不是輸出0.0,不符合題目要求
錯誤:
改正:
PTA 提交結果
修改:增加對i==5時程序結束的判斷
這種是還是要輸入一組
這種是直接跳到i==5的分支,不走循環體了
后面是一系列的折騰i==5,注意力全放在如何在剛好五組數據時結束程序,浪費很多時間去增添語句調試,把錯誤提示理解成恰好輸入五組,然后結束程序,不能再輸入了。調試成功后依舊提交錯誤,而且錯 的還是一樣的,開始去排查其他可能的錯誤,忽然發現輸入的不一定是數字也可能別的,所以改用default判斷余下輸入情況
改正:
優化:i>5這一分支沒有必要,可以刪去,因為i只有小於等於5才進入循環體,輸出相應語句
本題錯誤總結:
不熟悉錯誤類型,定位不准,導致浪費時間。最好是先寫算法再寫代碼,這樣會更熟悉每一步,而不會因為代碼理解的不足多加很多無用語句,可讀性更差了,也方便修正。一定要嚴格按照題目意思來,不能主觀妄斷。
題目7、8 歌唱比賽評分系統、餐飲服務質量調查打分【有類似點就放在一起寫了】
1.本題PTA提交列表
題目7
題目8
2.題目8設計思路
- 第一步:定義變量n表示輸入數字總數,repeat表示執行次數,class表示等級,i,j,m都是循環變量
- 第二步:輸入repeat的值
- 第三步:對one,two,three,four,five賦初值,初值為0
- 第四步:輸入class的值
- 第五步: 若class1,one的值加一;若class2,two的值加一;若class3,three的值加一;若class4,four的值加一;若class==5,five的值加一
- 第六步:當i滿足不大於n時,重復第四步,第五步
- 第七步:輸出1,當m小於等於one時,輸出,不滿足m<=one時換行
輸出2,當m小於等於two時,輸出,不滿足m<=two時換行
輸出3,當m小於等於three時,輸出,不滿足m<=three時換行
輸出4,當m小於等於four時,輸出,不滿足m<=four.時換行
輸出5,當m小於等於five時,輸出*,不滿足m<=five時換行 - 第八步:當評分次數小於等於repeat,重復第3步到第七步
3.本題調試過程碰到問題及解決辦法
問題代碼:
int repeat,n,i,j,one,two,three,four,five,m,class;
scanf("%d%d",&repeat,&n);
one=0;
two=0;
three=0;
four=0;
five=0;
for(j=1;j<=repeat;j++){
for(i=1;i<=n;i++){
scanf("%d",&class);
switch(class){
case 1:one++;break;
case 2:two++;break;
case 3:three++;break;
case 4:four++;break;
case 5:five++;break;
}
printf("%d:",class);
for(m=0;m<=one;m++){
printf("*");
運行結果:
首先一個小錯誤,換行符的使用導致輸出格式不對
第二個,輸出結果不對,比如1輸出的倆個*
調試:
可以看到輸出一個星號后再次進入循環體,輸出星號
結果:
錯誤原因:m所賦初值不對,導致循環多了一次。當m等於1也是可以進入循環的,所以不需要初值為0
后來想到要用變量count來儲存各數字輸入次數,來簡化程序。。。。
錯誤截圖:
調試:
count會跟着循環,導致輸出很多組
調試修改了一晚上發現真的不會這種方法,代碼本身好像都有問題,最終選擇用if語句判斷這五種情況,一一列舉,並且完善了當有1到5有數字沒輸入時的情況
代碼:
int n,repect,class,i,j,m;
scanf("%d%d",&repect,&n);
int one=0,two=0,three=0,four=0,five=0;
if(repect>0&&repect<9&&n>=1&&n<=20){
for(i=1;i<=repect;i++){
for(j=1;j<=n;j++){
scanf("%d",&class);
switch(class){
case 1:one++;break;
case 2:two++;break;
case 3:three++;break;
case 4:four++;break;
case 5:five++;break;
}
}
printf("1:");
for(m=1;m<=one;m++){
printf("*");
}
printf("\n");
printf("2:");
for(m=1;m<=two;m++){
printf("*");
}
printf("\n");
printf("3:");
for(m=1;m<=three;m++){
printf("*");
}
printf("\n");
printf("4:");
for(m=1;m<=four;m++){
printf("*");
}
printf("\n");
printf("5:");
for(m=1;m<=five;m++){
printf("*");
}
printf("\n");
}
PTA提交顯示答案錯誤,驗證多組數據,輸出都沒有問題,找不出錯誤,在助教和學長提示下修正了代碼,提交正確
錯誤原因:雖然明白repeat是多次輸入,但是調試時一直默認repeat為1,導致沒有發現n的輸入位置不對,所以檢驗時選擇多組數據以及選擇的條件很重要,要考慮充分。
后排補充:為什么每次循環評分后要把one到five初始化
第七題比賽評分與第八題餐飲打分某些部分是一個類型的,比如實現多次打分和打分后初始化這倆個點,下面借第七題調試解釋下為什么要初始化還有一些語句放置位置
可以看到輸出結果錯誤,計算方法沒問題那就是數值輸入發生了錯誤,下面調試
sum=85=min,也就是sum並沒有包括第一次輸入的90,所以調整或者加多一步sum=sum+grade,這個錯誤修正后我們往下進行
(截圖里我選了一組新數據)
這次評分結束后,准備下一組評分
可以看到sum不是我們想象中的0,而是保留了第一組評分的結果,導致后面一系列全錯了,這就是對一組運行后變量再次初始化的意義
題目4 換硬幣
1.本題PTA提交列表
2.設計思路
- 第一步:定義變量x,count1,count2,count3,count,total分別代表需要換的錢數目,5分的數目,2分的數目,1分的數目,有幾組達標,總共硬幣數
- 第二步:輸入x的值
- 第三步:計算5分最多的數目x/5,2分數目x/2,1分數目x
- 第四步:隨機遞減count1,count2,count3,當滿足count15+count22+count3時,count的值加一
- 第五步:total=count1+count2+count3
- 第六步:輸出5分,2分,1分的數目
- 第七步:輸出硬幣總數
3.本題調試過程碰到問題及解決辦法
錯誤代碼:
int x,count1,count2,count3,count,total;
scanf("%d",&x);
count=0;
for(count1=1;count1*5<=x;count1++)
for(count2=1;count2*2<=x;count2++)
for(count3=1;count3*1<=x;count3++)
if(count1*5+count2*2+count3*1==x){
count++;
total=count1+count2+count3;
printf("fen5:%d,fen2:%d,fen1:%d,total:%d\n",count1,count2,count3,total);
}
printf("count = %d",count);
首先輸出的count1,count2,count3是隨機的,只要滿足硬幣代表的錢數為x即可,不一定按照從大到小的順序,再一個,控制每種硬幣至少一枚比較麻煩,而且容易出錯,那能不能反着來,循環遞減,最小為1
改正后,結果正確
二、同學代碼結對互評
1.互評同學名稱:蘭子欣、陳歡
2.代碼截圖
梅森數
蘭子欣的代碼:
int i,j,n,sum,count=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
sum=pow (2,i)-1;
for(j=2; j<=sum; j++){
if(sum%j==0)
break;
if(j>sum/2&&sum!=1){
printf("%d\n",sum);
count++;
break;}
else
count=count;
}
}
if(count==0)
printf("None");
我的代碼:
int prime(int result);
int main(){
int n,result,i,j;
scanf("%d",&n);
j=0;
for(i=1;i<=n;i++){
result=pow(2,i)-1;
if(prime(result)!=0){
printf("%d\n",result);
j++;}
}
if(j==0)
printf("None");
return 0;
}
int prime(int result){
int m;
if(result==1)return 0;
for(m=2;m<=result/2;m++){
if(result%m==0)
return 0;
else return 1;
}
}
歌唱比賽評分系統
陳歡的代碼:
我的代碼:
for(i=1;i<=repeat;i++){
scanf("%d",&n);
scanf("%d",&grade);
sum=0;
sum=sum+grade;
max=min=grade;
for(j=2;j<=n;j++){
scanf("%d",&grade);
sum=sum+grade;
if(grade>max){
max=grade;
}
if(grade<min){
min=grade;
}
}
3.我的代碼和同學的代碼不同在哪里?有哪些各自的優勢?你更喜歡哪種代碼風格?
- 梅森數這題我和蘭子欣的代碼不同在我在代碼中使用了函數,看上去我的代碼要長一些,但我認為慢慢習慣使用函數是很好的一種代碼編寫方式,因為增加了代碼可讀性,思路更清楚,將判斷素數這一部分用函數調用,再分析其中一些特殊值比如1,但是弊端也是在函數調用上,初學可能會在調用發生各種問題,要考慮到函數聲明,形參,調用語句,返回結果等,if語句使用相對考慮的少些,只要考慮執行條件就可以了。初學函數的我還是偏向if語句,但在繼續學習的路上慢慢轉向函數的調用
- 歌唱比賽這題我和陳歡的代碼不同在對一組數據最大值最小值的判斷,我是將輸入的第一個成績,賦值給max,min,再與后面輸入的數據判斷大小,從而得到數據中最大值,最小值。而她是將評分范圍的最大值最小值賦值給max,min,然后再將這倆個值與輸入數據比大小,最終得到數據中最大值最小值,這也是一種方法,簡單明了,但我覺得這個方法是有漏洞的,如果沒有限制輸入的范圍,這種思路就行不通了,但是對於這一題來說,這是一個好辦法,一種新思維,至少我就沒想到過這種,學到了。
三、截圖本周題目集PTA最后排名
四、本周學習總結
1.你學會了什么?
(1)函數分類:庫函數、自定義函數
(2)函數定義一般形式
函數類型 函數名(形式參數表){//函數首部
函數實現過程//函數體
}
1.函數首部:函數類型、函數名、形式參數表
函數類型一般與return語句中表達式的類型一致
形參表中各個形參之間用逗號隔開,每個形參之前的類型必須寫明。
形參可以是一個,可以是多個,可以沒有
注意:函數首部后面不能加分號,它和函數體構成完整的函數定義
2.函數體是大括號括起來的多個語句,用於計算,完成特定工作
3.形參與普通變量的區別在於是否只能從主調函數中得到已知條件
(3)函數的調用
1.調用之前要有定義、聲明,函數聲明是一條C語句,即帶分號
2.調用形式:函數名(實際參數表)
注意點;- 實參可以是變量,常量或表達式,形參只能是變量
- 數值從實參傳遞給形參,是單向的,形參值改變了不會影響實參
- 實參和形參要一一對應,數量相同,類型盡量一致
3.常見調用:賦值語句;輸出函數的實參
4.結果返回:return語句,注意return只能返回一個值
5.關於函數調用:當遇到函數調用時,主函數被暫停執行,轉而執行相應函數,該函數執行完后將返回主函數,然后再從原先暫停的位置繼續執行
(3)不返回結果的函數類型:void
注意void不能省,否則默認函數類型為int
(4)局部變量和全局變量
局部變量作用於其所在的函數,優點是各函數互不干擾,但是一些被多個函數共同使用的變量,就沒法解決了,於是引出了全局變量,它作用范圍為定義到程序結束,就能解決這一問題了,並且全局變量可以幫助函數解決多結果返回的問題
注意,當全局變量和局部變量同名時,局部變量優先
(5)關於動態變量和靜態局部變量沒有賦初值,前者儲存單元中將是隨機值,后者會為0,但是賦0值只在函數第一次調用起作用
(6)靜態局部變量只作用於該函數,不作用於其他函數包括主函數,靜態局部變量最大特點是會保存函數上一次調用的結果,可以利用這一點解決循環問題
2.本周的內容,你還不會什么?
函數調用是對於形參名的設置,以及調用函數時主函數中調用條件的書寫。還是不大習慣把程序中某一計算過程換成調用函數從主函數中拎出來,領出來后主函數里的書寫形參實參傻傻不知道怎么辦了,不過這樣子調用函數代碼可讀性會提高,也方便調試改錯,慢慢從例題和代碼中體會吧