C言語関係掲示板

過去ログ

No.237.char型文字配列を関数に渡す時の疑問


No.1446

char型文字配列を関数に渡す時の疑問
投稿者---ユベントス(2002/04/22 22:49:26)


初めて投稿させて頂きます。

最近C言語を業務で使っていまして一つ納得のいかない事があります。
それはなぜ関数に渡すchar型文字配列は値渡し、参照渡しの際に
必ずもらう関数は"*"をつけないといけないのですか?
値を変更する必要がないのにも関わらず"*"をつけないと
コンパイルエラーになりますが、
int型変数などは値を関数の中で変更する際は必要ですが
それ以外はつけなくてもコンパイルエラーになりません。

誠に基本的な事ですがよろしくお願い致します。

No.1447

Re:char型文字配列を関数に渡す時の疑問
投稿者---かずま(2002/04/23 11:03:51)


>初めて投稿させて頂きます。
>
>最近C言語を業務で使っていまして一つ納得のいかない事があります。
>それはなぜ関数に渡すchar型文字配列は値渡し、参照渡しの際に
>必ずもらう関数は"*"をつけないといけないのですか?
>値を変更する必要がないのにも関わらず"*"をつけないと
>コンパイルエラーになりますが、
>int型変数などは値を関数の中で変更する際は必要ですが
>それ以外はつけなくてもコンパイルエラーになりません。
>
>誠に基本的な事ですがよろしくお願い致します。

基本事項から確認します。int型について考えてみてください。
Cの関数呼び出しの引数は、値渡しだけです。参照渡しはありません。
参照渡しと同等のことは、変数のアドレス(ポインタの値)を渡すこと
によって実現します。ポインタを使うことの利点は、
(1) 呼び出し元の変数の値を変更できる。
(2) 変数が int でなく、構造体のようにサイズが大きい場合でも、
コピーしなくて済む。

次に、配列がなぜ値渡しでないのかについて考えてみましょう。
値渡しにすると、次のような問題点が出てきます。
(1) サイズ(要素数)が固定になる。
(2) 大きなサイズのコピーが必要。

そこで、配列は、式の中では、&演算子をつけなくてもポインタに
変換されるという規則になっています。関数を呼び出すとき、引数に
配列を書くと、それはポインタになります。

したがって、配列を渡してもらう関数のほうは、ポインタが渡される
ように、引数を宣言しなければなりません。引数を配列宣言しても
それはポインタ宣言として扱われます。void func(char a[256]) も
void func(char a[]) も void func(char *a) として解釈されます。

No.1448

Re:char型文字配列を関数に渡す時の疑問
投稿者---かずま(2002/04/23 15:00:14)


>なぜ関数に渡すchar型文字配列は値渡し、参照渡しの際に
>必ずもらう関数は"*"をつけないといけないのですか?
>値を変更する必要がないのにも関わらず"*"をつけないと
>コンパイルエラーになりますが、
>int型変数などは値を関数の中で変更する際は必要ですが
>それ以外はつけなくてもコンパイルエラーになりません。

最初、この質問の意味がよく分からなかったのですが、
今、分かったような気がします。
#include <stdio.h>

void f1(int v)   { printf("%d\n", v); }
void f2(int *p)  { *p = 10 - *p; }
void f3(char *v) { printf("%s\n", v); }
void f4(char *p) { *p= 'A'; p[1] = 'z'; }

int main()
{
    int  i = 3;
    char s[] = "abc";

    f2(&i); f1(i); f4(s); f3(s);
    return 0;
}
このプログラムにおいて、
関数 f1 は、呼び出し元の変数の値を変更しないから、値渡し。
関数 f2 は、呼び出し元の変数の値を変更するから、参照渡し。
関数 f3 は、呼び出し元の変数の値を変更しないから、値渡し。
関数 f4 は、呼び出し元の変数の値を変更するから、参照渡し。

f3 は値渡しなのに、なぜ引数に * が必要か、という質問でしょうか。


No.1450

Re:char型文字配列を関数に渡す時の疑問
投稿者---ユベントス(2002/04/24 00:00:57)


かずまさんレスありがとうございます。

説明不足で大変申し訳ありません。
そうです、かずまさんが書かれたとうりです。

よろしくお願い致します。

No.1452

Re:char型文字配列を関数に渡す時の疑問
投稿者---かずま(2002/04/24 10:39:12)


>よろしくお願い致します。

と言われても、すでに No.1447 で答えは書いたつもりですが、....。
もう少し説明してみます。
これでも分からなかったら、また質問してください。
void f1(int v)  { v = 10 - v; }
void f2(int &r) { r = 10 - r; }  /* C++ には参照渡しがある */
void f3(int *p) { *p = 10 - *p; }

int main()
{   int i;
    i = 3; f1(i);  /* i の値は 3 のまま */
    i = 3; f2(i);  /* i の値は 7 になる */
    i = 3; f3(&i); /* i の値は 7 になる */
}
f3 は、変数 i のアドレスを値渡しすることによって、変数 i を
参照渡ししたのとほぼ同じ機能を果たしています。しかし、呼び出
し元では &i でアドレスを取り出し、呼び出し先では *p という形
で、変数にアクセスしなければなりません。だから、本当の参照渡
しではないのですが、まあ、これを C の「参照渡し」と呼ぶことに
しようといえば、そう言えない事もありません。

さて、配列の場合ですが、配列全体の値を値渡しすることはできま
せん。配列は、常に先頭要素をさすポインタに変換されます。だか
ら、配列要素の値をもらうだけで、変更しない場合でも、いわゆる
「参照渡し」になるのです。

戻る


「初心者のためのポイント学習C言語」 Last modified:2002.06.22
Copyright(c) 2000-2002 TOMOJI All Rights Reserved