C言語 プログラミング

C言語でプログラミング基礎編(3)【関数呼び出し】

C言語講座続けます。今回は3回目、いよいよモジュール化、関数呼び出しです。

ここをクリアすると、ひとつステップアップします。

C言語でプログラミング:関数呼び出し

C言語ソースコード

関数呼び出し

関数にわけることができるようになると、多少大きめのプログラムを書くことができるようになります。

関数に分けるときの考え方は、別講に譲るとして、関数の書き方です。


型 関数名([引数 [, 引数...] ])
{
    処理....
    
    return 戻り値;
}

という形で、型と関数名のあとに、()でくくって、必要に応じて引数を渡します。

関数に戻り値を返すのには、return 文を使います。

これまでも、C言語を実行するために、main関数を書いていましたが、同じ要領です。

hello, world を出力する関数を書くと。


void PrintHello(void)
{
   printf("hello, world\n");
}

ここで、 voidという型は、関数の型として使用されれば、戻り値なし。

引数のパラメータで指定されれば、引数なしを意味しています。

関数の型を省略すると、デフォルトでint 型とみなされますが、近年は明示的に書く方が多いです。

メイン関数側では、次のように呼び出します。


int main()
{
  PrintHello();
  return 0;
}

呼び出しは、今までも登場している、printf()関数と同じです。
C言語の標準ライブラリとして呼び出す関数群も、同じようにして作られています。

関数を呼び出す前には、その関数がどのような引数で、戻り値がどうであるかの宣言が してあれば、コンパイラはその宣言と呼び出し方が一致しているかチェックして、間違っている場合は、警告やエラーを出力してくれる。
例えば、次のような場合です。


void PrintHello(void);

int main()
{
    PrintHello("hello");
    return 0;
}

このように書くと、”PrintHelloの呼出時の引数が多すぎる”旨のエラーが出て、間違いを指摘してくれます。
プロトタイプ宣言は、引数なしで、

void PrintHello();

という書き方もできるものの、この場合、コンパイル時の引数チェックは行われないため、引数まで明記した(ない場合はvoid宣言)プロトタイプ宣言を心がけるべきです。

なお、C++の場合、引数なしは引数なしの関数とみなします。今回は、C言語ということで書いています。

C言語で、おまじないのように書かれる#include 文は、必要な関数のプロトタイプ宣言を記述したヘッダファイルというものを取り込んでいるわけで、どの関数群がどのヘッダファイルに存在しているかは、標準関数程度は、おおよそ覚えておくと開発が楽になります。

関数宣言(C言語 標準ヘッダファイル)

重要な標準ヘッダファイルをピックアップしてみました。
徐々に覚えていけばいいと思います。

stdio.h 入出力(printf, fgets等のファイル操作他)
string.h 文字列操作(strcpy, strlen, memcpy他)
stdlib.h ユーティリティ(atoi, malloc, free, exit, getenv等)
time.h 日付及び時間(time, mktime, localtime等)
assert.h 引数チェック等につかう、assert が定義
ctype.h 文字判断の関数群(isalnum, isdigit等)
errno.h エラー関係
math.h 数学関連(sin, cos, tan等)
stdarg.h 可変の引数をもつ関数を定義する際に利用

ときどき、ヘッダファイルを覗いて見ると、興味深い発見があるかも知れません。

さて、もう少し例を。
以前、第1回の構文説明のときに登場した階乗計算を関数にしてみます。


#include < stdio.h >
#include < stdlib.h >

int KaijyoKeisan(int n)
{
    int i, x;
    x = 1;
    for (i = 1; i < n; i++) {
        x = x * i;
    }
    return x;
}

int main()
{
    int n, x;
    char buf[128];
    
    printf("N : ");
    gets(buf);
    if ((n = atoi(buf)) < 0) {
	printf("Input Error!\n");
	return 1;
    }
    x = KaijyoKeisan(n);
    printf("%d! = %d\n", n, x);
    return 0;
}

実行結果:

N:10
10!=362880

階乗計算は、再帰呼出(自分を自分で呼び出す)で次のように書くこともできます。


int KaijyoKeisan(int n)
{
    if (n == 0) {
       return 1;
    }
    return n * KaijyoKeisan(n - 1);
}

※ライブラリ化するなら、n >= 0 であることもチェックが必要です!

また、もうひとつ同一ソースコード内(モジュール内)でしか使用しない関数は、static と付けておけば、他のソースコードから参照できなくなるります。

外部インターフェースは、少なければ少ないほど問題が起きる可能性が減りますので、他から呼び出されないようにするために、必要に応じてstaticはつけたほうが、いいです。

もっとも、C++を使って、クラスを作成すれば、クラス内のメソッドは公開(public)と非公開(private)も定義できるので、業務上C++ではなく、c言語で開発する、という場合の話になります。


#include < stdio.h >
static void func() /* 外部には公開しない関数(内部関数) */
{
   printf("hello\n");
}
int main()
{
    func();
    return 0;
}

こう書くことで、他の人からfuncは呼ぶ出すことができないし、他の人が同じfuncという関数を定義していても、重複でエラーになることはありません。

関数はここまでですが、関数を定義して呼び出し利用が、できるようになりましたか?

C言語の話は、この後も何回かに分けて投稿しますので、興味のある方は引き続きよろしくお願いします。

-C言語, プログラミング
-,

Copyright© SIMPLEONESOFT (BLOG) , 2022 All Rights Reserved.