閉じる

【C言語】 関数の作り方と呼び出し方 基本の書き方と実行例

C言語で安全かつ読みやすいプログラムを書くためには、関数の定義と呼び出しの基本を丁寧に押さえることが近道です。

本記事では、関数の構成要素、定義の書き方、呼び出しのポイントを順を追って解説し、最後に実行可能なサンプルを示します。

戻り値や引数の型を正しく扱うことを中心に、初心者がつまずきやすい注意点も補足します。

C言語の関数の基本

C言語の関数とは

関数とは、ある処理をひとまとまりにして名前を付け、必要に応じて呼び出せるようにした部品です。

入力(引数)を受け取り、結果(戻り値)を返すことで、同じ処理を何度でも再利用できます。

C言語には標準ライブラリの関数に加えて、プログラマが自分で作るユーザー定義関数があります。

関数の構成(戻り値/関数名/引数/本体)

関数は次の4要素で構成されます。

行頭の型が戻り値の型、続く識別子が関数名、丸括弧内が引数リスト、波括弧の中が本体です。

C言語
戻り値の型 関数名(引数リスト) { 
    本体
}

以下の表に役割を整理します。

構成要素役割記述例
戻り値の型関数が返す値の型を表しますintvoiddouble
関数名呼び出し時に使う識別子ですaddprint_line
引数リスト呼び出し時に渡す値の型と名前ですint a, int bvoid(引数なし)
本体実際の処理を書きます{ /* 手続き */ return a + b; }

戻り値がない関数は型にvoidを使います。

引数がない場合もvoidと書きます。

main関数とユーザー定義関数

Cプログラムはmain関数から実行が始まります。

ユーザー定義関数はmainから呼び出される側で、mainの前に定義するか、少なくともプロトタイプ宣言を前に置いておく必要があります。

本記事では単一ファイル内で「使う前に定義する」方針を基本に解説します(複数ファイルやヘッダの分割は別記事で扱います)。

関数の定義の書き方

基本構文(関数定義)

関数定義のひな型を示します。

コメントで各部の意味を確認してください。

C言語
// 戻り値の型 関数名(引数の型 引数名, ...) { 本体 }
int add(int x, int y) {           // 戻り値: int, 関数名: add, 引数: xとyはint
    int sum = x + y;               // 本体: 計算処理
    return sum;                    // 戻り値を返す
}

void print_line(void) {            // 戻り値なし(void)、引数なし(void)
    // 本体: 1行の飾り線を表示するだけ
    puts("---------------");
}

戻り値を返す関数ではreturn文が必須です。

戻り値がvoidの関数ではreturn;を省略可能ですが、早期終了したい場合は書けます。

戻り値ありの定義例(int)

2つの整数を足し算するadd関数の定義例です。

C言語
// 2つのintを受け取り、その和をintで返す
int add(int a, int b) {
    return a + b; // 計算結果を呼び出し元へ返す
}

計算結果を変数に格納しても、直接return a + b;としても構いません。

戻り値なしの定義例(void)

メッセージだけを表示するvoid関数の例です。

C言語
// 画面に挨拶を表示するだけの手続き
void greet(const char *name) {
    // printfはフォーマット済み出力を行う標準ライブラリ関数
    printf("Hello, %s!\n", name);
}

副作用(表示や書き込み)が目的の関数ではvoidがよく使われます。

使う前に定義する(単一ファイル)

Cでは関数を呼び出す箇所より前に、定義またはプロトタイプ宣言が必要です。

単一ファイルでは、もっとも簡単なのは「関数定義をmainより前に置く」方法です。

古いC規格のように暗黙宣言に頼る書き方はエラーや未定義動作の原因になるため厳禁です。

C言語
#include <stdio.h>

// 呼び出しより前に定義するのでプロトタイプ宣言は不要
int add(int a, int b) {
    return a + b;
}

int main(void) {
    printf("%d\n", add(2, 3)); // OK: すでにaddが定義済み
    return 0;
}

もし意図があってmainより後に定義したい場合は、前方にプロトタイプ宣言を書きます(複数ファイルへの分割は別記事で解説します)。

C言語
#include <stdio.h>

int add(int a, int b); // プロトタイプ宣言(戻り値と引数型の約束)

int main(void) {
    printf("%d\n", add(2, 3)); // 宣言があるのでOK
    return 0;
}

int add(int a, int b) { // 実体定義は後ろでもよい
    return a + b;
}

関数の呼び出しの書き方

基本構文(関数呼び出し)

呼び出しは関数名(実引数,...)と書きます。

戻り値がある場合は代入や式に組み込みます。

  • 代入例: int s = add(10, 20);
  • 式の一部: printf("%d\n", add(1, 2) * 3);
  • 手続き呼び出し: greet("Alice");

戻り値を受け取る呼び出し

戻り値がある関数は、型の合う変数に受け取るのが基本です。

C言語
int s = add(3, 5);  // sは8
printf("sum = %d\n", s);

戻り値を無視する呼び出し

戻り値がある関数でも、結果を使わない場合は代入せずに呼び出せます。

ただし静的解析では警告対象になることがあります。

意図を明確にするなら(void)関数呼び出しと明示することがあります。

C言語
(void)add(100, 200); // 結果を意図的に無視している明示

戻り値がvoidの関数はそもそも代入できません。

引数の数と型を合わせる

呼び出し時の実引数は、宣言された引数の数と型に一致させます。

数が足りない・多い、型が不一致といった誤りは未定義動作やバグの原因です。

プロトタイプ宣言が前にあれば、コンパイル時に型チェックされます。

数値リテラルの型や整数から浮動小数への暗黙変換に注意しましょう。

警告は必ずゼロにしてください。

繰り返し呼び出す

同じ関数をループ内で何度でも呼び出せます。

小さな関数に分けると、繰り返し処理の見通しが良くなります。

C言語
for (int i = 0; i < 3; i++) {
    greet("C learner"); // 毎回同じ処理を呼ぶ
}

サンプルコードと実行例

例1 add関数を定義して呼び出す

2つの整数を足し算して表示するプログラムです。

定義をmainの前に置く基本パターンにしています。

C言語
#include <stdio.h>

// 2つの整数a, bの和を返す
int add(int a, int b) {
    // 中間変数を使うとデバッグしやすい
    int sum = a + b;
    return sum; // sumを呼び出し元へ返す
}

int main(void) {
    int x = 12;
    int y = 30;

    // 戻り値を受け取って表示
    int s = add(x, y);
    printf("add(%d, %d) = %d\n", x, y, s);

    // 戻り値を式の中で直接使う
    printf("add(7, 5) * 2 = %d\n", add(7, 5) * 2);

    return 0; // 正常終了
}
実行結果
add(12, 30) = 42
add(7, 5) * 2 = 24

例2 void関数を呼び出す

表示専用のvoid関数を定義して、複数回呼び出します。

C言語
#include <stdio.h>

// 飾り線を表示するだけの手続き
void print_line(void) {
    puts("=========");
}

// 名前付きで挨拶する手続き
void greet(const char *name) {
    printf("Hello, %s!\n", name);
}

int main(void) {
    print_line();             // 1回目
    greet("Alice");           // メッセージ表示
    print_line();             // 2回目
    greet("Bob");
    print_line();             // 3回目
    return 0;
}
実行結果
=========
Hello, Alice!
=========
Hello, Bob!
=========

コンパイルと実行(gcc)

GNU Compiler Collection(gcc)を用いた基本的な手順です。

警告を有効にしてコンパイルする習慣を付けましょう。

  • 例1の保存ファイル名をexample_add.cとした場合
  • 例2の保存ファイル名をexample_void.cとした場合
text
gcc -std=c17 -Wall -Wextra -Wpedantic -o example_add example_add.c
./example_add

gcc -std=c17 -Wall -Wextra -Wpedantic -o example_void example_void.c
./example_void

-std=c17はC17規格を使う指定、-Wall -Wextra -Wpedanticは代表的な警告を有効にするオプションです。

上記のコマンドを実行すると次のような出力になります。

実行環境の差はほぼ影響しません。

text
# example_add の実行結果
add(12, 30) = 42
add(7, 5) * 2 = 24

# example_void の実行結果
=========
Hello, Alice!
=========
Hello, Bob!
=========

各行は、呼び出した関数の戻り値や副作用(表示)がそのまま反映されたものです。

戻り値がある関数は値として使える一方、void関数は表示などの副作用に意味があることを確認できます。

まとめ

本記事では、C言語における関数の定義と呼び出しの基本を解説しました。

関数は戻り値の型・関数名・引数・本体から成り、単一ファイルでは呼び出す前に定義するのが最も簡単で安全です。

戻り値は型の合う変数で受け取り、不要なら(void)で意図を示すこともできます。

引数の数と型は宣言と一致させ、-Wallなどの警告を有効にしてエラーを未然に防ぎましょう。

実務でも学習でも、同じ処理を関数に切り出して再利用することで、コードの見通しと品質が大きく向上します。

複数ファイルへの分割やプロトタイプ宣言の管理は、次のステップとして学ぶと理解が深まります。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!