第11章の2 関数にデータを渡す

1. 関数にデータを渡す

前節で見てきたように、上位の関数(呼ぶ側)から下位の関数(呼ばれる側)へデータを渡すことができますが、 その方法には、「データの値」を渡す方法と、「データのアドレス」を渡す方法があります。

(1) 値による渡し

前節の例はこれに相当します。

実引数の値を仮引数に代入するため、実引数と仮引数の変数名は不一致で構いません。
また、値が渡されたあと、実引数と仮引数はまったく無関係になり、仮引数の値が変更されても、実引数の値は変わりません。
ですから、仮に実引数と仮引数の名前が同一でも、両者は連動しません(次の例を参照してください)。

// 例
#include <stdio.h>

int ex_sub(int num);

int main(void)
{
    int rc;
    int num = 100;
    
    rc = ex_sub(num);
    printf("num = %d\n", num);  // num = 100 を出力
    printf("rc = %d\n", rc);    // rc = 5000 を出力
    
    return 0;
}

int ex_sub(int num)
{
    num = num * 50;    // num は 5000 になる
    
    return num;        // num(5000)を返す
}

【実行結果例】
num = 100
rc = 5000

(2) アドレスによる渡し

アドレス渡しでは、呼び出し側の関数で配列のアドレスを渡し、呼び出される側の関数でそれをポインタで受け取って処理します。

// 関数に配列を渡す例(ポインタで受け取る)
#include <stdio.h>

int goukei(int *dt);

int main(void)
{
    int a[10] = {1, 2, 3, 4, 5, -1};
    int sum;
    
    sum = goukei(a);  // 配列aの先頭要素のアドレスを渡す

    printf("sum = %d\n", sum);
    
    return 0;
}

int goukei(int *dt)	// 仮引数はポインタ
{
	int kei = 0;
	while (*dt != -1) {
		kei += *dt;
		dt++;
	}
    return kei;
}

【実行結果例】
sum = 15

アドレス渡しで変数のアドレスを渡すこともできます。次の例では、変数aとbのアドレスを渡し、それを関数swapではポインタで受け取っています。そうすることにより、ポインタを使ってmain関数の変数aとbの値を入れ替えています。

// 関数に変数のアドレスを渡す例(ポインタで受け取る)
#include <stdio.h>

void swap(int *dt1, int *dt2);

int main(void)
{
    int a = 10, b = 20;
	
	printf("呼び出し前:a = %d, b = %d\n", a, b);

    swap(&a, &b);    // 変数aとbのアドレスを渡す

	printf("呼び出し後:a = %d, b = %d\n", a, b);
    
    return 0;
}

void swap(int *dt1, int *dt2)	// 仮引数はポインタ
{
	int temp = *dt1;
	*dt1 = *dt2;
	*dt2 = temp;
}

【実行結果例】
呼び出し前:a = 10, b = 20
呼び出し後:a = 20, b = 10

アドレス渡しでは、メモリ上の実際のアドレスを渡すため、呼び出される関数側がその内容を変更すると、呼び出した関数側で用意していた内容を変更することになってしまいます。
そのため、意図的に、渡されたアドレスが指す値を変えるとき以外は、注意が必要です。

(3) 添字演算子を使ってアドレスを受け取る

関数に配列を丸ごと渡すことはできませんが、添字演算子([])を使うと、あたかも配列を丸ごと渡すように書くことができます。

// 関数に配列を渡す例(添字演算子を使う)
#include <stdio.h>

int goukei(int dt[]);

int main(void)
{
    int a[10] = {1, 2, 3, 4, 5, -1};
    int sum;
    
    sum = goukei(a);  // 配列aの先頭要素のアドレスを渡す

    printf("sum = %d\n", sum);
    
    return 0;
}

int goukei(int dt[])    // 仮引数に添字演算子
{
    int kei = 0;
    int i = 0;
    while (dt[i] != -1) { // 添字演算子で要素をアクセス
        kei += dt[i];
        i++;
    }
    return kei;
}

【実行結果例】
sum = 15

dt[i]は、*(dt + i)と等価です。ポインタと添字演算子のどちらを使ってもかまいませんが、次のように使い分けるといいでしょう。

  • ポインタをインクリメント・デクリメントしながら操作するときは「ポインタ演算」 (*(p++) など)
  • 「添字によるアクセス」の形が分かりやすいときは「添字演算子」 (dt[i] など)

〇 演習問題

次のプログラムの空欄部を埋めて、プログラムを完成させなさい。

問1

// 文字列を表示する関数
#include <stdio.h>

void print_str(_______);

int main(void)
{
    char str[] = "COMPUTER";
    
    print_str(_______);
    return 0;
}

void print_str(_______)
{
    printf("%s\n", sr);
}

【実行結果例】
COMPUTER

問2

// 文字列を大文字に変換する関数
#include <stdio.h>
#include <ctype.h>

void oomoji(char _____);

int main( void )
{
    char str[3][10] = {
        "apple", "banana", "cherry"
    };
    int i;
    
    for ( i = 0; i < 3; i++ ) {
        oomoji(_______);
    }
    
    return 0;
}

void oomoji(char _____)
{
    int i = 0;
    
    while(_____ != '\0' ) {
        _____ = toupper(_____);
        i++;
    }
    printf("%s\n", st);
}

【実行結果例】
APPLE
BANANA
CHERRY

解答例

// 問1
#include <stdio.h>

void print_str(char *sr);

int main(void)
{
    char str[] = "COMPUTER";
    
    print_str(str);
    return 0;
}

void print_str(char *sr)
{
    printf("%s\n", sr);
} 
// 問2
#include <stdio.h>
#include <ctype.h>

void oomoji(char *st);

int main( void )
{
    char str[3][10] = {
        "apple", "banana", "cherry"
    };
    int i;
    
    for ( i = 0; i < 3; i++ ) {
        oomoji(str[i]);
    }
    
    return 0;
}

void oomoji(char *st)
{
    int i = 0;
    
    while(*(st + i) != '\0' ) {
        *(st + i) = toupper(*(st + i));
        i++;
    }
    printf("%s\n", st);
}
// 問2(別解)
#include <stdio.h>
#include <ctype.h>

void oomoji(char st[]);

int main( void )
{
    char str[3][10] = {
        "apple", "banana", "cherry"
    };
    int i;
    
    for ( i = 0; i < 3; i++ ) {
        oomoji(str[i]);
    }
    
    return 0;
}

void oomoji(char st[])
{
    int i = 0;
    
    while(st[i] != '\0' ) {
        st[i] = toupper(st[i]);
        i++;
    }
    printf("%s\n", st);
}

コメント