C言語関係掲示板

過去ログ

No.515.2次元配列を関数に渡す

[戻る] [ホームページ]
No.4014

2次元配列について
投稿者---ナタデ(2002/12/22 23:11:19)


void sum(int *a);

int n=0;

sum(&n);

は意味がわかるんです

void sum(int *a);

int n[20]={0};

sum(n);

も配列の先頭のアドレスを渡してるってことでわかるんです

void sum(int a[2][3]);

int n[2][3]=0;

sum(n);

は,全然わかりません
nの配列の先頭アドレスを渡している事はわかるんです。
受け取る側のn[2][3]の意味がわかりません。
先頭のアドレスを貰うのに,なんで[2][3]なんでしょうか?

No.4018

Re:2次元配列について
投稿者---かずま(2002/12/23 00:20:06)


> void sum(int *a);
>
> int n[20]={0};
> sum(n);
> も配列の先頭のアドレスを渡してるってことでわかるんです

void sum(int *a); は、
void sum(int a[]); と書いても、
void sum(int a[20]); と書いてもかまいせん。
コンパイラは void sum(int *a); と解釈します。

void sum(int (*a)[3]); も
void sum(int a[][3]); と書いても
void sum(int a[2][3]); と書いてもかまいません。
コンパイラは void sum(int (*a)[3]); と解釈します。

関数の宣言で、引数に配列を書くと、それはポインタと解釈されます。
void sum(int (*a)[3]); の a はポインタです。配列へのポインタです。
その配列は、要素数 3 の int の配列です。
a は引数ですが、(*a) は引数ではないので、void sum(int *(*a)); にはなりません。
void sum(int *a)
{
    int i, s = 0;
    for (i = 0; i < 20; i++)
        s += a[i];
    printf("%d\n", s);
}

と書けるのと同様に、

void sum(int (*a)[3])
{
    int i, j, s = 0;
    for (i = 0; i < 2; i++)
        for (j = 0; j < 3; j++)
            s += a[i][j];
    printf("%d\n", s);
}

と書けます。


No.4020

Re:2次元配列について
投稿者---ナタデ(2002/12/23 00:34:07)


>void sum(int *a); は、
>void sum(int a[]); と書いても、
>void sum(int a[20]); と書いてもかまいせん。
>コンパイラは void sum(int *a); と解釈します。
これは理解しています。
20とか書いてもコンパイラは無視するんですよね。

>void sum(int (*a)[3]); も
>void sum(int a[][3]); と書いても
>void sum(int a[2][3]); と書いてもかまいません。
>コンパイラは void sum(int (*a)[3]); と解釈します。

>関数の宣言で、引数に配列を書くと、それはポインタと解釈されます。
>void sum(int (*a)[3]); の a はポインタです。配列へのポインタです。
>その配列は、要素数 3 の int の配列です。
>a は引数ですが、(*a) は引数ではないので、void sum(int *(*a)); にはなりません。
void add(int *a);
int num[3][4];
add(num);
として,
void add(int *a)
{
a[0][0]=5;
}
という風には出来ないのでしょうか?
(*a)[0],(*a)[1],(*a)[2]が実引数のnum[0],num[1],num[2]のポインタをさしていると考えるのでしょうか?
*aでは,a[0]とは出来ますが,a[0][0]というふうには,なぜできないのでしょうか?
ちょっと文章がわかりずらくてすみません。

No.4022

Re:2次元配列について
投稿者---かずま(2002/12/23 01:09:44)


> void add(int *a);
> int num[3][4];
> add(num);
> として,
> void add(int *a)
> {
> a[0][0]=5;
> }
> という風には出来ないのでしょうか?

できません。

num の型は、int [3][4] ですが、add(num); のときに、num は、int (*)[4] という
型を持つポインタの値に変換されてしまいます。

次に、int *a という引数宣言があると、a[0] の型は int であって、配列ではありま
せんから、その a[0] にさらに [0] をつけることは出来ません。


> (*a)[0],(*a)[1],(*a)[2]が実引数のnum[0],num[1],num[2]のポインタをさしている
> と考えるのでしょうか?

これは、どの場合のことでしょうか。void add(int *a); はダメですから。

void add(int (*a)[4]); で、呼び出し側が、int num[3][4]; add(num); だとすれば、
関数 add の中で、a の型は、int (*)[4]。だから、*a の型は、int [4]。a の値は、
num[0] へのポインタの値ですから、*a の値は num[0][0] へのポインタの値です。
ポインタに [0] をつけた (*a)[0] はもうポインタではありませんから、
(*a)[0] はどこも指しません。(*a)[0] の型は int です。
(*a)[0], (*a)[1], (*a)[2] は、num[0][0], num[0][1], num[0][2] となります。

No.4028

Re:2次元配列について
投稿者---ナタデ(2002/12/23 10:42:19)


>void add(int (*a)[4]); で、呼び出し側が、int num[3][4]; add(num); だとすれば、
>関数 add の中で、a の型は、int (*)[4]。だから、*a の型は、int [4]。a の値は、
>num[0] へのポインタの値ですから、*a の値は num[0][0] へのポインタの値です。
>ポインタに [0] をつけた (*a)[0] はもうポインタではありませんから、
>(*a)[0] はどこも指しません。(*a)[0] の型は int です。
>(*a)[0], (*a)[1], (*a)[2] は、num[0][0], num[0][1], num[0][2] となります。

(*a)[0], (*a)[1], (*a)[2] は、num[0][0], num[1][0], num[2][0] となりのでは(違う?)

よーく考えてみたんですが,
void add(int *a);
int num[2][3];
add(num);
だと,
a側は,num[1]やnum[2]とかのアドレスがどこにあるのか知らないから,a[2][1]とか出来ないってことですよね?
a[4]とかとしてからさす事は出来ますけど。
だから,aは配列にしてnum[0],num[1],num[2]のアドレスを(*a)[0],(*a)[1],(*a)[2]に渡してるってことですよね?
使いやすいように。

No.4079

Re:2次元配列について
投稿者---コモ(2002/12/26 22:24:41)


void a(int (*a)[5]);

とかくのは,列の要素数がわからなければ,アクセスできないからです。