dポイントプレゼントキャンペーン実施中!

int (*i())[3];の宣言は、
変数iは、「int型の配列3個へのポインタを返す関数」ですが、

#include <stdio.h>

int array[3] = { 0, 1, 2 };
typedef int(*ap)[3];

ap i()
{
return array;
}

int main()
{
printf("%d\n", (*i())[0]);
printf("%d\n", (*i())[1]);
printf("%d\n", (*i())[2]);

}

の記述は、それぞれ0,1,2を表示してくれるようなのですが、
printf("%d\n", i()[0]);などの書き方は駄目なようなのですが、何故、この書き方ではだめなのでしょうか?

質問者からの補足コメント

  • ワーニングは出ています。
    おっしゃるようにここは、
    return array ではなくて
    return (int (*)[3])array;
    と書いて、関数i()の型であるapに合わせた方がいいですね。

    No.2の回答に寄せられた補足コメントです。 補足日時:2016/04/04 10:11
  • 配列の方を(int(*)[3])でキャストした配列へのポインタを返す方法もありますが、結局は
    キャストはしてしまいます。
    どんな方法があるのでしょうか?ご参考までに御教示ください。

    No.3の回答に寄せられた補足コメントです。 補足日時:2016/04/04 20:13
  • ちょっとこんがらがって分からなくなりました。
    通常、
    int array[3];
    と宣言した場合、
    arrayの型は、(int *)になると思うのですが、
    arrayの型を、(int [3])と解釈して、それへのポインタとして、(int (*))[3]が使えるということなのでしょうか?

    No.4の回答に寄せられた補足コメントです。 補足日時:2016/04/04 22:37
  • arrayは先頭要素に対するポインタとも解釈できるので、
    その場合は、(int *)型と解釈できるのではないでしょうか?
    2つの解釈が可能。

    No.5の回答に寄せられた補足コメントです。 補足日時:2016/04/05 01:30
  • int (*p)[3]のpの型は、
    int (*)[3]

    int *[3]
    のどちらが正しいのでしょうか?
    sizeof()で調べると、
    sizeof(int (*)[3]) = 4
    sizeof(int *[3]) = 12
    となり、後の方が合っているように思うのですが?

    No.6の回答に寄せられた補足コメントです。 補足日時:2016/04/05 22:16
  • pの型は「要素数3個のint型配列」になるので、その大きさは12バイトになると思うのですが。
    sizeof()の使い方とか間違っています?

    No.9の回答に寄せられた補足コメントです。 補足日時:2016/04/06 01:24

A 回答 (11件中1~10件)

i() が int[3]へのポインタなら (int (*)[3] )


(*i()) は int[3] であり、そのint[3]の配列の先頭アドレスとして扱われ (int *)
(*i())[0] は int[3]の添字0 です。(int)

i()[0] は *i() と同じです。(int *)
i()[1] は *(i() +1)と同じで、 i()の「隣りのint[3]」のアドレスです。(int *)
    • good
    • 0
この回答へのお礼

色々と指摘いただいてありがとうございました。

お礼日時:2016/04/07 20:41

>int (*p)[3]のpの型は、


>int (*)[3]
>か
>int *[3]
>のどちらが正しいのでしょうか?

勿論宣言通りの int (*)[3] です。
ポインタだから、32ビットでコンパイルすれば常に4です。

sizeof(p) を調べるのが簡単です。

>sizeof()で調べると、
>sizeof(int (*)[3]) = 4
>sizeof(int *[3]) = 12
>となり、後の方が合っているように思うのですが?

int *[3] は intを指すポインタの配列(要素数=3)

なので sizeof(int *[3]) は sizeof(int *) * 3
という意味になります。
    • good
    • 0
この回答へのお礼

詳しい説明ありがとうございます。

お礼日時:2016/04/06 07:23

int (*p)[3];


の p は「要素数3個のint型配列」ではなく「要素数 3 の int の配列へのポインタ」ですよ.

ところで sizeof p って調べてみましたか? その値は sizeof (int *[3]) と sizeof (int (*)[3]) のどちらと同じでしたか?
    • good
    • 0
この回答へのお礼

やっぱり勘違いしていました。
型 p

seizeof(型)とsizeof(p)
が同じ大きさになるのは当たり前ですよね。

お礼日時:2016/04/06 07:21

sizeof の結果からどうしてそう思ったのかわからんが int (*p)[3] とあるなら p の型は int (*)[3].

この回答への補足あり
    • good
    • 0

>arrayは先頭要素に対するポインタとも解釈できるので、


>その場合は、(int *)型と解釈できるのではないでしょうか?

同じじゃなくて、変換が必要になったときに変換されるという意味。
決して、配列とポインタは同じ型ではありません。
#最大の違いはサイズ
いつ変換がかかるのかを正確に学びましょう。

これは大鉄則なんで、いままでの誤った解釈はすっぱり忘れましょう。
    • good
    • 0

int (*p)[3]: と宣言した場合


pは配列へのポインタ

p[0]は配列を返すから、配列はその先頭要素への「ポインタ」
に変換される。

つまり、p[0]はintじゃなくポインタ。簡単でしょ?
    • good
    • 0

厳密にいえば, 単純に「arrayは先頭要素に対するポインタとも解釈できる」としてしまってはいけません. まず


配列名は「配列全体というオブジェクト」を表し, その型は「配列型」である
ということが前提で, そのうえで
特定の場合を除いて配列オブジェクトは先頭要素のアドレスに変換される
という規則を適用しなければなりません. 単に「array」とのみ書いた場合, 文脈がない以上「特定の場合」かどうかが判定できません. つまり, 下の変換をしていいかどうかわからないのです. よしんばポインタと解釈するとしても
「arrayの型は、(int *)になると思うのですが、
arrayの型を、(int [3])と解釈して」
は順序が逆です. 本来が int [3] で変換したあとが int *.

なお, 単項 & のオペランドになるときは「特定の場合」にあたる.
この回答への補足あり
    • good
    • 0

int array[3];


と宣言した場合, array の型は int [3] です. int * ではありません.
この回答への補足あり
    • good
    • 0

int x とすると、xのアドレス(intへのポインタ)を求めるには、 &x と &単項演算子を使います。


同様に、
array が int[3] なのだから、 arrayへのアドレスを求める & 演算子を使えば、int[3]へのポインタになり、キャストの必要はありません。


普通にC言語使っていたら、キャストが必要な場面なんてそうそうありません。
・int,double等の数値型の相互変換
・汎用ポインタとしての void *を元の型に戻す
くらいなものです。

それ以外で、キャストしないと警告やエラーが無くならないようなら、プログラムに間違いがあると思った方がよいです。


このプログラムも、
・ return array ; が間違っている
となりますが、他に
・(int *)[3] を戻り値に選んだことが間違っている
戻り値が int * なら、 return array ; で正しい
とも考えられます。
この回答への補足あり
    • good
    • 0

キャストをする前に「キャストをしなくていい方法は存在しないのだろうか」と考えてほしい.

この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!