関数

| Topic path: Top / 授業 / C言語基礎 / 関数

これまでに、標準で用意されている関数として、printf関数、scanf関数、rand関数、srand関数、time関数を使ってきました。

これらは、それぞれ特定の機能を実行するための処理をまとめたもので、これを''関数''といいます。



*関数の呼び出し [#u320153f]

プログラムの中で関数を使うことを、関数の''呼び出し''といいます。

関数を呼び出すときは、必ず、関数の名前の後に括弧 ( ) を付けます。

( ) の中には、関数に渡す変数を記述します。
関数に渡す変数のことを''引数''といいます。
複数の引数を渡すときは、引数をコンマ , で区切って指定します。

また、呼び出すと、その結果を返してくれる関数もあります。
返してくれる値のことを''戻り値''といいます。

たとえば、srand関数は、乱数のシードを引数として受け取り、戻り値を返さない関数です。
#geshi(c){{
  srand(1);
}}

rand関数は、引数なしで、int型の値を戻り値として返す関数です。
#geshi(c){{
  int r = rand();
}}

普通の関数は引数の数が決まっていますが、printf関数とscanf関数のように、引数の数が決まっていない関数もあります。
#geshi(c){{
  int i = 0;

  printf("Hello World!\n");
  printf("i = %d\n", i);
}}

ちなみに、printf関数とscanf関数はint型の値を戻り値として返しますが、これまで、戻り値を無視していました。
printf関数は出力した文字数を、scanf関数は代入された値の数を返します。



*関数の定義 [#i5bd75d0]

関数は自分で作ることができます。
これを、関数を''定義''するといいます。
関数を作ることを、「関数を''定義''する」といいます。



**引数と戻り値がある関数の定義 [#na622bb2]

関数を定義するには、次のようにします。
#geshi(c){{
戻り値の型 関数の名前(引数1の型 引数1の名前, 引数2の型 引数2の名前, ...) {
  処理
  return 戻り値;
}
}}
同じ型の引数を複数使うときでも、型を省略できないことに注意しましょう。

たとえば、二つのint型の値の和を返す関数addを次のように定義できます。
#geshi(c){{
int add(int x1, int x2) {
  int y = x1 + x2;  
  return y;
}
}}

これを呼び出すプログラムは、次のようになります(プログラム1)。
#geshi(c){{
#include <stdio.h>

int add(int x1, int x2) {
  int y = x1 + x2;  
  return y;
}


int main(void) {
  int i = 1, j = 2, k;
  
  k = add(i, j);
  printf("%d\n", k);
  
  return 0;
}
}}
このように、引数として渡す変数の名前と引数として受け取る変数の名前が同じである必要はありません。



**演習1 [#mbf19437]

プログラム1を作成し、実行結果を確認せよ。



**引数がない関数の定義 [#oedbd187]

引数がない関数を定義するときは、''仮引数''として ''void'' と定義します。
#geshi(c){{
戻り値の型 関数の名前(void) {
  処理
  return 戻り値;
}
}}
呼び出すときは、引数に何も指定しません。

たとえば、サイコロを振る(引数がない)関数を定義すると、次のようになります(プログラム2)。
#geshi(c){{
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int dice(void) {
  int r = rand() % 6 + 1;
  return r;
}


int main(void) {
  int r;

  srand((unsigned int) time(NULL));  // 乱数のシード
  r = dice();
  
  printf("%d\n", r);
  
  return 0;
}
}}


**演習2 [#he2b796c]

プログラム2を作成し、実行結果を確認せよ。




**戻り値がない関数の定義 [#ib9cc723]

戻り値がない関数を定義するときは、戻り値の型を ''void'' として定義します。
また、return文には、戻り値を指定しません。
(関数の最後にある戻り値のないreturn文は、省略できます。)
#geshi(c){{
void 関数の名前(引数) {
  処理
  return;
}
}}

たとえば、指定された回数Hello World!と表示する(戻り値がない)関数を定義すると、次のようになります(プログラム3)。
#geshi(c){{
#include <stdio.h>

void hello(int n) {
  int i;

  for (i = 1; i <= n; i++) {
    printf("Hello World!\n");
  }

  return;
}


int main(void) {
  hello(5);

  return 0;
}
}}



**演習3 [#hf18b253]

プログラム3を作成し、実行結果を確認せよ。



*特別な関数 main [#o5e6ede1]

実は、これまでのプログラムでも、関数を定義していました。

それが、特別な関数、''main関数''です。

main関数は次のように定義していました。
#geshi(c){{
int main(void) {
  処理
  return 0;
}
}}
これは、名前がmainで、引数なし、戻り値がint型の関数です。

main関数は、プログラムが実行されたときに、最初に呼び出されます。

プログラムが終了すると、main関数の戻り値がOSへ返されます。
main関数から 0 が返されると、OSはプログラムが正常に終了したと判断し、1 が返されると、OSはプログラムが異常に終了したと判断します。

main関数は、特別に、return文を省略でき、省略すると 0 が返されます。
また、main関数は、特別に、戻り値の型の宣言を省略できます。
#geshi(c){{
int main(void) {
  printf("Hello World!\n");
}
}}
#geshi(c){{
main(void) {
  printf("Hello World!\n");
  return 0;
}
}}

昔は、main関数の戻り値はありませんでした。
ですから、古い教科書では、main関数の戻り値の型をvoidとしているものがあります。
今は、main関数の戻り値の型をvoidにすることはできません。

また、main関数には、プログラムを実行するときに指定されたコマンドライン引数を渡すことができます。
コマンドライン引数については、もう少し先に進んでから後で勉強します。




*関数の中で宣言した変数の有効範囲 [#t4ba4657]
*関数の中で宣言した変数の有効範囲(おまけ) [#t4ba4657]

関数の中で宣言した変数は、その関数の中だけで有効です。

次のプログラムでは、print1関数とmain関数のそれぞれで変数 i が宣言されています(プログラム4)。
#geshi(c){{
#include <stdio.h>

void print1(void) {
  int i = 1;
  printf("%d\n", i);
}

int main(void) {
  int i = 0;

  print1();
  printf("%d\n", i);

  return 0;
}
}}
main関数で宣言された変数 i とprint1関数で宣言された変数 i は、コンピューターのメモリーの中では別の場所に記憶されていて、同姓同名の別人のように、同じ名前だけど別の変数として扱われます。
最初にmain関数において変数 i に 0 を代入し、その後、print1関数において変数 i に 1 を代入していますが、print1関数で宣言された変数 i はmain関数で宣言された変数 i とは別の変数なので、print1関数の変数 i に 1 を代入してもmain関数の変数 i の値は 0 のままで変更されません。

これを実行すると、次のようになります。
#geshi(sh){{
luna% a.out
1
0
}}


**演習4 [#h043e1bd]
プログラム4を作成し、実行結果を確認せよ。



----
*まとめ [#o9611338]

複数の処理をまとめたものを''関数''といい、プログラムの中に関数を用意することを「関数を''定義''する」、プログラムの中で関数を使用することを「関数を''呼び出す''」といいます。

関数を呼び出すときに関数に渡す値を''引数''といい、関数が戻す値を''戻り値''といいます。

''引数がない関数''も定義できます。
引数がない関数を定義するときは、引数として''仮引数 void'' を指定します。

''戻り値がない関数''も定義できます。
戻り値がない関数を定義するときは、戻り値の型として ''void'' を指定します。

''関数の中で宣言された変数''は、その関数の中だけで有効です。
他の関数からは見えません。


----
*練習問題 [#u7c26afd]
**08A-1 関数の呼び出し(難易度★) [#n95256a2]
次の空欄部分を補って、int型の引数を2つ受け取るとその積を返す関数 add 呼び出し、3 + 5 を計算して出力するプログラムを完成させよ。
#geshi(c){{
int add(int x, int y) {
  int z;
  z = x + y;
  return z;
}

int main(void) {
  int a = 3, b = 5, c;
  c =         ;
  printf("%d\n", c);
  return 0;
}
}}

**08A-2 関数の定義(難易度★) [#xf1286fe]
次の空欄部分を補って、int型の引数を2つ受け取るとその積を返す mult という名前の関数を定義し、その関数を呼び出して 3 * 5 を計算するプログラムを完成させよ。
#geshi(c){{
    mult(        ) {
  int z;
  z =         ;
  return z;
}

int main(void) {
  int a = 3, b = 5, c;
  c = mult(a, b);
  printf("%d\n", c);
  return 0;
}
}}

**08A-3 引数のない関数の定義(難易度★) [#re4a9ae5]
次の空欄部分を補って、0 を返す zero という名前の関数を定義し、その関数を呼び出すプログラムを完成させよ。
#geshi(c){{
    zero(        ) {
  return 0;
}

int main(void) {
  int z;
  z = zero();
  printf("%d\n", z);
  return 0;
}
}}

**08A-4 戻り値のない関数の定義(難易度★) [#p39edcb6]
次の空欄部分を補って、呼び出されると Hello World! と出力する hello という名前の関数を定義し、その関数を呼び出すプログラムを完成させよ。
#geshi(c){{
    hello(        ) {
  printf("Hello World!\n");
  return;
}

int main(void) {
  hello();
  return 0;
}
}}

練習問題は[[こちら>授業/C言語基礎/関数/練習問題]]。
トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS