第11章の3 関数からデータを返す

1. 関数からデータを返す

第11章の1 で見てきたように、下位の関数(呼ばれる側)から上位の関数(呼ぶ側)へデータを返すことができますが、 それには、「1個の戻り値を返す方法」と、「複数の戻り値を返す方法」があります。

2. 1個の戻り値を返す

1個の戻り値を返す場合には、第11章の1 のように、

return 戻り値;

で値を返します。

3. 複数の戻り値を返す

複数の戻り値を返す方法には、「配列のアドレスを引数にする方法」と、 「複数の変数のアドレスを引数にする方法」があります。

(1) 配列を使って複数の戻り値を返す

配列の先頭要素のアドレスを引数にして、上位関数側と下位関数側で配列を共有し、見かけ上、複数のデータを返したようにします。

#include <stdio.h>
#define N 7		// 配列要素数

void waru2(int *p, int n);

int main(void)
{
    int i;
    int dt[N] = {20, 10, 4, 35, 66, 78, 2};
    
    waru2(dt, N);  // 配列の先頭要素のアドレスと要素数を渡す
    
    for(i = 0; i < N; i++) {
        printf("%d ", dt[i]);
    }
    printf("\n");
    
    return 0;
}

/***
配列要素を2で割る関数
引数:int *p;  配列の先頭要素へのポインタ
      int n;   配列要素数
***/
void waru2(int *p, int n)        // 配列dt のアドレスをポインタp に入れる
{
    for (int i = 0; i < n; i++) {
        *(p + i) /= 2;           // ポインタの指す値を 2 で割る
    }
}

【実行結果例】
10 5 2 17 33 39 1

呼び出された関数は配列の要素数を知る方法がないので、必ず配列の要素数も一緒に渡します。

(2) 変数を使って複数の戻り値を返す

複数の変数のアドレスを引数にして、上位関数側と下位関数側でデータを共有し、見かけ上、複数のデータを返したようにします。

#include <stdio.h>

#define N 8

void max_min(int p[], int n, int *mx, int *mn);

int main(void)
{
    int array[N] = 
        {45, 78, 345, 987, 23, 2, 92, 123};
    int max, min;

    max_min(array, N, &max, &min);

    printf("最大値 = %d\n", max);
    printf("最小値 = %d\n", min);

    return 0;
}

/***
配列要素の最大値と最小値を返す関数
引数:int p[];    配列の先頭要素へのポインタ
      int n;      配列の要素数
      int *mx;    最大値を格納する変数へのポインタ
      int *mn;    最小値を格納する変数へのポインタ
***/
void max_min(int p[], int n, int *mx, int *mn)
{
    *mx = *mn = p[0];   // 初期値は配列の先頭

    for (int i = 1; i < n; i++) {
        // より大きな値があったらmaxを入れ替え
        if (*mx < p[i]) {
            *mx = p[i];
        }
        // より小さな値があったらminを入れ替え
        if (*mn > p[i]) {
            *mn = p[i];
        }
    }
}

【実行結果例】
最大値 = 987
最小値 = 2

〇 演習問題

キーボードから入力した2つの整数値の和差積商を求めるプログラムを作りたい。
和差積商を求める部分は関数にすることとする。
次の仕様に従った関数を作成し、2つのプログラムを作りなさい。

問1

関数名称: 	keisan1
引数: int x; 計算に使う整数値1
int y; 計算に使う整数値2
int *wa; 和を入れる変数のポインタ
int *sa; 差を入れる変数のポインタ
int *seki; 積を入れる変数のポインタ
double *shou; 商を入れる変数のポインタ
戻り値: 無し

【実行結果例】
整数値を2つ入力しなさい 20 6
和 = 26 差 = 14 積 = 120 商 = 3.333333

問2

関数名称:	keisan2
引数: int x; 計算に使う整数値
int y; 計算に使う整数値
int *p; 和差積商を入れる配列のポインタ
        (上から順に和差積商を格納する)
戻り値: 無し

【実行結果例】
整数値を2つ入力しなさい 20 6
和 = 26 差 = 14 積 = 120 商 = 3

解答例

// 問1
#include <stdio.h>

void keisan1(int x, int y, int *wa, int *sa, int *seki, double *shou);

int main(void)
{
    int dt1, dt2;
    int sum, diff, mul;
    double div;

    printf("整数値を2つ入力しなさい ");
    scanf("%d %d", &dt1, &dt2);

    keisan1(dt1, dt2, &sum, &diff, &mul, &div);        // 和差積商を求める

    printf("和 = %d 差 = %d 積 = %d 商 = %f\n", sum, diff, mul, div);

    return 0;
}

/***
和差積商を求める関数
引数:int x;        計算に使う整数値1
      int y;        計算に使う整数値2
      int *wa;      和を入れる変数のポインタ
      int *sa;      差を入れる変数のポインタ
      int *seki;    積を入れる変数のポインタ
      double *shou; 商を入れる変数のポインタ
返却値:なし
***/
void keisan1(int x, int y, int *wa, int *sa, int *seki, double *shou)
{
    *wa = x + y;
    *sa = x - y;
    *seki = x * y;
    if (y != 0)
        *shou = (double)x / y;
    else
        printf("エラー:0で割り算はできません\n");
}
// 問2
#include <stdio.h>

void keisan2(int x, int y, int *p);

int main(void)
{
    int dt1, dt2;
    int answer[4];

    printf("整数値を2つ入力しなさい ");
    scanf("%d %d", &dt1, &dt2);

    keisan2(dt1, dt2, answer);        // 和差積商を求める

    printf("和 = %d 差 = %d 積 = %d 商 = %d\n", 
        answer[0], answer[1], answer[2], answer[3]);

    return 0;
}

/***
和差積商を求める関数
引数:int x;        計算に使う整数値1
      int y;        計算に使う整数値2
      int *p;       和差積商を入れる配列のポインタ
                   (上から順に和差積商を格納する)
返却値:なし
***/
void keisan2(int x, int y, int *p)
{
    *p = x + y;
    *(p + 1) = x - y;
    *(p + 2) = x * y;
    if (y != 0)
        *(p + 3) = x / y;
    else
        printf("エラー:0で割り算はできません\n");
}

コメント