自定函數

一、質數問題

我們先來看一個問題,假設我們要寫一個程式,輸入一個正整數 N,如果 N 是質數則印出 Y,否則印出 N。我們看到這個問題,最直覺的想法假設系統有一個函數 P(N) 可以檢查 N 是不是質數,如果是則傳回 1 ,否則傳回 0,於是我們把它寫成下面的程式:

#include <stdio.h>

void main()

{

 int a;

 scanf("%d", &a);

 if(P(a)) printf("Y\n");

 else printf("N\n");

}

上面的程式很容易可以理解,但是系統並沒有提供這樣的一個函數 P(N),所幸有  C 語言中我們可以自定建立函數,定義函數的語法如下:

傳回值型態  函數名稱(參數一型態  參數一名稱, 參數二型態  參數二名稱, ....)

{

  變數宣告

  程式碼

  return  傳回值;

}

上面的寫法是不是和 main() 很像,事實上 main() 本身也是一個函數,只不過 main() 是一個特別的函數,它會在程式開始的時候就自動執行。而要讓 main() 函數可以使用這個新的函數,要把這個函數定義在 main() 之前,或是定義在 main() 之後,而在 main() 之前補上這個函數的宣告。我們先用這函數定義在 main() 之前的寫法:

#include <stdio.h>

int P(int n)

{

 int p=1, i;

 if(n<2) return 0;

 for(i=2; i<n; i++)

   if( (n%i)==0 ) p=0;

 return p;

}

void main()

{

 int a;

 scanf("%d", &a);

 if(P(a)) printf("Y\n");

 else printf("N\n");

}

上面黃色的部分是我們新增的部分,在函數 P 中,由於最小的質數是 2,所以先檢查它是否小於 2,如果是的話,則傳回 0。接下來我們假設它是質數(用變數 p 記錄),然後我們從 2 到 n-1 去對 n 取餘數,只要有一個餘數為 0,也就是 n 可以被那個數整除,那麼 n 就不是質數,就把 p 設為 0。最後,我們再把它是不是質數,也就是變數 p 的值用 return 傳回去。要注意的是,在函數 main 及 P 中的變數只限於該函數使用,至於我們用 P(a) 的方式呼叫函數 P,這個 a 到了 P 的時候會變成 n。接下來我們看到宣告函數的語法:

傳回值型態  函數名稱(參數一型態  , 參數二型態  , ...);

宣告函數的用意是告訴下面的程式這個函數的用法,也就是讓系統知道這個函數要有哪些參數、以及傳回值,所以在宣告函數的時候不需要寫程式碼,也不用加上參數的名稱(要加也可以),但是宣告函數那一行後面要加上分號 ; 代表結束。宣告函數之後,就可以使用該函數,我們把上面的程式改用先宣告後定義的寫法:

#include <stdio.h>

int P(int);

void main()

{

 int a;

 scanf("%d", &a);

 if(P(a)) printf("Y\n");

 else printf("N\n");

}

int P(int n)

{

 int p=1, i;

 if(n<2) return 0;

 for(i=2; i<n; i++)

   if( (n%i)==0 ) p=0;

 return p;

}

至於我們常用的一些函數如 printf、scanf 等,都已經在它們的標頭檔 *.h 中宣告,所以只要把該標頭檔 include 進來後,就可以直接使用。另外,定義函數的同時也等於宣告了該函數,所以第一個例子就不用再寫一行函數宣告。而同一個程式中,可以對同一個函數寫很多次的宣告,但是只能寫一次的定義。

至於函數要定義在 main 之前還是之後,這個見人見智,寫在前面的優點是不用再宣告一次,寫在後面的優點是 main 主程式在前面,可以很快看懂這個程式(因為函數只要知道它的功能即可,不用去管它是如何寫出來的)。

上面的例子雖然不一定要用函數的寫法,但是使用自定函數有下列的好處:

  1. 讓主程式 main 更簡潔
  2. 可以分工完成各函數後再合併起來

最後,這先把程式分成幾個大步驟,再將這些大步驟分解成數個小步驟的寫法,我們稱之為「由上而下的寫法」(Top-Down),有助於讓一個複雜的問題簡單化。

 

二、數學星球的問題

公元 20xx年,數學星球派來大量的太空船,企圖佔領地球。將過地球人代表陳阿扁和數學星球人交涉後,數學星球人開出一個條件,如果地球人可以在 1 分鐘之內完成 10 題數學星球的三位數相加,數學星球人則立即離開地球,放棄入侵地球的計畫。他們的前三題是:

135+246

234+543

616+353

這時,小明為維護高中數學教師的尊嚴,挺身而出上台挑戰,只花了 20 秒不到就完成十題的答案:381、777、969....,可是,數學星球人卻用電擊把他電昏了。這個時候,同樣也是高中數學教師的小志發現數學星球人的左手只有四根指頭、右手只有三根指頭,也就是說,數學星球是使用七進位。為了拯救地球,小志決定寫一個程式,輸入兩個七進位數字 A、B,並印出相加後的結果。

由於 C 語言沒有讀取七進位的函數,所以我們可以先用字串把這兩個數讀進來,接著用自定函數 R7 把該字串依照七進位的規則把它轉換成數字,接下來再用自定函數  P7 把兩數相加的結果轉換成七進位印出來,主程式 main 的部分如下:

void main()

{

 char s1[10], s2[10];

 int a, b;

 scanf("%s %s", s1, s2);

 a=R7(s1);

 b=R7(s2);

 P7(a+b);

}

接下來我們看到 R7 的寫法:

int R7(char s[])

{

 int n=0, i;

 for(i=0; i<strlen(s); i++)

   n=n*7+s[i]-'0';

 return n;

}

上面先假設該數 n 為 0,接下來將每個位數的字元減去 '0' 以取得該位數的數值,再將原先的數字乘以七後加上該位數的數值,重複這個步驟到最後一個位數為止,最後再將該數 n 傳回。接著看到 P7 的寫法:

void P7(int n)

{

 int p[10], i, j=0;

 while(n>0) {

   p[j]=n%7;

   n/=7;

   j++;

 }

 for(i=j-1; i>=0; i--)

   printf("%d", p[i]);

}

上面我們用一個整數陣列儲存轉換後的每一個位數,我們將該數對 7 做連續的除法,餘數存到陣列中,商數則繼續除下去,直到變成 0 為止,我們再從最高位數(陣列中最後面一個數字)往前面印回來。最後我們把這三個部分的程式合併起來:

#include <stdio.h>

#include <string.h>

int R7(char s[])

{

 int n=0, i;

 for(i=0; i<strlen(s); i++)

   n=n*7+s[i]-'0';

 return n;

}

void P7(int n)

{

 int p[10], i, j=0;

 while(n>0) {

   p[j]=n%7;

   n/=7;

   j++;

 }

 for(i=j-1; i>=0; i--)

   printf("%d", p[i]);

}

void main()

{

 char s1[10], s2[10];

 int a, b;

 scanf("%s %s", s1, s2);

 a=R7(s1);

 b=R7(s2);

 P7(a+b);

}

接下來,我想再想一個問題,如果數學星球人的手指頭是左手七根、右手八根,也就是他們是使用十五進位的話,那該怎麼辦?

 

上一頁

首頁

下一頁