C言語

関数の基本的な仕組み

何度も登場している main()printf() なども実は関数です。
今回は、今まで使ってはいるものの触れてこなかった関数についての基本的な仕組みを説明します。

関数とは

複雑なコードを書くようになってくると、同じ処理を何度も行わなければならないことが出てくる場合があります。
何度も記述していくのはとても面倒です。そこで、C言語では、処理をまとめて記述する関数という機能が用意されています。
関数を利用すると、よく使う処理を1か所にまとめておき、必要なときに、名前を呼ぶだけで実行できます。

C言語で関数を利用するためには、次の2つの手順をふみます。

  • 関数を作成する(関数定義)
  • 関数を使う(関数呼び出す)

関数の定義

関数を使うためには、最初に、関数の処理を書く必要があります。
これを関数の定義といいます。

関数定義の構文は次の通りです。

戻り値の型 関数名( 引数の型 仮引数名 )
{
  文; // いままで書いてきたプログラムと同じように処理を記述
}

戻り値引数は後ほど説明します。
まずは、もっとも簡単な関数定義をみてみましょう。

void output(void)
{
  printf("output関数を呼び出しました。\n");
}

outputという関数名を付けて、ブロック { } 内に処理を書いています。
なお、ブロックの最後の } の後にセミコロン( ; )は付けません。

関数呼び出し

関数を定義すると、使用することができるようになります。
関数を使用することを、関数呼び出しといいます。

関数呼び出しの構文は次の通りです。

関数名(実引数);

関数を呼び出すときは戻り値の型や、引数の型の記述は書きません。
例えば、先ほどの output 関数を呼び出す場合は、次のようにします。

output();

関数定義の際に、引数を void とした場合は、( ) 内に何も書かなく必要はありません。

関数定義と関数呼び出しの例

それでは、実際に、簡単なプログラムを作成してみましょう。

#include <stdio.h>

void output(void)
{
  printf("output関数を呼び出しました。\n");
}

int main(void)
{
  printf("main関数の始まり\n");
  output();  // 関数を呼び出す
  printf("main関数の終わり\n");
  return 0;
}

C言語のプログラムは main() 関数から実行が始まります。
このプログラムでは、次のように動きます。

  1. main() の最初の printf() が実行され、「main関数の始まり」が表示される
  2. output() が呼び出され、「output関数を呼び出しました。」が表示される
  3. output() の処理が終わると、再び、 main()output() を呼び出した位置に戻り、次の printf() が実行される

プログラムの実行結果は次の通りです。

main関数の始まり
output関数を呼び出しました。
main関数の終わり

引数とは

関数を呼び出す際に、呼び出し先の関数に値を渡したい場合があります。
このとき使うのが引数です。

関数定義で指定した引数のことを仮引数といいます。

int型の値の引数を定義する場合は、次のように記述します。

void output(int number)
{
  printf("output関数を呼び出しました。\n");
  printf("引数は、%dです。\n", number);
}

この関数を呼び出すときは、次のように、int型の値を記述します。

output(5);

関数を呼び出すときに渡す値を実引数と呼びます。
また、次のように変数を渡すこともできます。

int num = 10;
output(num);

次は、引数を使用した関数を確認する例です。

#include <stdio.h>

void output(int number)
{
  printf("output関数を呼び出しました。\n");
  printf("引数は、%dです。\n", number);
  number = 0;
  printf("引数の値を%dに変更しました。\n", number);
}

int main(void)
{
 int num = 5;
  printf("main関数の始まり:num=%d\n", num);
  output(num);
  printf("main関数の終わり:num=%d\n", num);
  return 0;
}

このプログラムの実行結果は次の通りです。

main関数の始まり:num=5
output関数を呼び出しました。
引数は、5です。
引数の値を0に変更しました。
main関数の終わり:num=5

この結果から、呼び出し元の変数numをoutput関数に渡して、output関数内で仮引数の変数を変更しても、呼び出し元の変数numは変化してないことがわかります。
これは、引数の値がコピーされて渡される(値渡し)ためです。

複数の引数をもつ関数を使う

関数には、引数を複数指定することができます。
複数の引数を使う場合は、かっこの中にカンマ(,)で区切って並べます。

void printSum(int a, int b)
{
    int sum = a + b;
    printf("合計は %d です。\n", sum);
}

この関数は、2つの int 型の値を受け取り、それらを足して表示します。
ab仮引数 になります。

関数呼び出しの例

int main(void)
{
    printSum(3, 5);  // 実引数として3と5を渡す
    return 0;
}

実行結果は次のようになります。

合計は 8 です。

引数が複数ある場合は、型と変数名のセットをカンマで区切ります

void func(int a, int b, double c)

呼び出すときも、同じ順番で 値を渡す必要があります。

func(10, 20, 1.5);

※引数の型と順番が一致しないと、コンパイルエラー になります。

戻り値とは

次に戻り値について説明します。
戻り値とは、関数定義した関数から呼び出し元に値を渡すことができるものです。
呼び出し元に値を渡すことを呼び出し元に値を返すといいます。

戻り値は、次のように関数定義するときに関数名の前に型を記述し、関数を終了するときにreturn文で返したい値を記述します。

int output(void)
{
  printf("output関数を呼び出しました。\n");
  
  return 5;
}

return の後に値や変数を記載することで、この値を呼び出し元に返します。

呼び出し元で値を受け取るには、次のように書きます。

num = output();

これで、output関数のreturn文で指定した値がnumに代入されます。

次は、戻り値を使ったプログラムの例です。

#include <stdio.h>

int output(void)
{
  int ret;
  printf("output関数を呼び出しました。\n");

  ret = 5 * 2;

  return ret;
}

int main(void)
{
 int num = 1;
  printf("main関数の始まり:num=%d\n", num);
  num = output();
  printf("main関数の終わり:num=%d\n", num);
  return 0;
}

output()では、5*2した結果をretに代入して、returnで返しています。
main関数に戻り、値を変数numに代入しています。
その後にprintf関数を実行してプログラムを終了します。

プログラムを実行した結果は次の通りです。

main関数の始まり:num=1
output関数を呼び出しました。
main関数の終わり:num=10

output() が返した値(10)が、main()num に代入されたことが確認できます。

補足(voidの意味)

voidの説明をしていなかったので、ここで補足しておきます。
voidは、「何もない」という意味です。
つまり、void output(void)というのは、引数も戻り値もない関数であるとことを表しています。
int output(void)は、戻り値はint型で、引数はない関数。
void output(int num)は、戻り値はなく、引数だけある関数。

まとめ

  • 関数は「処理をまとめて名前をつけたもの」
  • 関数を使うには、「定義」と「呼び出し」が必要
  • 引数を使うと、関数に値を渡すことができる
  • 戻り値を使うと、関数から値を返すことができる
  • 引数は「値渡し」のため、関数内で変更しても呼び出し元には影響しない
  • main()printf() も関数の一種

-C言語