パソコン日記

気づいたこと まとめてみる

C言語で関数を使う

C言語の関数とは

C言語で関数とは、ある一通りの処理をまとめたものです。今まで使ってきた"main()“や"printf()"も実は関数です。"main()"以外にも自分で関数を定義し、使っていくことができます。今回はC言語で関数を定義し、実際に使ってみたいと思います。

簡単な関数をつくってみる(void型)

はじめに、与えられた整数型の数字を足して、"printf()“で表示するプログラムを作ってみました。

include <stdio.h>

void sum(int d1, int d2){
    printf("%d\n", d1+d2);
}

int main(void){
    sum(2,4);
    return 0;
}

この中で、自分で定義した関数は"void sum(int d1, int d2)“です。関数を定義するときはこのようにします。関数を定義するときの注意点としては、プログラムは上から順にコンパイラに解析されていくので、実行するところよりも上に書いてないといけないことです。もし、実行するところよりもあとに書きたいときは関数原型宣言(関数プロトタイプ宣言)をしなければなりません。これについては後で説明いたします。

上記のプログラムでは"sum()“をvoid型で宣言しました。void型は返り値がない関数です。この関数ではint型のd1、d2を引数として受け取っています。引数とは、関数を利用する際に、実行する関数に与えることができる値です。引数は関数の中で利用することができます。この関数は"main()"の中で"sum(2,4)"と関数を呼び出し、関数に渡した二つの引数を足して表示しています。

簡単な関数をつくってみる(int型)

今度は、先程の関数をvoid型ではなく、int型の返り値を持つ関数で作ってみます。次のようにしてみました。

#include <stdio.h>

int sum(int d1, int d2){
    int ans;
    ans = d1 + d2;
    return ans;
}

int main(void){
    int x;
    x = sum(2,4);
    printf("%d\n",x);
    return 0;
}

この関数"sum()“では"void"となっていたところが"int"となっています。これは返り値はint型ですよ、という意味です。"main()"を見てみると、"x = sum(2,4)"となっており、"sum()"が実行され、返ってくる値を"x"に代入しています。そして、得られたxを"printf()"で表示しています。

関数原型宣言(プロトタイプ宣言)をやってみる。

ここで、次のプログラムをコンパイルしてみます。

#include <stdio.h>

int main(void){
    int x;
    x = sum(2,4);
    printf("%d\n",x);
    return 0;
}

int sum(int d1, int d2){
    int ans;
    ans = d1 + d2;
    return ans;
}

gccコンパイルしてみましたが、以下のような警告がでました。

test.c:5:9: warning: implicit declaration of function 'sum' is invalid in C99 [-Wimplicit-function-declaration]
    x = sum(2,4);
        ^
1 warning generated.

自分としては、コンパイルできないのかなと思っていましたが、コンパイルができ実行もできました。警告は"sumが宣言されてないけど、C99では無効だよ"って意味です。コンパイラによってはコンパイルできないみたいです。この警告を消すためにプログラムを次のようにしてみました。

#include <stdio.h>

int sum(int, int);

int main(void){
    int x;
    x = sum(2,4);
    printf("%d\n",x);
    return 0;
}

int sum(int d1, int d2){
    int ans;
    ans = d1 + d2;
    return ans;
}

main()の前に"int sum(int d1, int d2);“の行が追加されています。これが関数原型宣言です。こういう型の関数を宣言するよ、というのを先にコンパイラに教えておきます。関数原型宣言ではカッコ内の引数の"d1"、"d2"などの変数名は必要なく、型だけでオッケーです。

再帰関数をつくってみる

次に、再帰関数というものを作ってみたいと思います。今まで、関数を"main()“の中から呼び出していました。宣言した関数の中で、さらにその関数自身を呼び出すとどうなるのでしょうか。そのように、関数の中で自分自身の関数を呼び出す関数を再帰関数と呼びます。

階上の再帰関数をつくってみる

はじめに単純な例である、階上の再帰関数をつくってみます。例えば4の階上は

4! = 4 × 3 × 2 × 1 = 24

となります。そこで次のようなプログラムを作ってみました。

#include <stdio.h>

int factorial(int n){
    if (n == 1){
        return n;
    } else {
        return n * factorial(n - 1);
    }
}

int main(void){
    int x;
    x = factorial(4);
    printf("%d\n",x);
    return 0;
}

このプログラムの中で"factorial()“という関数が再帰関数として書かれています。この関数の中で、"return n * factorail(n-1)"という行があります。この行で自分自身が呼び出されています。階上では数字を1づつ減らしながら1まで掛けていきます。なので、"n"がイチのとき、関数を呼び出さず値を返してあげ、それ以外は、"n-1"をもとの数と掛けていきます。理解しやすくするため、"factorial()"を次のようにしてみました。

int factorial(int n){
    int x;
    if (n == 1){
        x = n;
        printf("factorial: %d\n",x);
        return x;
    } else {
        x =  n * factorial(n - 1);
        printf("factorial: %d\n",x);
        return x;
    }
}

実行結果↓

factorial: 1
factorial: 2
factorial: 6
factorial: 24
answer: 24

はじめに表示されている値は"1"です。"main()“の中で、関数に渡した値は4なのにはじめに"1"が表示されます。これは"printf()"を通過する前に"factorial(n-1)"が呼び出されているので、値が表示される前に、さらに関数が呼び出されるためです。"n == 1"までいくと、値が返ってくるのでその下の"printf()"が実行されていきます。そして、はじめは1、その後1×2=2、2×3=6、6×4=24というのが表示されていきます。

等比数列の和の再帰関数をつくってみる

次に等比数列の和を再帰関数で求めてみたいと思います。

等比数列 - Wikipedia

別に再帰関数を書かなくても、公式を使えばすぐできますが、練習のため作ってみました。また、等比数列の和を求める中で、累乗を求める必要があります。C言語の数学的な計算をするための"math.h"のヘッダの中に、累乗を計算する"pow()“が定義されていますが、今回はこれも自分で作って見ました。"math.h"で定義されている"pow()"はdouble型の返り値を持ちますが、今回つくってみたのはint型ですのでご注意ください。

#include <stdio.h>

int pow(int a, int n) {
    int ans = 1;
    int i;
    for(i=0; i<n; i++){
        ans = ans*a;
    }
    return ans;
}

int geoprog(int a, int r, int n) {
    if (n == 1) {
        return a;
    } else {
        return a*pow(r,n-1) + geoprog(a, r, n-1);
    }
}

int main(void){
    int x;
    x = geoprog(1,2,5);
    printf("answer: %d\n",x);
    return 0;
}

等比数列の和を求める関数は"geoprog()“です。引数は"a"が初項、"r"が項比、"n"が項数です。"初項1,公比2,項数5"で実行すると"31"とでてきたので、おそらくあっていると思います。ちなみに、"pow()"は引数"a"が底で、"n"が指数です。ちなみに、"pow()"はint型で作っているので、"n"が負の数になるような場合はきちんと動きません。"n"を負の数にも対応させたいときはdouble型になるように作ってみてください。