Re: [問題] 我是學程設的新手 可以救救我嗎?
※ 引述《nike22puma (酷斃了你 酷!斃了你)》之銘言:
: 學了程設但是聽不懂老師在說啥
: 還有
: 老師出了個回家功課但是不知道怎麼做
: EX(1)使用scanf_s()輸入五位同學各三次成績 並顯示出結果
: (2)計算每一位學生的總成績和平均值並顯示出結果
: (3)以函式呼叫方式完成第(2)項工作
: (4)當輸入值不回0-100匙顯是錯誤
: (5)以call by address 完成第(2)項工作
: 誰可以幫幫我完成
: 我會看內容但是不知道從何打起.......
不知道你對C程式的內容理解到什麼程度; 這會與"跟你討論的人該提供什麼訊息給你
較適當"有關係.
scanf_s() 很少用,查一下資料說,C函式庫也有,說是"強化安全的scanf",嗯,
那就假裝是 scanf() 差不多的東西來用吧!
首先要寫個程式,先要把一些結構打好:
// 開頭加一些像 #include<stdio.h> 這種引用詞
int main() {
// 這裡填一些東西
}
這樣好像可以了. 你可以先寫這樣,然後編譯看看,ok之後,開始看第一題:
"(1)使用scanf_s()輸入五位同學各三次成績 並顯示出結果"
「輸入?」腦中把這個問題一步一步拆開:
1. 輸入五位同學各三次成績 = 「輸入三次成績」這件事情做五次.
2. 輸入三次成績 = 「輸入成績」做三次.
3. 怎麼輸入成績?
最後就有一個問題可以開始: 怎麼輸入成績呢? 而且要用 scanf_s().
scanf_s() 要輸入一個整數, 要在主程式中寫:
int main() {
int n;
scanf_s("%d", n );
}
「先宣告一個 n, 然後用 scanf_s 取值輸入到 n, 這樣對嗎? 然後你會注意到,
第一,使用 scanf_s() 要引用相對的函式庫標頭 stdio.h ,
第二,呼叫 scanf_s() 用的參數 n 應該要給 n 的位址 &n 才找得到.
所以程式要修改成:
#includ<stdio.h>
int main() {
int n;
scanf_s("%d", &n);
// 最後加個 printf("%d\n", n); 看看結果.
}
好像可以了. 然後要跳到上一個問題: 怎麼輸入三個成績?
當然是用迴圈. 不過除了迴圈之外,儲存成績的變數也要延伸為陣列:
#include<stdio.h>
int main() {
int i;
int score[3];
for (i=0; i<3; i++) {
scanf_s("%d", &score[i]);
}
/* 加入以下段落,可以檢查輸入值有沒有存進去並存得正確.
for (i=0; i<3; i++) {
printf("%d\n", score[i]);
}
*/
}
接著你可能突然想到,以上程式輸入浮點數,看起來會有一點點問題.
應該是資料類型不一樣的問題. 所以程式改成:
#include<stdio.h>
int main() {
int i;
float score[3];
for (i=0; i<3; i++) {
scanf_s("%f", &score[i]);
}
/* 加入以下段落,可以檢查輸入值有沒有存進去並存得正確.
for (i=0; i<3; i++) {
printf("%f\n", score[i]);
}
*/
}
這樣感覺還不錯吧? 然後可以再往上跳一個問題: 怎麼輸入五個學生的三次成績?
每個成績要佔一個變數,五個學生各有三個成績,共要佔 15 個變數.
你可能會想用:
float score[15];
或是用:
float score[5][3];
這樣都ok的. 陣列結構不一樣,程式結構也會跟著不同而已.
先寫到這裡. 以上你可以做做看,把這一題做完.
第二個問題: 「(2)計算每一位學生的總成績和平均值並顯示出結果」
怎麼算總和? 要先知道每一個學生的每一個成績.
這裡先假設,按照前面的陣列結構,用 score[5][3] 存好了 15 個成績,
如果把它列表,看起來是:
[0] [1] [2]
score[0] 35 60 70
score[1] 90 70 75
score[2] 85 90 90
score[3] 40 75 70
score[4] 60 50 55
以上方陣,在第五列第一行位置 60 代表 score[4][0], 這樣你知道意思.
你知道程式中從某一段落開始,你先知道這樣的 score 陣列,就可以繼續寫下去:
...
int sum = 0;
for (i=0; i<3; i++) {
sum = sum + score[0][i];
}
/* 加上下列段落可以印出加總結果:
for (i=0; i<3; i++) {
printf("%d ", score[0][i]);
}
printf('\n');
*/
}
這樣你可以先做到第一步,是將 0 號同學的三個成績加起來.
接下來,想要把五個同學的成績加起來,所以程式改成這樣:
...
int sum[5];
for (i=0; i<5; i++) {
for (j=0; j<3; j++) {
sum[i] = sum[i] + score[i][j];
}
}
/* 加上下列段落可以印出加總結果:
for (i=0; i<5; i++) {
printf("%d\n", sum[i]);
}
*/
}
然後執行一下,覺得好像有點問題. 往上一看, sum[0], sum[1], sum[2], ... 等等
都沒有給一個初值 0. 所以在那邊改一下:
...
int sum[5];
for (i=0; i<5; i++) {
sum[i] = 0;
}
for (i=0; i<5; i++) {
for (j=0; j<3; j++) {
sum[i] = sum[i] + score[i][j];
}
}
/* 加上下列段落可以印出加總結果:
for (i=0; i<5; i++) {
printf("%d ", sum[i]);
}
*/
}
這樣就可以了. 可以加總好,就可以計算平均. 這些常識在你熟悉寫程式的過程之後,
就很容易會應用上去.
第三個問題: 「(3)以函式呼叫方式完成第(2)項工作」.
這部份你要先知道函式定義的語法要怎麼寫,然後要怎麼分配函數的工作:
也就是說,要想想哪個重覆計算的部份寫成函數.
例如:
for (i=0; i<5; i++) {
for (j=0; j<3; j++) {
sum[i] = sum[i] + score[i][j];
}
}
這個重複加總三個成績的地方太多了,也許我改寫成函數:
for (i=0; i<5; i++) {
sum[i] = subtotal( score[i] );
}
為什麼能寫成這樣的函數,以及 subtotal() 這樣的函數要怎麼寫,
可能是這邊你要思考的重點.
第四個問題: 「(4)當輸入值不回0-100匙顯是錯誤」
說輸入值不是0-100時顯示錯誤,這段程式應該要寫在前面 scanf_s() 附近.
那邊的原程式是:
#include<stdio.h>
int main() {
int i;
float score[3];
for (i=0; i<3; i++) {
scanf_s("%f", &score[i]);
}
/* 加入以下段落,可以檢查輸入值有沒有存進去並存得正確.
for (i=0; i<3; i++) {
printf("%f\n", score[i]);
}
*/
...
在 scanf_s("%f", &score[i]); 這行執行之後, score[i] 都會取得一個值,
這時候可以來檢查 0-100 的限制. 所以程式在此改成:
for (i=0; i<3; i++) {
scanf_s("%f", &score[i]);
if (score[i] < 0 || score[i] > 100) {
printf("input error!");
}
}
這樣,是在有輸入錯誤時印出 "input error!"
不過,顯示錯誤的方式可以很多樣,可能是在 printf("input error!"); 同句改寫成:
exit(1);
直接中斷程式執行,並對外部送出一個 1 代號的訊息. 或是改成:
scanf_s("%f", &score[i]);
重抓一次輸入值. 程式怎麼寫,看你的需要.
第五個問題: 「(5)以call by address 完成第(2)項工作」
這個問題較讓人看不懂,因為 "call by address" 是指先有個函式呼叫,
才來討論這個呼叫是不是 "call by address."
而第二項題目是說:
: (2)計算每一位學生的總成績和平均值並顯示出結果
這裡還沒講到函式. 又或許在這裡是指 "總成績" 和 "平均值" 的計算是函式.
來看平均值的計算吧,先用第三個問題的觀點把平均值函式寫好,像是:
float average(float sum, int count) {
return (sum / count);
}
Call by address 意思是說,你呼叫 average() 的時候,如果將 sum 定義為
可以 called by address, 而且 sum 在 average() 函式中值有所改變,
sum 的變化就會帶回到主程式去.
但是,目前並不需要改變 sum 的值,所以舉 sum 為例不是個好的舉例.
從 average() 來做個例子,我說,把 average() 的參數改成三個:
float average(float *result, float sum, int count) {
return (sum / count);
}
float *result 是一個可以 call by address 的參數,因為是將 result 定為
(float*). 函式定義可以改成:
float averageCBA(float *result, float sum, int count) {
(*result) = sum / count;
return (sum / count);
}
這邊會考驗你對指標的了解程度;你是否能明白指標和被指標所指的物件之間的區別.
至於以上 call by address 版本的平均值函式 averageCBA(), 呼叫的方式也有改變:
...
// 假設有個 sum 和 count 變數,相對的數值都存好了.
int average;
averageCBA( &average, sum, count);
要用一個 average 變數接受計算結果,並同時 average 所代替參數位置是 call-by-
address, 所以要取變數的位址 &average 當做參數.
以上一點討論. 你可以做練習之後,將你遇到的障礙提問.
並不是每個人都永遠拒絕提供有關作業或課堂習作的討論. ok的.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 218.160.211.92
→
05/30 00:59, , 1F
05/30 00:59, 1F
→
05/30 01:05, , 2F
05/30 01:05, 2F
→
05/30 01:06, , 3F
05/30 01:06, 3F
推
05/30 01:10, , 4F
05/30 01:10, 4F
→
05/30 01:13, , 5F
05/30 01:13, 5F
→
05/30 01:23, , 6F
05/30 01:23, 6F
→
05/30 01:24, , 7F
05/30 01:24, 7F
→
05/30 01:24, , 8F
05/30 01:24, 8F
※ 編輯: yauhh 來自: 218.160.211.92 (05/30 01:26)
推
05/30 02:12, , 9F
05/30 02:12, 9F
→
05/30 02:12, , 10F
05/30 02:12, 10F
→
05/30 02:13, , 11F
05/30 02:13, 11F
→
05/30 02:13, , 12F
05/30 02:13, 12F
※ 編輯: yauhh 來自: 218.160.211.92 (05/30 12:30)
推
05/30 12:32, , 13F
05/30 12:32, 13F
※ 編輯: yauhh 來自: 218.160.211.92 (05/30 12:38)
推
05/31 08:59, , 14F
05/31 08:59, 14F
→
05/31 22:33, , 15F
05/31 22:33, 15F
→
05/31 22:34, , 16F
05/31 22:34, 16F
→
05/31 22:44, , 17F
05/31 22:44, 17F
→
05/31 22:44, , 18F
05/31 22:44, 18F
推
05/31 23:03, , 19F
05/31 23:03, 19F
→
05/31 23:03, , 20F
05/31 23:03, 20F
→
06/01 12:15, , 21F
06/01 12:15, 21F
推
06/02 09:32, , 22F
06/02 09:32, 22F
推
06/07 10:42, , 23F
06/07 10:42, 23F
→
06/07 10:42, , 24F
06/07 10:42, 24F
推
06/08 21:38, , 25F
06/08 21:38, 25F
推
06/19 01:35, , 26F
06/19 01:35, 26F
討論串 (同標題文章)
完整討論串 (本文為第 3 之 3 篇):