C言語でプログラムを書いていると、同じような処理を何度も書く場面が出てきます。
そのたびに同じコードをコピーしていると、ミスが増えたり、修正が大変になったりします。
そこで登場するのが関数です。
本記事では、関数の引数と戻り値に焦点を当てて、C言語初心者の方にも分かりやすいように、実際のサンプルコードを交えながら丁寧に解説していきます。
C言語の関数とは
関数の基本構造(戻り値 型名 関数名(引数)…)
C言語の関数は、特定の処理に名前を付けてまとめたものです。
最も基本的な書き方は次の形になります。
戻り値の型 関数名(引数の型 引数名, ...) という形式です。
関数の一般的な形
// 戻り値の型: int
// 関数名: add
// 引数: int a, int b
int add(int a, int b) {
int result; // 計算結果を保存する変数
result = a + b; // a と b を足し算
return result; // 計算結果を呼び出し元へ返す
}
この例では、戻り値の型としてintを指定しています。
つまりこの関数addは、int型の値を1つ返す関数です。
関数の基本構造を表に整理すると次のようになります。
| 部分 | 例 | 役割 |
|---|---|---|
| 戻り値の型 | int | 関数が返す値の型を指定します |
| 関数名 | add | 関数を呼び出すときに使う名前です |
| 引数リスト | int a, int b | 関数に渡す値(入力)を定義します |
| 関数本体 | { ... } | 実際に処理を書きます |
戻り値の型・関数名・引数・本体の4つを押さえておくと、関数の読み書きがしやすくなります。
main関数と自作関数の違い
C言語のプログラムは、必ずmain関数から実行が始まります。
このmain関数も、他の関数と同じく「関数」の一種ですが、いくつか特徴があります。
main関数の特徴
#include <stdio.h>
int main(void) {
// プログラムの最初に実行される場所
printf("Hello, C language!\n");
return 0; // OS に終了コード0を返す(正常終了の意味)
}
main関数には、次のような特徴があります。
1つ目に、プログラムの入り口になる特別な関数であることです。
C言語の処理は必ずmainから始まり、mainが終わるとプログラム全体も終了します。
2つ目に、戻り値の型が通常intに決まっていることです。
return 0;のように整数を返すことで、プログラムの終了状態をOSに知らせます。
これに対して、自分で作る関数(自作関数)は次のような違いがあります。
- 関数名は自由に決められる(
addやprint_messageなど) - 戻り値の型も自由に決められる(
int、double、voidなど) - プログラムの中で必要になったときに
mainや他の関数から呼び出される
main関数は「入口」、自作関数は「部品」と考えると分かりやすいです。
関数を使うメリット
関数を使うと、プログラムの書き方や管理の仕方が大きく改善されます。
特に初心者のうちから意識しておきたいメリットは次の3つです。
1つ目は同じ処理を何度も書かなくてよくなることです。
足し算や平均値の計算、メッセージ表示などを関数にしておけば、必要なときに呼び出すだけで済みます。
2つ目はプログラムの見通しがよくなることです。
長いmainの中に全部の処理を書くと、後で読みにくくなりますが、処理ごとに関数に分けることで「何をしているか」がすぐに分かります。
3つ目はバグ修正や機能変更が簡単になることです。
例えば、平均値の計算方法を変えたくなった場合に、その関数だけ修正すれば、呼び出している場所は修正不要になります。
このように、関数はコードの再利用性・読みやすさ・保守性を高めるための重要な仕組みです。
C言語の引数とは
引数の役割
引数とは、関数に渡す入力データのことです。
関数はこの引数をもとに処理を行い、その結果を戻り値として返します。
例えば「2つの数の和を計算する関数」を考えるとき、足される数と足す数を関数に渡す必要があります。
この2つが引数です。
int add(int a, int b) {
return a + b; // a と b は「引数」
}
この例ではaとbが引数であり、関数の中で自由に使える変数として扱われます。
「関数に必要な材料を渡す仕組み」が引数だとイメージするとよいです。
引数の宣言方法と型
引数を使うには、関数の宣言部分で「型」と「名前」をセットで書く必要があります。
単純な引数宣言の例
// 1つの int 型引数を受け取る関数
int square(int x) {
return x * x;
}
// 1つの double 型引数を受け取る関数
double half(double value) {
return value / 2.0;
}
引数の宣言では、次の2点が重要です。
1つ目に引数の型を指定することです。
intやdoubleなど、通常の変数と同じように型を書きます。
2つ目に引数の名前を決めることです。
この名前は、関数の中でその値を参照するために使われます。
関数の外の変数名とは別物です。
例えばint xという引数宣言は、「整数型の入力データを1つ受け取り、そのデータを関数内ではxという名前で使う」という意味になります。
複数の引数と順番のルール
関数は、カンマで区切って複数の引数を定義できます。
ただし、引数の順番はとても重要です。
複数引数の例
// 2つの整数を受け取り、その差(a - b)を返す関数
int subtract(int a, int b) {
return a - b;
}
int main(void) {
int x = 10;
int y = 3;
int result1, result2;
result1 = subtract(x, y); // 10 - 3 = 7
result2 = subtract(y, x); // 3 - 10 = -7 (順番が逆なので結果も違う)
return 0;
}
この例では、subtract関数の引数は(int a, int b)の順番で定義されています。
呼び出し時にsubtract(x, y)と書くとa = x、b = yが対応します。
引数に関する重要なルールは次の通りです。
- 引数は左から順に、呼び出し側の値が対応する
- 型の数と順番も一致していなければならない
- 引数の順番を間違えると、意図しない計算結果になる
初心者のうちは、「引数は位置で対応する」という点を意識して、名前だけで判断しないようにすることが大切です。
実引数と仮引数の違い
引数には、実引数と仮引数という2つの用語があります。
意味の違いを理解しておくと、関数の動作がイメージしやすくなります。
用語の整理
| 用語 | 読み方 | 意味 |
|---|---|---|
| 仮引数 | かりひきすう | 関数定義側で書く引数(受け取る側) |
| 実引数 | じつひきすう | 関数を呼び出すときに渡す値(渡す側) |
サンプルで確認
#include <stdio.h>
// 仮引数: int a, int b
int add(int a, int b) {
return a + b;
}
int main(void) {
int x = 5;
int y = 7;
int ans;
// 実引数: x, y
ans = add(x, y); // x の値が a に、y の値が b に渡される
printf("答えは %d です\n", ans);
return 0;
}
ここで、
int add(int a, int b)のaとbが仮引数add(x, y)のxとyが実引数
です。
イメージとしては、実引数の「値」が仮引数にコピーされると考えると分かりやすいです。
引数なしの関数(void引数)の書き方
関数の中には、引数を必要としないものもあります。
例えば、「固定のメッセージを表示するだけ」の関数などです。
そのような場合は、引数リストにvoidと書きます。
引数なしの関数の例
#include <stdio.h>
// 引数なし、戻り値なしの関数
void print_hello(void) {
printf("こんにちは、C言語の世界!\n");
}
int main(void) {
print_hello(); // 引数は渡さない
return 0;
}
ポイントは次の2つです。
1つ目に、関数定義側の引数リストにvoidと書くことです。
これは「何も受け取りません」という宣言になります。
2つ目に、呼び出し側ではprint_hello();のように何も渡さないことです。
カッコの中は空にしておきます。
このように、引数が不要な場合はvoidを使って明示的に「受け取らない」と書くのがC言語のスタイルです。
C言語の戻り値とは
戻り値の役割
戻り値とは、関数が処理した結果として、呼び出し元に返す値です。
例えば、足し算の結果や、平均値の計算結果などが戻り値になります。
int add(int a, int b) {
int result = a + b;
return result; // これが戻り値
}
呼び出し側では、この戻り値を変数に代入したり、さらに別の計算に使えます。
int x = add(3, 4); // add(3, 4) の戻り値 7 が x に入る
「関数の出力」が戻り値と考えるとよいです。
引数が入力、戻り値が出力という関係になります。
戻り値の型とreturn文の使い方
戻り値は、関数の宣言で指定した型と一致していなければなりません。
また、戻り値を返すためにはreturn文を使います。
基本的なreturn文の例
// int 型を返す関数
int double_int(int x) {
return x * 2; // int 型の値を返す
}
// double 型を返す関数
double double_double(double x) {
return x * 2.0; // double 型の値を返す
}
ここで重要なのは、戻り値の「型」とreturnで返す式の「型」が一致していることです。
また、return文には2つの役割があります。
1つ目に値を呼び出し元に返すことです。
2つ目に関数の処理をその場で終了することです。
例えば次のようなコードでは、returnの後の行は実行されません。
int sample(int x) {
return x + 1;
// ここに何か書いても実行されない
}
戻り値あり関数と戻り値なし関数
C言語の関数には、戻り値がある関数と戻り値がない関数の2種類があります。
戻り値あり(非void)の関数
int add(int a, int b) {
return a + b; // int の値を返す
}
戻り値ありの関数は、計算結果を使いたい場合に便利です。
例えば、結果を変数に入れて後で利用したり、別の関数に渡したりできます。
戻り値なし(void)の関数
#include <stdio.h>
// 戻り値なしの関数
void print_message(void) {
printf("処理が完了しました。\n");
}
voidを戻り値の型に指定すると、「何も返さない」という意味になります。
そのため、この関数内でreturn;を書く場合は、値を指定せずにreturn;だけを書きます。
「何かを計算して結果が必要」なら戻り値あり、「画面表示だけする」なら戻り値なしというように、役割に応じて使い分けるとよいです。
1つしか返せない戻り値と設計の考え方
C言語の関数は、戻り値を1つしか返せません。
例えば、「合計」と「平均」の2つを同時に返したい、といったことは直接はできません。
この制約を踏まえて、次のような設計の工夫が必要になります。
1つの方法は、本当に必要な結果だけを戻り値にするという考え方です。
例えば「計算が成功したかどうか」を戻り値として0や1で返すなどです。
もう1つの方法は、戻り値以外の手段で複数の値を扱うことです。
ポインタや配列を使って、複数の結果を関数の外側の変数に書き込む方法がありますが、これは少しレベルが上がるため、初心者のうちは「戻り値は1つだけ」と覚えておけば十分です。
設計のポイントとしては、「その関数は何をしたい関数なのか」を明確にし、最も重要な1つを戻り値にするという意識を持つことです。
サンプルコードで学ぶ引数と戻り値
ここからは、具体的なサンプルコードを通して、引数と戻り値の使い方を確認していきます。
足し算関数
まずはとてもシンプルな「2つの整数を足し算する関数」です。
#include <stdio.h>
// 2つの int 型の数値を受け取り、その和を返す関数
int add(int x, int y); // 関数宣言(プロトタイプ宣言)
int main(void) {
int a = 10;
int b = 20;
int sum;
// add 関数を呼び出し、戻り値を sum に代入
sum = add(a, b);
printf("a と b の合計は %d です。\n", sum);
return 0;
}
// 関数定義
int add(int x, int y) {
int result;
// x と y を足し算
result = x + y;
// 足し算の結果を呼び出し元へ返す
return result;
}
a と b の合計は 30 です。
この例では、
- 引数
(int x, int y)が入力 resultをreturn result;で戻り値として返す
という形で、引数と戻り値がセットで動いていることが確認できます。
平均値を計算する関数
次に、2つの整数の平均値をdouble型で返す関数を作成してみます。
ここでは、異なる型を組み合わせて使う点にも注目してみてください。
#include <stdio.h>
// 2つの int 型の数の平均を double 型で返す関数
double average(int a, int b); // 関数宣言
int main(void) {
int x = 5;
int y = 8;
double ave;
ave = average(x, y); // 戻り値を ave に代入
printf("%d と %d の平均は %f です。\n", x, y, ave);
return 0;
}
// 関数定義
double average(int a, int b) {
double result;
// (a + b) / 2 の結果を double 型として計算
result = (a + b) / 2.0;
return result;
}
5 と 8 の平均は 6.500000 です。
ここでのポイントは、戻り値の型がdoubleであり、計算式の中でも2.0のように小数を使っていることです。
これにより、整数同士の割り算ではなく、小数を含む割り算になります。
「どの型で返したいか」を意識して、戻り値の型を決めることが重要です。
メッセージを表示する関数
次は、戻り値なし・引数ありの例として、メッセージを表示する関数を作ってみます。
#include <stdio.h>
// 名前を受け取り、あいさつメッセージを表示する関数
void greet(int hour); // 関数宣言
int main(void) {
greet(10); // 10時としてあいさつ
greet(18); // 18時としてあいさつ
return 0;
}
// 関数定義
void greet(int hour) {
// hour の値によってあいさつを変える
if (hour < 12) {
printf("おはようございます。\n");
} else if (hour < 18) {
printf("こんにちは。\n");
} else {
printf("こんばんは。\n");
}
// 戻り値はないので return は省略してもよい
}
想定される実行結果の例は次のようになります。
おはようございます。
こんにちは。
この関数greetは、引数hourをもとに表示内容を変えていますが、画面に表示するだけで戻り値は必要ないため、戻り値の型はvoidになっています。
判定結果を返す関数
次に、戻り値を使って「判定結果」を返す例として、整数が偶数か奇数かを判定する関数を作ります。
#include <stdio.h>
// 整数 n が偶数なら 1、奇数なら 0 を返す関数
int is_even(int n); // 関数宣言
int main(void) {
int value = 7;
if (is_even(value)) {
// is_even(value) が 1 のときに実行される
printf("%d は偶数です。\n", value);
} else {
// is_even(value) が 0 のときに実行される
printf("%d は奇数です。\n", value);
}
return 0;
}
// 関数定義
int is_even(int n) {
if (n % 2 == 0) {
return 1; // 偶数の場合は 1 を返す
} else {
return 0; // 奇数の場合は 0 を返す
}
}
7 は奇数です。
この例では、戻り値を「状態のフラグ」として使っている点がポイントです。
1や0で「はい・いいえ」を表現し、if文で分岐に利用しています。
このように、戻り値は「計算結果」だけでなく、処理が成功したかどうか・条件を満たしているかどうかなどの判定にもよく使われます。
関数宣言(プロトタイプ宣言)と定義・呼び出しの流れ
最後に、関数宣言(プロトタイプ宣言)と定義・呼び出しの関係を、簡単なサンプルで整理します。
C言語では、関数を呼び出す前に「このような関数がある」と知らせておく必要があります。
これがプロトタイプ宣言です。
#include <stdio.h>
// プロトタイプ宣言: コンパイラに「こんな関数があります」と知らせる
int add(int a, int b);
void print_result(int value);
int main(void) {
int x = 3;
int y = 4;
int sum;
// 関数呼び出し
sum = add(x, y);
// 結果を表示する関数の呼び出し
print_result(sum);
return 0;
}
// 関数定義: 実際の処理の中身を書く部分
// 2つの整数の和を返す関数
int add(int a, int b) {
return a + b;
}
// 結果を表示する関数(戻り値なし)
void print_result(int value) {
printf("計算結果は %d です。\n", value);
}
計算結果は 7 です。
ここで、関数の流れを整理してみます。
1つ目に、プロトタイプ宣言です。
int add(int a, int b); のように、;で終わる形で宣言だけを行います。
これにより、コンパイラは「addという関数があって、引数はintが2つ、戻り値はint」と理解します。
2つ目に、関数の呼び出しです。
sum = add(x, y);のように書くことで、add関数が実行され、戻り値がsumに代入されます。
3つ目に、関数定義です。
ファイルの後半にint add(int a, int b) { ... }のように、本体を書く部分があります。
ここで実際の計算処理を記述します。
このように、「宣言」→「呼び出し」→「定義」という3つの段階を意識しておくと、複数の関数を含む大きなプログラムでも整理しやすくなります。
まとめ
本記事では、C言語の関数の引数と戻り値について、基本構造から具体的なサンプルコードまで詳しく解説しました。
引数は関数への「入力」、戻り値は関数からの「出力」という役割を持ちます。
関数を使いこなすことで、処理を分割し、再利用性や読みやすさを高めることができます。
初心者の方は、まずは足し算・平均・判定などのシンプルな関数を自分で書き、引数と戻り値の流れを体で覚えていくと良いでしょう。
