第2章26 自作の関数を作ってみる@イチからゲーム作りで覚えるC言語

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
現在の記事が不明です。一覧からどうぞ。

この記事でやること

今回は、新しくプロジェクト「0210_myfunc」を作り、関数を自作する方法についてお話します。いままではすべて main 関数の中でプログラミングをしてきましたが、同じような機能を自作関数にして、必要なときに呼び出すことで、すっきりとコードをまとめて読みやすくしたりすることができます。

この記事はゆる~くC言語でコンソールゲームを作りながらプログラミングを学ぶための連載記事です。シリーズものですので記事の一覧はこちらを参照してくださいね。

自作の関数を作り、利用するプログラム

自作の関数を作り、利用するプログラムを動かして結果を見てみましょう。プロジェクト「0210_myfunc」を新しく作成し、ソースコード「MyFunc.c」を作成してみてください。

#include <stdio.h>
#include <stdlib.h>

int kinokoHiroi () {
 int kinoko = rand() % 3 + 1;
 return kinoko;
}

int main() {
 for (int i = 0; i < 4; i++) {
   int toretaKinoko = kinokoHiroi();
   printf("ぷらんくは %d 本のキノコを採取しました。\n", toretaKinoko);
 }
}

このコードを実行してみるとこんな結果になったかと思います。

ぷらんくは 3 本のキノコを採取しました。
ぷらんくは 3 本のキノコを採取しました。
ぷらんくは 2 本のキノコを採取しました。
ぷらんくは 2 本のキノコを採取しました。

ぷらんくはランダムに4回、キノコを採取します。

関数とは

ここまでのお話の中で printf 関数や rand 関数などいろいろな関数を使ってきました。
少しおさらいになります。ざっくりいうとC言語で関数とは便利な機能をあらかじめどこかで定義しておき、定義した引数を設定して呼び出しすることで、なんらかの結果を得ることができる機能です。数学で下のような式をみたことがあるかと思います。

f(x) = x + 5

これは x を引数にもち、x + 5 という計算を行った結果を出す f という名前の関数です。
例えば引数に 1 を入れると、f(1) = 1 + 5 = 6 という結果になります。
C言語でも関数の形はとても似ています。

ただ数学と異なり、プログラムでは「x + 5」などの計算だけではなく、文字を表示したり、ファイルをいじったり、画像を表示したりなど、さまざまなことができます。

C言語での関数の定義の仕方

C言語で関数は下のように宣言&定義することができます。関数の宣言は「こういう名前で、引数はコレコレの関数を作るよ!」と明示することです。関数の定義は「この関数の具体的な処理は〇〇だ」と処理を明記することです。
他にも宣言の方法はありますが、まずはこちらから。

戻り値の型  関数名 ( 引数1の型 引数1の変数, 引数2の型 引数2の変数, … 略 … ) {
 関数が行う(複数の)処理;
 return  呼び出し元に返す値;
}

オリジナルの関数を作るには、まず〇〇するような関数、という宣言からする必要があります。重要なことですが関数を宣言&定義するだけでは関数に書いたプログラムは動きません

戻り値の型とreturn文

まず関数を宣言するとき「戻り値の型」を書く必要があります。
関数を使うとき、例えば乱数を生成する rand 関数では呼び出した戻り値が整数の乱数となっていたかと思います。具体的には rand 関数の「戻り値の型」は int 型と定義されています。
こういった関数の呼び出し元に返す値の型は自分で決めることができます。具体的にどんな値を関数の呼び出し元に返すかは return 文で決めます。

int型を返す関数の例

例でみてみましょう。

int funcA () {
   return 100;
}

と書くと、int 型の整数 100 を返す関数 funcA を宣言&定義することができます。

return の右側に 100 と書くことで、 整数100 を返すことができますが、このとき、return ( 100 ); とする必要はありません。
細かな話ですが、関数は「関数名(ほにゃらら)」とする必要がありますが、 return は関数ではなく、「return 〇〇」という文(C言語の仕様)で定められています。

double型を返す関数の例

同じように double 型(浮動小数点数を代入できる型)を返すような関数を見てみましょう。

double funcB () {
  return 3.1415;
}

上のように書くことで、double型の「3.1415」という浮動小数点数を返す関数 funcB を宣言&定義することができます。

return 文が処理されるとき

関数の中で return 文までたとりついたとき、関数の呼び出し元にその場で戻ります。
その後に書いてある関数の中の処理は実行されないので注意して下さい。例えば、

int okanehiroi() {
 printf ("100 枚の銅貨を拾いました。");
 return 100;
 printf ("よくみたら 200 枚の銅貨でした。");
 return 200;
}

のようなコードであれば、3 行目の「return 100;」以降のプログラムは実行されず、関数 okanehiroi を呼び出した元に 100 という戻り値をもって戻ります。

何も値を返さない関数の例

計算結果などは別にないし、特に関数の呼び出し元に値を返す必要のない関数があります。
すでにいままで出てきた例だと、 srand関数(疑似乱数の種を設定する関数)は戻り値が特にありません。ですので、「int kekka = srand(100);」のように書くとエラーとなります。

こういった関数は、ただ文字を表示するだけだったり、内部で事前計算をするだけのときにもよく使われます。例を見てみましょう。

void hyouji () {
    printf("文字を出すだけの関数ですよ");
    return ;
}

ただ文字を表示するだけで、関数の呼び出しもと結果を何も返す必要がないときは関数の戻り値に void と書きます。void は、「空」とか「虚ろ」とかいう意味です。この場合、return文は省略することができます

main 関数について

今までのプログラムで、それほど意識せずに int main () { … } という形式でソースコードを書てきましたが、これも同じく関数です。

int main () { … }

という書き方ですので、main という名前の関数で、int型を返す関数ということになります。この main 関数はプログラムをビルドして出来上がった「〇〇.exe」というファイル(CPUが理解して実行することのできるバイナリファイル)を実行したとき、自動的に呼び出しされるようになっており、そのあたりの処理はC言語のプログラマが直接意識しなくても良いようになっています。
この辺りは Windows や Linux、Android、iOSなどの OS(オペレーティングシステム)が処理してくれています。

main 関数は int 型を返すように宣言しています。
今までのプログラムでは「 return 〇〇; (〇〇は int 型)」と最後に書いていませんでしたね。でも今までreturn を書かなくともエラーなどは出ていなかったと思います。実は main 関数だけは特別に return を省略した場合は main 関数の「}」関数の終わりに到達したとき、「return 0;」と自動的に処理してくれています。

明示的に「return 1;」など書けば、 main 関数の呼び出し元である OS にその値が渡されますが、特に今は意識しなくても大丈夫です。

ソースコードを追ってみよう

今回のソースコードを追ってみましょう。今回のプログラムの中では rand 関数を使いたかったので、ソースコードの頭で「#include <stdlib.h>」と記載しています。これで rand 関数が利用できます。

#include <stdio.h>
#include <stdlib.h>

オリジナルの関数の作成(定義)

続いて、オリジナルの関数 kinokoHiroi を定義しています。
重要なことですが、定義するだけでは書いてある処理は実行はされません。
main 関数などから呼び出したとき、はじめて実行されます。

int kinokoHiroi () {
  int kinoko = rand() % 3 + 1;
  return kinoko;
}

その名前の通り、キノコを拾う処理をしてくれる関数をイメージしています。
関数の名前は英数字と一部の記号を使うことができます。

関数名は日本語でも動くかもしれませんが、あまりお勧めはしません。C言語の開発は英語圏が基本だったこともあり、文に日本語を使うことは考慮しきれていないことがよくあります。

関数名の例:

  • myFunc (){ … }
  • getGold100 (){ … }
  • lets_bake_bread(){ … }

※関数名の大文字と小文字は区別されるので注意しましょう。

関数 kinokoHiroi の中では具体的にどのような処理をしているか確認しましょう。

int kinokoHiroi () {
  int kinoko = rand() % 3 + 1;
  return kinoko;
}

5 行目の右辺「rand() % 3 + 1」では 乱数で 1 ~ 3 の整数を生成しています。そして、その計算結果を変数 kinoko に代入しています。

6行目で return 文が登場しています。return 文の右側に kinoko と書いてありますので、kinoko の中身である 1~ 3 のいずれかの乱数を、呼び出し元の関数に返していることになります。return 文がでてきたら関数の処理は終了となります。

main 関数の定義

ここからはいままでもやってきたように、main関数の定義をしています。
あまり意識はしませんが、関数 kinokoHiroi と同じで、main 関数を定義しているだけなので中身の実行はされません。ただ、結果的には実質一番最初に main 関数に書いた処理が実行されることとなります。

正確にはこのソースコードがビルドされて「〇〇.exe」というCPUが理解するファイルになった後、実行したとき OS から「main」という名前の関数が定義されているかをチェックされ、あれば main関数が呼び出され実行される、という流れです。
今回、main 関数はこんな風に定義しました。
int main() {
 for (int i = 0; i < 4; i++) {
   int toretaKinoko = kinokoHiroi();
   printf("ぷらんくは %d 本のキノコを採取しました。\n", toretaKinoko);
 }
}

for 文で繰り返し処理をするように書かれていて、4回ループすることになります。

ループ処理の中で、自作関数を呼び出ししていますね。

   int toretaKinoko = kinokoHiroi();
   printf("ぷらんくは %d 本のキノコを採取しました。\n", toretaKinoko);

11行目、自作関数の kinokoHiroi() を呼び出し、結果を変数 toretaKinoko に代入しています。kinokoHiroi() の戻り値は int 型で定義したので、代入先も int 型にしてあげています。

12行目で自作関数 kinokoHiroi() の結果である取れたキノコの量を表示しています。

補足:main関数の他の書き方

この項目は補足です。このシリーズではこの書き方は基本的にしませんので飛ばしてもらってもOKです。
ですが、コンソールプログラムでゲームデータを作るような補助ツールを作ったりするときには有用だと思いますので書いておきます。

main 関数は 「int main () { … } 」以外にもいくつかの種類の書き方があります。C言語の文法を取り決めた、2018年6月時点でほぼ最新のC11(N1570)バージョンには以下の書き方も紹介されています。

int main ( int argc, char* argv[] ) { … }

この書き方にはなにやら二つの引数がついていますね。
VisualStudio などの IDE 上から実行するのではなく、コンソール上からプログラムを呼び出すこともできます。そのとき、引数をつけて 〇〇.exe を実行することもできますが、その引数にどのような文字を設定したのか、この main 関数の書き方であれば引数の「argc」と引数の「argv[]」から取得することができます。

この辺りは必要に応じてお話しようと思います。

あとがき

今回は「キノコを採る」という関数を作ってみました。プレイヤーの決まった動作や、敵の動作など、決まった処理を関数としてまとめておき、必要なタイミングで呼び出すことで分かりやすいソースコードを書くことができます。

次回も関数について追加でお話したいと思います。

今回はここまで。おつかれさまでした。

イチからゲーム作りで覚えるC言語
連載ページ一覧へ
現在の記事が不明です。一覧からどうぞ。

非常に参考になったサイトさまや、参考文献など

ページの更新履歴

更新日更新内容
更新なし