C言語-関数の作成
前へ 目次へ 次へ 

4 関数の作成

4.1 関数定義

 標準ライブラリ関数のように関数は、プログラマが自由に作成することができる。これをユーザ関数という。関数の基本的な形は次のとおりである。

型 関数名(引数)
{
    プ ロ グ ラ ム
}

 型は、変数宣言に使用するものと同じで、関数のプログラムが実行された結果、得られるデータの型を指定する。このデータは関数の処理が終わり、関数を呼び出した側に戻ってきたときに返却される値なので返却値という。この返却値は、関数プログラム中の return 文で指定する。関数によっては、返却値が必要でない場合もある。その時は、void型とする。
 関数名は、変数名同様ユーザが自由に付けることができる。
 引数は、関数の呼び出し側から関数に渡すデータを指定する。引数が複数ある場合は、カンマで区切る。関数によっては、引数が必要ない場合もある。その時は、voidとする。
 例えば、すでにリストを示してある関数test_pointerは、次のように記述している。

void test_pointer(char *s, char *p)

 これは、関数名がtest_pointerで、引数にchar型のアドレス値(ポインタ)が2つ必要であり、返却値はない(したがって、関数のプログラム中にreturn文はない)。
 関数を使用する(呼び出す)側では、変数と同じように関数も使用することを宣言しなければならない。これをプロトタイプ宣言という。プロトタイプ宣言することでコンパイラが引数の型や返却値の型などの誤りをチェックしてくれる。


4.2 関数の作成例

 どのような処理を関数にすれば良いか、これはプログラマの経験やセンスによって違ってくる。主として、同じ処理が何度も現れる部分や関数test_pointerのようにいろいろなプログラムで便利・役立つであろう処理を関数として作成することが多い。

重複する処理を関数にするT[pro4-1.c]

 次のリストを見ると、データ入力処理(赤色の部分)が重複している(同じである)。

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int n;
    double a, b, c;
    char buf[80];

    while(1){
        printf("\n1. TASHIZAN\n");
        printf("2. HIKIZAN\n");
        printf("3. KAKEZAN\n");
        printf("4. WARIZAN\n");
        printf("0. OWARI\n\n");
        printf("Please input number : ");
        gets(buf);
        n = atoi(buf);
        if(n == 0)
            break;
        else if(n == 1){
            printf("a + b\n");
            printf("a=");
            gets(buf);
            a = atof(buf);
            printf("b=");
            gets(buf);
            b = atof(buf);
            c = a + b;
            printf("%f\n", c);
        }else if(n == 2){
            printf("a - b\n");
            printf("a=");
            gets(buf);
            a = atof(buf);
            printf("b=");
            gets(buf);
            b = atof(buf);
            c = a - b;
            printf("%f\n", c);
        }else if(n == 3){
            printf("a * b\n");
            printf("a=");
            gets(buf);
            a = atof(buf);
            printf("b=");
            gets(buf);
            b = atof(buf);
            c = a * b;
            printf("%f\n", c);
        }else if(n == 4){
            printf("a / b\n");
            printf("a=");
            gets(buf);
            a = atof(buf);
            printf("b=");
            gets(buf);
            b = atof(buf);
            c = a / b;
            printf("%f\n", c);
        }else
            printf("unkown number\n");
    }
    return(0);
}

 このプログラムでは、データとして四則演算のための実数値が必要であるが、データ入力処理(赤色の部分)に文字列入力の関数getsを使用している。一度、文字列として入力し、関数atofで数字の文字列を数値に変換している。同様の関数に文字列を整数値に変換する関数atoiがある。

#include <stdlib.h>
double atof(char *str);

文字列strをdouble型の数値に変換する。

#include <stdlib.h>
int atoi(const char *string);

文字列を整数に変換する。

 これは、scanf("%f", &a); で入力した場合、数字以外の文字を入力したときに暴走する可能性がある。これを避けるために文字列入力を使用している。


重複する処理を関数にするU[pro4-2.c]

 データ入力部を関数にする。関数名はinputf、返却値はdouble型、引数はプロンプト文字列とする。

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
56:
57:
58:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int n;
    double a, b, c;
    char buf[80];
    double inputf(char *);

    while(1){
        printf("\n1. TASHIZAN\n");
        printf("2. HIKIZAN\n");
        printf("3. KAKEZAN\n");
        printf("4. WARIZAN\n");
        printf("0. OWARI\n\n");
        printf("Please input number : ");
        gets(buf);
        n = atoi(buf);
        if(n == 0)
            break;
        else if(n == 1){
            printf("a + b\n");
            a = inputf("a=");
            b = inputf("b=");
            c = a + b;
            printf("%f\n", c);
        }else if(n == 2){
            printf("a - b\n");
            a = inputf("a=");
            b = inputf("b=");
            c = a - b;
            printf("%f\n", c);
        }else if(n == 3){
            printf("a * b\n");
            a = inputf("a=");
            b = inputf("b=");
            c = a * b;
            printf("%f\n", c);
        }else if(n == 4){
            printf("a / b\n");
            a = inputf("a=");
            b = inputf("b=");
            c = a / b;
            printf("%f\n", c);
        }else
            printf("unkown number\n");
    }
    return(0);
}
double inputf(char *msg)
{
    char buf[80];

    printf("%s", msg);
    gets(buf);
    return(atof(buf));
}

 メインのプログラムがすっきりとして見やすくなったと思う。


重複する処理を関数にするV[pro4-3.c]

 関数の返却値は1つしか指定できないが、複数の返却値が必要なとき、次のような方法がある。
 例えば、a=1, b=2のとき、左のリストの場合、関数内で引数の値を変更しているが、関数から呼び出し側に戻ったとき変数a,bの値は元のままである。これは、単に関数に値を渡しただけであるためである(値渡し)。それに対して、引数の値を変更するには、右のリストのようにアドレスを渡すようにする(参照渡し)。

値渡し 参照渡し
test(a, b);
 
void test(int x, int y)
{
    x = 10;
    y = 20;
}
test(&a, &b);
 
void test(int *x, int *y)
{
    *x = 10;
    *y = 20;
}

 変数の直前の&はアドレス演算子といい、変数の値が格納されているアドレスを取り出す演算子である。引数として、このアドレスを渡し、そのアドレスの内容を関数内で変更することで、呼び出し側に戻ったときにその変更が有効になる。この場合、各変数の値は、a=10, b=20になる。
 もうひとつの方法は、返却値を格納する変数をグローバル変数にすることである。ここでは、前者の方法を利用する。

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
56:
57:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int n;
    double a, b, c;
    char buf[80];
    void inputf(double *, double *);

    while(1){
         printf("\n1. TASHIZAN\n");
         printf("2. HIKIZAN\n");
         printf("3. KAKEZAN\n");
         printf("4. WARIZAN\n");
         printf("0. OWARI\n\n");
         printf("Please input number : ");
         gets(buf);
         n = atoi(buf);
    if(n == 0)
         break;
    else if(n == 1){
         printf("a + b\n");
         inputf(&a, &b);
         c = a + b;
         printf("%f\n", c);
    }else if(n == 2){
         printf("a - b\n");
         inputf(&a, &b);
         c = a - b;
         printf("%f\n", c);
    }else if(n == 3){
         printf("a * b\n");
         inputf(&a, &b);
         c = a * b;
         printf("%f\n", c);
    }else if(n == 4){
        printf("a / b\n");
        inputf(&a, &b);
        c = a / b;
        printf("%f\n", c);
    }else
        printf("unkown number\n");
    }
    return(0);
}
void inputf(double *a, double *b)
{
    char buf[80];

    printf("a=");
    gets(buf);
    *a = atof(buf);
    printf("b=");
    gets(buf);
    *b = atof(buf);
}

 返却値を格納する変数をグローバル変数にした場合のプログラムは、自分で考えてみよう。(「3.2 大域変数(グローバル変数)」参照)


重複する処理を関数にするW[pro4-4.c]

 演算記号を引数として渡すことで、データ入力、計算、結果表示までする関数を作成する。

 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int n;
    char buf[80];
    void keisan(char);

    while(1){
        printf("\n1. TASHIZAN\n");
        printf("2. HIKIZAN\n");
        printf("3. KAKEZAN\n");
        printf("4. WARIZAN\n");
        printf("0. OWARI\n\n");
        printf("Please input number : ");
        gets(buf);
        n = atoi(buf);
        if(n == 0)
            break;
        else if(n == 1)
            keisan('+');
        else if(n == 2)
            keisan('-');
        else if(n == 3)
            keisan('*');
        else if(n == 4)
            keisan('/');
        else
            printf("unkown number\n");
    }
    return(0);
}
void keisan(char op)
{
    char buf[80];
    double a, b, c;

    printf("a %c b\n", op);
    printf("a=");
    gets(buf);
    a = atof(buf);
    printf("b=");
    gets(buf);
    b = atof(buf);
    if(op == '+')
        c = a + b;
    else if(op == '-')
        c = a - b;
    else if(op == '*')
        c = a * b;
    else if(op == '/')
        c = a / b;
    printf("%f\n", c);
}

 どのような形の関数にするかは、少しプログラミングの経験を積んでいかなければならない。pro4-3.cの関数は、2つのデータ入力専用になる。pro4-4.cの関数は、四則演算専用のになる。その点、pro4-2.cの関数は実数入力に幅広く使用できる。私ならば、pro4-2.cの関数を採用する。

 この後、いろいろな処理を関数として作成していくケースが多く出てくるので参考にして欲しい。


前へ 目次へ 次へ 
Copyright © 2001 Hiroshi Masuda 

 

 

inserted by FC2 system