C言語関係掲示板

過去ログ

No.1291 ダブルポインタと2次元配列について

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

ダブルポインタと2次元配列について
投稿者---jun(2004/10/07 14:03:32)


ダブルポインタと2次元配列について疑問に思っていることがあります。
わけのわからない質問をしていたらすみません。

一次元配列はすごくポインタと密な関係がありますよね。

例えば、

int a[10];

と定義されていれば

func(int *p);

と定義されている関数を

func(a);

と使えるのに、

なぜ

例えば、

int a[10][10];

と定義されていれば

func(int **p);

と定義されている関数を

func(a);

と使えないのでしょうか??

誰か教えてください。おねがいします。





No.17164

Re:ダブルポインタと2次元配列について
投稿者---たか(2004/10/07 14:05:58)


>int a[10][10];
>
>と定義されていれば
>
>func(int **p);
>
>と定義されている関数を
>
>func(a);
>
>と使えないのでしょうか??

int a[10][10]はint (*)[10]と変換され、これはint **型ではないからてす。


No.17165

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/07 14:19:39)


ありがとうございます。

>int a[10][10]はint (*)[10]と変換され、これはint **型ではないからてす。

では、

func((int (*)[10])a);

とすれば正しく動作するしないは別にエラーは起きないということですね。
キャストが正しくできてるか微妙ですが。。。


No.17168

Re:ダブルポインタと2次元配列について
投稿者---REE(2004/10/07 14:33:34)


>func((int (*)[10])a);
>
>とすれば正しく動作するしないは別にエラーは起きないということですね。

いや、aは既にint (*)[10]型なので、キャストしても意味ありません。

もしするのなら、func((int **)a); ですが、正しく動作する見込みはありません。

int (*)[10]は配列へのポインタで、int **はポインタへのポインタです。
全く別物であることをご理解下さい。



No.17170

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/07 14:51:11)



>いや、aは既にint (*)[10]型なので、キャストしても意味ありません。

あ、ほんとですね!私は何をばかなことを・・・・。

言いたかったのは、

例えば
int a[10];
などと定義しておいて、
(別に
int *a;
でもいいですが、)

func(int b[10][10]);
と定義された関数を、

func((int (*)[10])a);

とすればエラーは起きないということですよね??
まぁ正しくは動作されるされないは別ですけど。

>int (*)[10]は配列へのポインタで、int **はポインタへのポインタです。
>全く別物であることをご理解下さい。

わかりました!どうもありがとうございます!

ちなみに

int *c[10];

と定義するとこの c は(int **)型ですよね??

なんとなく私は納得がいかないんですよねー・・・。




No.17171

Re:ダブルポインタと2次元配列について
投稿者---REE(2004/10/07 15:06:00)


>int *c[10];
>
>と定義するとこの c は(int **)型ですよね??

厳密にはint *[10]型ですがint **型と互換はあります。

int (*x)[10];
のとき、確保される領域は、ポインタ1個分
そのポインタは、intの配列を指すものです。

int *y[10];
のとき、確保される領域は、ポインタ10個分
そのポインタは、intを指すものです。



No.17172

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/07 15:19:58)


>厳密にはint *[10]型ですがint **型と互換はあります。

int *[10]型 と int (*)[10]型は全く別の型ですよね??

>int (*x)[10];
>のとき、確保される領域は、ポインタ1個分
>そのポインタは、intの配列を指すものです。
>
>int *y[10];
>のとき、確保される領域は、ポインタ10個分
>そのポインタは、intを指すものです。

これは理解しました。



No.17180

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/08 09:06:27)


すみません。もう一度質問させてください。

int *[10]型 と int (*)[10]型は全く別の型ですか??


No.17184

Re:ダブルポインタと2次元配列について
投稿者---YuO(2004/10/08 10:21:24)


>int *[10]型 と int (*)[10]型は全く別の型ですか??

完全に別の型です。

int *[10]型というのは,
「『[int]型へのポインタ』型を要素とする,10個の要素からなる配列」型
であり,int (*)[10]型というのは,
「『[int]型を要素とする,10個の要素からなる配列』型へのポインタ」型
です。


ちなみに,根本的な話として,Cに2次元配列というものは存在しません。
存在するのは「『配列』型への配列」型です。

int a[10];
と宣言されたaを式中で使うとint *になるのは,変換によって
・「『int』型を要素とする,10個の要素からなる配列」型
が,
・(aという配列の先頭要素をさす)「『int』型へのポインタ」
に変換されるからです。同じように,
int a[10][20];
と宣言されたaを式中で使うと,
・「『[int]型を要素とする,20個の要素からなる配列』型を要素とする,10個の要素からなる配列」型
が,
・(aという配列の先頭要素をさす)「『[int]型を要素とする,20個の要素からなる配列』がたへのポインタ」
に変換されます。これをCの型として記述すると,
int (*)[20]
となります。



No.17186

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/08 13:00:05)


>int *[10]型というのは,
>「『[int]型へのポインタ』型を要素とする,10個の要素からなる配列」型
>であり,int (*)[10]型というのは,
>「『[int]型を要素とする,10個の要素からなる配列』型へのポインタ」型
>です。

int *[10]はあくまで配列であって、int (*)[10]はポインタということですね。()←カッコというのはポインタであるということを明示的にするためについているんですね。よくわかりました。どうもありがとうございました。

つまり、

int []型はint *型と互換があって、
int *[]型はint **型と互換がって、
int [][]型はint (*)[]型と互換があるのですね。 


No.17187

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/08 13:59:35)


すいません。もうひとつどうしても疑問に思っていることがあるので、もし誰か説明できる方がいらしたら教えてください。

例えばint型を返す関数へのポインタを宣言する時には


int (*myfunc)();

としますよね。

そしてこのint型を返す関数へのポインタの配列(3つの)を定義する時には

int (* flist[3])();

と定義しますよね。これはなぜ


int (* flist)[3]();

のように定義せず、[3]の部分まで括弧に含めてしまうのでしょう??
何か私は不自然に思ってしまいます。

どなたか良い説明していただけませんでしょうか??




No.17188

Re:ダブルポインタと2次元配列について
投稿者---REE(2004/10/08 14:13:17)


http://kmaebashi.com/programmer/pointer.html

このページを一通りご覧になって下さい。



No.17189

Re:ダブルポインタと2次元配列について
投稿者---YuO(2004/10/08 14:49:55)


>そしてこのint型を返す関数へのポインタの配列(3つの)を定義する時には
>int (* flist[3])();
>と定義しますよね。これはなぜ
>int (* flist)[3]();
>のように定義せず、[3]の部分まで括弧に含めてしまうのでしょう??
>何か私は不自然に思ってしまいます。


文法の定義から,ポインタ宣言子は配列宣言子や関数宣言子よりも優先順位が低いです。
そのため,T *flist[3]は
  • flistは要素数3の配列である
  • その配列の要素の型はT *である

というように処理されます。

関数宣言子でない括弧は宣言子の結びつく優先順位を変えるので,T (*flist)[3]は,
  • flistはポインタ型である
  • その参照型は,T [3]である

というように処理されます。
#宣言は,前から後ろにとか,後ろから前に読めばよいものではないです。


ちなみに,
int (*flist)[3]()
は,
typedef int T1();
typedef T1 T2[3];
typedef T2 * flist;

とやって,
flist is pointer to array[3] of function returing int.
となるので,
「『[引数が不明でintを返す関数]型を要素とする,要素数が3個の配列』型へのポインタ」型
となるのですが,配列の要素型になれるのはオブジェクト型のみなので,
関数型の配列は生成できず,コンパイラはエラーを吐くはずです。



No.17190

Re:ダブルポインタと2次元配列について
投稿者---jun(2004/10/08 15:31:03)


>REEさん
ざっと読みました。非常に深いですね。C言語は荒削りな面がこんなにもたくさんあるのだなぁと思いました。

>YuOさん
どうもありがとうございます。なんかすっきりしました。