これから、本格的にプログラムを記述するようになると、同じような処理を何回も書く必要がでてくることがあります。
同じ処理を何度も記述するのはとても面倒です。そこで、C言語では、一定の処理をまとめて記述したプログラムを部品化し、再利用できるように関数という仕組みが用意されています。
C言語は、関数の集まりでできていることを学びました。そして、今まで、サンプルプログラムで記述していた、main も関数の1つです。なので、これまで学んでこられた方は、すでに、関数を使っていることになります。
ただ、関数については、詳しく説明していませんでしたので、今回は、この関数の基本的な使い方について学んでいこうと思います。
C言語で、関数という仕組みを利用するためには、関数を作成することと、作成した関数を呼び出すという手順が必要です。
関数を作成する
関数を使うには、一定のまとまった処理に名前を付けて識別できるように定義をしないといけません。
また、まとまった処理に名前を付けて識別する際に、まとめた処理に対して、値を渡したい、また、処理した結果を知りたいなどを決める必要があります。
これを「関数を定義する」という言い方をします。
次に関数の定義の構文を示します。
関数の定義
戻り値の型 関数名 ( 引数の型 変数名 )
{
文 ;
}
戻り値とは、関数から返される数値のことをいいます。関数の呼び出し元に、関数の処理した結果を返したいときに指定します。
戻り値の型とは、関数の呼び出し元に返す時に、どのデータ型を返すのかを指定します。
戻り値として返すことができるのは、1つだけになります。
引数とは、関数に渡すデータのことをいいます。呼び出し元から関数に対して何かデータを渡し、その値に応じた処理を行いたい場合に指定します。
引数は、戻り値と違い、複数指定できます。複数指定する場合は、カンマ( , )を付けて、次の引数を指定することになります。
戻り値の型と、引数について、使用しないときは、void を記述します。
次に、関数名とは、変数の名前と同じように識別子(変数の名前として使える文字や数字、アンダースコアの組み合わせのこと)を使った関数の名前です。
文には、関数の中で、行いたい処理を記述します。
関数名の最後、また、ブロックの最後には、セミコロンは必要ありません。
戻り値も、引数もない関数定義したサンプルプログラムを次に示します。
#include <stdio.h>
int main( void )
{
return 0;
}
void output( void )
{
printf("output関数の処理です。\n");
}
これで、引数も戻り値もない、outputという名前の関数の定義が終わりました。
main関数は、まだ、何も処理がありませんが、この後、main関数にて、定義した関数を呼び出すことにします。
関数を呼び出す
関数を定義すると、あとで、定義した関数を別の関数から使用できるようになります。関数を使用することを関数を呼び出すといいます。
先ほど、定義した関数を呼び出すには次のような構文になります。
関数の呼び出し
関数名( 引数 ) ;
関数の定義とは違い、関数を呼び出すときは、関数名とカッコで引数を指定し、最後にセミコロン( ; )を付けるのみです。
引数がない場合でも、( ) は、必要です。引数がないときは、関数名( ) ; となります。
先ほどのサンプルプログラムのmain関数に定義したoutput関数の呼び出しを追加したサンプルプログラムを次に示します。
#include <stdio.h>
int main( void )
{
printf("main関数の始まり");
output();
printf("main関数の終わり");
return 0;
}
void output( void )
{
printf("output関数の処理です。\n");
}
13行目から関数定義したoutput関数を、main関数内の7行目で呼び出しています。
その前後に、printf関数を入れましたが、これは、output関数の呼び出した前後の動作がどのようになるかをわかりやすくするために記述しました。
このサンプルプログラムをコンパイルしても、エラーになってしまいます。
これは、main関数内から呼ばれるoutputの関数定義が後に記述されているからです。コンパイラは、main関数を解析し、output関数の呼び出しのところで、まだ、この段階で、関数定義されていないことにより、outputが関数であることがわからないため、エラーとなってしまいます。
これを解決するためには、二通りのやり方があります。
- 関数呼び出しする前に関数定義を記述する。
サンプルプログラムでは、main関数の前にoutput関数の関数定義を記述する。 - プログラムの最初のほうで、どんな関数定義があるか、前もって概要的なものを一覧にしておく。
これをプロトタイプ宣言と呼びます。
関数呼び出しする前に関数定義を記述した場合のサンプルプログラムを次に示します。これでコンパイルしてもエラーはでなくなります。
#include <stdio.h>
void output( void )
{
printf("output関数の処理です\n");
}
int main( void )
{
printf("main関数の始まり\n");
output();
printf("main関数の終わり\n");
return 0;
}
サンプルプログラムの実行結果を次に示します。
実行結果
main関数の始まり
output関数の処理です
main関数の終わり
main関数より前にoutput関数の記述がありますが、C言語では、main関数が処理の開始となります。これにより、実行順は次のようになります。
- 10行目のprintf関数が実行されて、「main関数の始まり」が表示されます。
- output関数の呼び出しを行われます。
- output関数の処理に移り、5行目のprintf関数が実行されて、「output関数の処理です」が表示されます。
- output関数の処理が終わると、main関数の12行目に戻ります。
- そのあとは、14行目のprintf関数が実行されて、「main関数の終わり」が表示されます。
- 最後にreturn 0が実行されてプログラムが終了します。
以上が、関数定義から関数を呼び出し実行するまでの流れでした。
戻り値のない関数は、ブロックの最後まで処理を行うか、return文によって関数が終了します。戻り値のない関数のreturn文を記述する場合は、「return ;」のみを記述します。
関数定義した関数は、複数の箇所から、好きなタイミングで呼び出すことができるため、いろんな箇所から使いたい処理や、まとまった処理に名前を付けて記述することで、複雑なソースコードをわかりやすいコードにすることができます。今回のサンプルプログラムは、関数にするメリットはないですが。。
プロトタイプ宣言
先ほど、 エラーとなってしまうサンプルプログラムの解決方法で、「プログラムの最初のほうで、どんな関数定義があるか、前もって概要的なものを一覧にしておく。」プロトタイプ宣言する方法があると伝えていましたが、やり方について学んでいませんでしたので、ここで学びたいと思います。
関数のプロトタイプ宣言は、関数を呼び出す前に、呼び出す関数の戻り値の型、関数名、引数の型を、前もって記述しておくことにより、ソースコードのどこの場所で関数定義しても、エラーとならず呼び出すことができるようになります。
プロトタイプ宣言の構文は次のようになります。
関数のプロトタイプ宣言
戻り値の型 関数名( 引数の型 引数名 ) ;
引数名については、省略することができます。また、関数定義とは異なり、セミコロン( ; )は必要です。
コンパイルでエラーとなったサンプルプログラムに関数のプロトタイプ宣言したものを次に示します。
#include <stdio.h>
void output( void );
int main( void )
{
printf("main関数の始まり");
output();
printf("main関数の終わり");
return 0;
}
void output( void )
{
printf("output関数の処理です。\n");
}
3行目に、プロトタイプ宣言をしました。これにより、main関数のあとにoutputの関数定義を記述していてもエラーにならなくなりました。
このプロトタイプ宣言ですが、実は、今まで学んできた中で、隠れて使用されていました。printf関数などです。これは、#include <stdio.h>で、stdio.hをインクルードしていました。この中にprintf関数などのプロトタイプ宣言が記述されており、printf関数がどこでも使用できるようになっていたのです。
プロトタイプ宣言は、戻り値の型や、引数の型、引数の数が関数定義と違う場合は、コンパイルエラーとなりますので、注意してください。
戻り値も引数もない関数については、以上になります。
次に、引数を使った関数の使い方について学んでいこうと思いますが、少し長くなってしまったので、次のページで学習します。