KID's World
 

おしながき
トップページ
プログラミング
研究
いんすぴ
色日記
ソフトウェア
KID's Worldの歴史
リンク
小出俊夫について


関数を自作しよう

関数を使うと効率的なプログラムを作れることを知ろう

 

とにかく関数を作ろう

 何のために関数を使うのか、どんなときに関数を使うのかなどという説明は今はすっ飛ばして、とにかく関数を作ってみましょう。といっても、何も難しいことではありません。実はいままであなたはいくつもの関数を作ってきているのです。へっ? と思われるかもしれませんが、ズバリ「main関数」がそれです。main関数はOSから呼ばれていると考えることができます。すなわち、プログラムを実行すると、OSがそのプログラムのmain関数を呼びます。すると、あなたがmainの中に書いた命令が実行されるわけです(厳密には違いますが(^-^;)。

 というわけで、ただ単にメッセージを表示する関数fooを作ってみましょう。適当に、

 
#include <stdio.h>

main()
{
  foo();
}

foo()
{
  printf("メッセージ\n");
}

 と、作ってみました。ではコンパイルしてみましょう。

 
C>lcc foo.c
foo.c 5: 警告: 関数 foo は宣言されていないので、int 型とみなす
lld @link.i

C>foo
メッセージ

C>

 あれ? エラーが出てきました。でも、エラーが起きたのにちゃんと実行できてる、なんか気持ち悪いですよね。じつはこれ、コンパイラ側の都合なんです。main関数の中でfoo関数を呼び出していますが、その肝心のfooは、mainよりも後にあります。だからコンパイラが「foo」まで処理を進めたときにはまだfooという存在を知らないために、「宣言されていない」などとエラーを出したのです。ということは、fooとmainを入れかえればいいわけです。

 
#include <stdio.h>

foo()
{
  printf("メッセージ\n");
}

main()
{
  foo();
}

 これでエラーは出なくなります。しかし、mainよりも上にfooがあるのは気持ち悪い! と思う方は、「fooという関数を作ったよ」と、コンパイラに教えてあげましょう。これをプロトタイプ宣言と言います。そうすればコンパイラは不安を抱えずエラーも出さずにコンパイルしてくれます。プロトタイプ宣言のしかたは簡単で、関数の形を書いておくだけです。が、ここで新しいキーワード「void」を使います。

 
#include <stdio.h>

void foo(void); /* プロトタイプ宣言 */

main()
{
  foo();
}

void foo(void)
{
  printf("メッセージ\n");
}

 関数はもともと値をもらって何らかの処理をして値を返すものですが、このように値を返す必要のない関数の場合は、「無効」という意味のvoidを使います。カッコの中にもvoidとありますが、これは省略されることもあります。以降では、このようなプロトタイプ宣言を使った書き方を採用することにします。

 

値を返す関数の作成

 では、値を受け取って、値を返す関数を作成してみましょう。

 関数で値を受け取るとき(これを引数といいますが)、それは何の型なのかということが必ず決められています。また、返す値に対しても、型が決められています。これらを決めるには、前に「void」と書いたところを変更します。例えば二つのint型の引数を取り、int型の値を返す関数は、次のように書けます。

  int foo(int i1, int i2);

 例えばあんまり関数にする意味はないですが、i1とi2の値を足し合わせた答えを返す関数fooを作ってみましょう。...といっても値を返すにはどうすればいいかがまだ分かりませんね。値を返すには、return文を使います。return文はその時点で関数の実行を終了し、return文の後に書かれた式の値を返します。

 
#include <stdio.h>

int foo(int i1, int i2);

main()
{
  printf("%d\n", foo(10,20));
}

int foo(int i1, int i2)
{
  return i1+i2;
}

実行すると、画面に「30」と表示されます。見やすくするためにreturn文のところを「return (i1+i2);」と書くこともあります。

 余談ですが、僕が通っていた大学でC言語を教えていた先生、教科書のreturn文を使った例題にカッコが書かれていないのを見て「これ間違ってるよ」と堂々と言ってしまったことがあります。returnは関数ではないので、カッコは必ずしも必要ありません。あの先生、いろんなところで嘘教えてたなぁー。しかも教科書よりも難解な講義でした(^-^;

 

関数を自作するメリット

 では、実際に関数を使ったほうが良い場合を考えてみましょう。ある程度大きなプログラムを作るようになってくると、同じ処理をしなければならないところが色々なところで出てくるものです。具体的に、年月日を聞くという処理をプログラムの何箇所かでやっている場合を考えましょう。

 年月日を聞くプログラムは、以下のように作れます。


  int y,m,d;
  printf("年月日を入力してください。\n年:");
  scanf("%d",&y);
  printf("月:");
  scanf("%d",&m);
  printf("日:");
  scanf("%d",&d);
  printf("年月日は、%d年%d月%d日です。\n",y,m,d);

 こうしてint型変数y, m, dに年月日が入ります。

 
年月日を入力してください。
年:1978
月:1
日:15
年月日は、1978年1月15日です。

これを何回もほとんど同じ内容でソースコードの中に書くのは面倒ですし、非効率です。そこで、これを関数として作ってしまって、今までの部分を関数の呼び出しのみにしてしまいます。

 ちょっとここで考えなければならないのは、3つも値を同時に返す必要があるということです。しかし関数は値を一つしか返せません。そこでポインタを使います。ポインタを使えば、変数の値を直接書きかえられますので、関数の中で3つの変数の値を書き換えてしまいましょう。よって関数の戻り値の型はvoidにしてしまいます。

 ついでに、「年月日」のメッセージを自由に変えられるようにしておきましょう。年、月、日をあらわす変数へのポインタを渡して、メッセージも変えられる、年月日の入力を処理する関数は、次のように作ることができます。第4引数にメッセージを渡します。

 
void getYMD(int *y, int *m, int *d, char *msg)
{
  printf("%sを入力してください。\n年:", msg);
  scanf("%d",y);
  printf("月:");
  scanf("%d",m);
  printf("日:");
  scanf("%d",d);
  printf("%sは、%d年%d月%d日です。\n", msg, *y, *m, *d);
}

この関数は、このように使えます。

 
main()
{
  int year, month, day;

  getYMD(&year, &month, &day, "あなたの誕生日");
  printf("%d/%dは、あなたの誕生日です。\n", month, day);
}

ポインタを渡していることに注意してください。実行結果はこのようになります。水色は入力した文字、白はgetYMD関数の出力した文字、緑はmain関数で表示した文字です。

 
あなたの誕生日を入力してください。
年:1978
月:1
日:1
あなたの誕生日は、1978年1月1日です。
1/1は、あなたの誕生日です。

 getYMD関数を呼び出せば、このようにたったの1行で年月日の入力ができるようになります。これが関数を使うメリットです。

 ん〜ちょっと難しかったですか? とにかく、いろいろな関数を自分で作ってみてください。そして、このようにポインタを利用することで、いくつもの変数を同時に一度の関数の呼び出しで書きかえることができるというテクニックも覚えておいてください。

 

まとめ。

  1. 関数はmain関数と同じように作ることができる
  2. 関数を使う前に、関数の宣言(関数プロトタイプ宣言)をしなければならない
  3. 値を返すには、return文を使う
  4. 何度も同じ処理をする場合は、その処理を関数にするとよい
  5. 2つ以上の値を同時に返すには、ポインタをうまく使う

(1999/03/13 公開)

[目次へ] [次へ]

 著作権は全て小出 俊夫にあります。KID's World © 1996-2003 Toshio Koide.

 対応ブラウザについて