C言語の学習を進めると、避けては通れないのが関数です。最初は「なんだか小難しそう…」「なんでわざわざ使うの?」なんて思うかもしれませんね。
この記事を読めば、関数の基本的なことから、実際の使い方、ちょっとした注意点までバッチリ分かります。さあ、一緒にC言語の関数をマスターして、プログラミングをもっと楽しく、効率的にしちゃいましょう!
この記事で学べること
- 関数がどんなもので、なぜプログラム作成に役立つのか
- 関数の基本的な作り方(定義のしかた)
- 関数をプログラム中で使う方法(呼び出し方)
- 関数に情報を渡す「引数」と、関数から結果を受け取る「戻り値」の仕組み
- 関数を使うときに気をつけるべき点
C言語の関数とは?プログラムを分かりやすく整理する考え方
C言語における関数とは、一連の処理をひとまとめにしたものです。例えば、画面にメッセージを表示する、二つの数字を足し算する、といった特定の作業を一つの「部品」として作っておくイメージです。
なぜ関数が役立つのでしょうか? プログラムが長くなったり複雑になったりすると、同じような処理をあちこちで書く必要が出てくることがあります。そんな時、関数としてまとめておけば、その処理が必要な時に「関数名」を呼び出すだけで済みます。
何度も同じコードを書かなくて良いので、タイプミスも減りますし、コード全体が短く、読みやすくなります。
料理で考えてみましょう。「野菜を切る」「お湯を沸かす」「炒める」といった作業をそれぞれ別の手順(関数)として覚えておけば、色々な料理(プログラム)を作る時に、手順を組み合わせるだけで済みますよね。関数も同じで、プログラムを小さな作業単位に分割して、管理しやすくするための仕組みなんです。
実は、皆さんがC言語で最初に書くであろう main
というのも、特別な関数の一つなんですよ。プログラムは main
関数から実行が始まります。
C言語の関数の基本的な書き方(関数の定義)
では、実際にどうやって関数を作る(定義する)のか、その基本形を見てみましょう。関数は主に4つの部分から構成されます。
戻り値の型 関数名(仮引数リスト) { // ここに関数が行う処理を書く // 例: 計算したり、文字を表示したり return 戻り値; // 関数が何か結果を返す場合 }
それぞれの部分を分解してみましょう。
- 戻り値の型
- 関数が処理を終えた後に、どんな種類のデータ(結果)を返すかを指定します。整数なら
int
、何も返さないならvoid
などです。 - 関数名
- 関数を呼び出すときに使う名前です。どんな処理をするか分かりやすい名前を付けるのがおすすめです。
- 仮引数リスト
- 関数が処理を行うために外部から受け取る情報(データ)を指定します。
(int a, int b)
のように、型と名前のペアで書きます。情報を受け取らない場合は(void)
または()
と書きます。 - 関数本体
{ }
で囲まれた部分で、実際に行う処理の命令を書きます。
例えば、二つの整数を受け取って、足し算した結果を返す関数は、こんな風に定義できます。
int add(int a, int b) { // int型の値を返し、int型の引数を2つ取るadd関数 int sum; // 計算結果を入れるための変数 sum = a + b; return sum; // 計算結果(sum)を返す }
値を返さない(画面に何か表示するだけ、など)関数の場合は、戻り値の型を void
にします。
void printHello(void) { // 何も返さず、引数も取らないprintHello関数 printf("Hello!\n"); // void型なので return 文は必須ではない }
戻り値の型:関数が返す「結果」の種類
関数が処理を終えたときに、呼び出し元に「結果」として返すデータの種類を「戻り値の型」で示します。主な型には以下のようなものがあります。
int
整数(例 10, -5, 0)float
/double
小数(例 3.14, -0.5)char
1文字(例 'a', 'B')void
何も返さない
関数の中で計算した結果や、処理の成否などを呼び出し元に伝えたい場合に、return
文を使います。return 値;
のように書くと、その「値」が関数の結果として返されます。例えば、return sum;
であれば、変数 sum
の中身が関数の結果となります。
void
型は値を返さない関数の目印です。 void
型の関数の場合、return
文は書かなくても良いですし、書く場合は処理を途中で終了させる目的で return;
のように値なしで記述します。
関数名:関数を呼び出すための「名前」
関数名は、その関数を識別し、呼び出すために使います。自分で関数を作る場合、自由に名前を付けられますが、いくつかルールと、分かりやすくするためのコツがあります。
ルールとしては、
- 英数字とアンダースコア
_
が使えます。 - 最初の文字は英字かアンダースコアである必要があります(数字はダメ)。
int
やwhile
のようなC言語のキーワード(予約語)は使えません。- 大文字と小文字は区別されます(
add
とAdd
は違う関数名とみなされます)。
そして、一番意識したいのは、関数が何をするのかが名前から推測できるようにすることです。
例えば、合計を計算するなら calculateSum
や addNumbers
、メッセージを表示するなら printMessage
のような名前が良いでしょう。func1
や a
のような名前は、後でコードを見返したときに「何をする関数だっけ?」となりがちです。
処理内容がわかる名前付けが、後々の自分を助けます。分かりやすい名前は、プログラム全体の読みやすさにも繋がります。
仮引数リスト:関数に渡す「情報」
関数が処理を行う際に、外部(呼び出し元)からデータを受け取りたい場合があります。その受け取るデータを入れるための「入り口」が「仮引数(かりひきすう)」です。関数定義の ( )
の中に、型名 変数名
の形で書きます。
// 例: 2つの整数を受け取る場合 int add(int number1, int number2) { ... } // 例: 1つの小数を受け取る場合 void printFloat(float value) { ... }
複数の引数が必要な場合は、カンマ ,
で区切って記述します。仮引数で宣言された変数(上の例だと number1
, number2
, value
)は、その関数の中だけで使うことができます。
もし、関数が外部から情報を受け取る必要がない場合は、( )
の中を空にするか、(void)
と書きます。
どちらでも動作しますが、引数を取らないことを明確に示すために (void)
と書く方が、より丁寧な書き方とされています。
// 引数を取らない関数の例 void sayGoodbye(void) { ... }
引数がない場合は ( ) の中を空にするか、(void) と書きます。
C言語の関数の使い方(関数の呼び出し)
関数を定義しただけでは、プログラム中でその処理は実行されません。定義した関数を使うには、「呼び出す」必要があります。関数の呼び出しはとてもシンプルです。
関数名(実引数リスト);
定義した「関数名」の後に ( )
を付け、もし関数が引数を必要とするなら、( )
の中に渡したい値(実引数)を書きます。複数の実引数がある場合は、カンマ ,
で区切ります。
例えば、先ほど定義した add
関数や printHello
関数を呼び出すには、以下のように書きます。
int main() { int result; // add関数を呼び出し、引数として 5 と 3 を渡す // 戻り値(計算結果)を変数 result で受け取る result = add(5, 3); printf("計算結果: %d\n", result); // result を表示 // printHello関数を呼び出す (引数なし、戻り値なし) printHello(); return 0; }
ここで注意したいのが「仮引数」と「実引数」の違いです。
- 仮引数 関数を定義するときに書く、値を受け取るための変数名 (例:
int add(int a, int b)
のa
とb
)。 - 実引数 関数を呼び出すときに実際に渡す値や変数 (例:
add(5, 3)
の5
と3
)。
関数が呼び出されると、実引数の値が仮引数にコピーされて、関数本体の処理が実行されます。add(5, 3)
の呼び出しでは、a
に 5
が、b
に 3
が入った状態で add
関数の処理が始まるわけです。
戻り値がある関数の場合、その戻り値は呼び出し元の式の一部として使えます。result = add(5, 3);
のように変数に代入したり、printf("答えは %d\n", add(10, 20));
のように直接別の関数の引数として使ったりもできます。
C言語の関数を使ったサンプルプログラム
さて、理屈は分かってきたところで、実際に動くプログラムを見てみましょう! ここでは、簡単な関数を2つ作り、それを main
関数から呼び出すサンプルを示します。
実際にコードを書いて、コンパイルして、実行してみるのが理解への一番の近道です。ぜひお手元の環境で試してみてくださいね。
サンプル1:2つの整数の合計を計算して返す関数
まずは、整数を2つ受け取って、その合計を計算して返す add
関数を使った例です。戻り値がある関数の典型的な使い方になります。
#include <stdio.h> // ----- 関数の定義 ここから ----- // 機能:2つの整数 a と b を受け取り、その合計を返す // 戻り値:int型 (合計値) // 引数:int a (1つ目の整数), int b (2つ目の整数) int add(int a, int b) { int sum = a + b; // a と b を足して変数 sum に入れる return sum; // sum の値を返す } // ----- 関数の定義 ここまで ----- int main() { int num1 = 10; int num2 = 20; int answer; // 関数の戻り値を受け取るための変数 // ----- 関数の呼び出し ここから ----- // add関数を呼び出し、num1 と num2 を引数として渡す // add関数が返した値(計算結果)が answer に入る answer = add(num1, num2); // ----- 関数の呼び出し ここまで ----- printf("%d + %d = %d\n", num1, num2, answer); // 直接、関数の呼び出し結果を printf の引数に使うこともできる printf("5 + 8 = %d\n", add(5, 8)); return 0; }
このコードをコンパイルして実行すると、次のような結果が表示されるはずです。
10 + 20 = 30 5 + 8 = 13
main
関数の中で add(num1, num2)
と書くことで、add
関数が呼び出されています。num1
の値 10
が仮引数 a
に、num2
の値 20
が仮引数 b
に渡され、add
関数内で計算された結果 30
が return sum;
によって返されます。return
文で返された値が、呼び出し元の変数 answer
に代入されています。 2回目の printf
では、add(5, 8)
の戻り値 13
が直接使われていますね。
サンプル2:メッセージを表示する関数 (戻り値なし)
次は、特定のメッセージを画面に表示するだけの、戻り値がない (void
型の) 関数 printMessage
の例です。引数も受け取らないようにしてみましょう。
#include <stdio.h> // ----- 関数の定義 ここから ----- // 機能:固定のメッセージを画面に表示する // 戻り値:void (何も返さない) // 引数:void (何も受け取らない) void printMessage(void) { printf("Hello from the function!\n"); // void型なので、return文は省略可能 } // ----- 関数の定義 ここまで ----- int main() { printf("Calling the function first time...\n"); // ----- 関数の呼び出し ここから ----- printMessage(); // printMessage関数を呼び出す // ----- 関数の呼び出し ここまで ----- printf("Calling the function second time...\n"); // ----- 関数の呼び出し ここから ----- printMessage(); // もう一度呼び出す (何度でもOK) // ----- 関数の呼び出し ここまで ----- return 0; }
実行結果は以下のようになります。
Calling the function first time... Hello from the function! Calling the function second time... Hello from the function!
main
関数内で printMessage();
と書くことで、printMessage
関数が呼び出され、その中の printf
文が実行されています。void
型の関数は、何か値を返すわけではないので、answer = printMessage();
のように戻り値を受け取る書き方はできません(エラーになります)。void
型の関数は、呼び出しても値が返ってこないので、変数で受け取ることはしません。 ただ処理を実行させたいだけの場合に便利です。
C言語の関数を使う上でのポイント・注意点
関数は非常に便利ですが、いくつか知っておくと良いポイントや、初心者がつまずきやすい注意点があります。ここでは特に「関数プロトタイプ宣言」と「変数のスコープ」について見ていきましょう。
関数プロトタイプ宣言:関数の「紹介状」
C言語では、基本的にプログラムは上から下に読まれて処理されます。もし、関数を呼び出すコードよりも「後」に、その関数の定義が書かれている場合、コンパイラ(プログラムを機械語に翻訳するやつ)は呼び出し時点で「そんな名前の関数、知らないよ?」となってしまい、エラーや警告を出すことがあります。
それを解決するのが「関数プロトタイプ宣言」です。これは、プログラムの(通常は)先頭の方で、「これから、こんな形の関数を使いますよ」と、事前に関数の名前、戻り値の型、引数の型リストだけをコンパイラに教えてあげる記述です。いわば、関数の「紹介状」のようなもの。
書き方は、関数定義の最初の行(ヘッダー)の最後にセミコロン ;
を付けるだけです。
#include <stdio.h> // ----- 関数プロトタイプ宣言 ここから ----- int add(int a, int b); // add関数のプロトタイプ宣言 (引数名は省略しても良い: int add(int, int);) void printHello(void); // printHello関数のプロトタイプ宣言 // ----- 関数プロトタイプ宣言 ここまで ----- int main() { int sum = add(10, 5); // 定義は下にあるけど、宣言があるのでOK printf("Sum: %d\n", sum); printHello(); // 定義は下にあるけど、宣言があるのでOK return 0; } // ----- 関数の定義 ここから ----- // (main関数よりも後に定義を書いても大丈夫) int add(int a, int b) { return a + b; } void printHello(void) { printf("Hello!\n"); } // ----- 関数の定義 ここまで -----
このようにプロトタイプ宣言をしておけば、関数の定義が main
関数より後(あるいは別のファイル)にあっても、コンパイラは関数の形を認識できるので、問題なく呼び出すことができます。
関数定義をmain関数より後に書く場合、プロトタイプ宣言がないとコンパイラが関数の形を知らずエラーになることがあります。 多くの標準ライブラリ関数(printf
など)も、stdio.h
といったヘッダーファイル内でプロトタイプ宣言されているからこそ、私達は定義を知らなくても使えるのです。
変数のスコープ:関数内で生まれた変数の寿命
関数の中で宣言された変数(これを「ローカル変数」と呼びます)は、原則として、その関数の中だけで有効です。関数の処理が終わると、そのローカル変数は消えてしまいます。これを変数の「スコープ(有効範囲)」と言います。
例えば、ある関数 myFunc
の中で int count = 0;
と宣言した場合、変数 count
は myFunc
の { }
の中でしか使えません。main
関数や、他の関数から count
変数を直接参照したり、値を変更したりすることはできないのです。
#include <stdio.h> void myFunction() { int localVar = 100; // myFunction のローカル変数 printf("myFunctionの中: localVar = %d\n", localVar); // ここで localVar は使える } int main() { int mainVar = 50; // main のローカル変数 printf("mainの中: mainVar = %d\n", mainVar); myFunction(); // myFunction を呼び出す // printf("mainからlocalVarを参照: %d\n", localVar); // エラー! localVarはここから見えない return 0; }
もし最後のコメントアウトされた printf
文を実行しようとすると、コンパイル時に「localVar
なんて変数は定義されていませんよ」というエラーが出ます。localVar
は myFunction
の「部屋」の中だけで使える道具であり、main
関数の「部屋」からは見えない、と考えれば分かりやすいかもしれません。
この仕組みがあるおかげで、関数ごとに独立して変数を使えるため、他の関数で同じ変数名を使っていたとしても、互いに影響を与えずに済みます。プログラム全体の見通しが良くなり、予期せぬバグを防ぐのに役立ちます。
関数内で宣言した変数は、基本的にその関数の { } の中でしか使えません。
まとめ
お疲れ様でした! 今回はC言語の関数の基本について、かなり詳しく見てきましたね。もう一度、ポイントをおさらいしておきましょう。
- 関数は処理をまとめた「部品」で、コードの再利用性や可読性を高める。
- 関数を作るには「定義」が必要で、戻り値の型、関数名、仮引数リスト、関数本体から成る。
- 関数を使うには「呼び出し」が必要で、関数名と実引数を指定する。
- 「引数」で関数に情報を渡し、「戻り値」で関数から結果を受け取れる (
void
型は返さない)。 - 関数を呼び出す前に定義がない場合は「プロトタイプ宣言」が必要になることがある。
- 関数内で宣言した変数(ローカル変数)は、その関数の中だけで有効(スコープ)。
関数を理解し、使いこなせるようになると、C言語でのプログラミングが格段に楽になりますし、作れるプログラムの幅も広がります。最初は少し戸惑うかもしれませんが、実際に自分で簡単な関数を作って動かしてみるのが一番です。
【関連記事】
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。