- ベストアンサー
アドレス格納のための二次元配列のメモリ動的確保
- アドレス格納のための二次元配列のメモリを動的に確保する方法を教えてください。
- int型の配列を動的に確保する場合と同様に、DATA型のポインタを格納するための二次元配列を動的に確保することができます。
- DATA *d; d = (DATA *)malloc( m * n * sizeof(DATA) );という形で二次元配列を動的に確保することができます。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
m×n の int の配列を ◆ int *i; ◆ i = (int *)malloc( m * n * sizeof(int) ); とするのが「ふつう」なのかなぁ? メモリを節約したいならともかく, そうでなければ int **i; i = malloc(m * sizeof (i[0])); i[0] = malloc(m*n*sizeof (i[0][0])); /* 以下 i[1]~i[m-1] に確保した領域を分配する */ の方がいいんじゃないかねぇ. ま, ど~でもいいけど. さておき, 自分で書いた「int の場合」をよく見てください. ここは「int」と明示してあるけど, もっと一般に「T」という型なら当然 T *array; array = (T *)malloc(m*n*sizeof (T)); でしょ? この「T」に, 適切なものを入れればいい. そんだけ.
その他の回答 (4)
- asuncion
- ベストアンサー率33% (2127/6289)
>アドレス格納のための二次元配列 この部分、もし動的確保を使わないとすると、例えば int *p[m][n]; // pは、int型へのポインタを格納する二次元配列 のようになります。 これに類することを動的確保を使って行ないたいのですか? だとすると、まず定義すべきは int ***p; ですね。
お礼
御礼が遅くなり申し訳ありません。 コンパイルが通りました!有難うございました。 じつは勘違いしていて、問題は3次元配列だったのですが、 それでも宣言は int *p[m][n][o]; が int ****p; となる、ということで同じものだったということがわかりました。 非常に勉強になりました。有難うございます。
- kmee
- ベストアンサー率55% (1857/3366)
二次元配列って a[m][n] みたいに、添字2つを使うもので、 malloc(m*n*sizeof(T)) は、あくまで「 m*n の1次元配列」だと思うんですけど。 たとえ、それを [i*n+j]と2次元的に使うとしても。 DATA *の一次元配列を動的に用意するなら ・DATA *の容器を用意するのだから、sizeof(DATA *) (あるいはDATA*型で宣言された変数) ・帰ってくるのは DATA *用に確保した領域へのポインタだから、 DATA * にポインタの*を付けた DATA ** 型
お礼
御礼が遅くなり申し訳ありません。 コンパイルが通りました!有難うございました。 >>上の段 Cはメモリを確保した際、箱の大きささえ合っていればどうとでも使えてしまうので、本質的には同じだと思いますよ。 その意味で、Cには多次元配列は存在しないという主張もあるくらいです。 >>下の段 わかりやすい解説を有難うございました m(_ _)m おかげで他の回答者様方々の回答のソースの読み方を理解することができました。
- magicalpass
- ベストアンサー率58% (378/648)
「DATA型のポインタを格納するための二次元配列」であれば DATA **dp; dp = (DATA**)malloc(m * n * sizeof(DATA *)); となると思います。 構造体の本体は次のように確保していきます。 for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { dp[j * m + i] = (DATA *)malloc(sizeof(DATA)); } }
お礼
御礼が遅くなり申し訳ありません。 コンパイルが通りました!有難うございました。 今回は、最終的には DATA ***d; と宣言する方法を採らせて頂きましたが、 上記のソースの意味も今なら読めます。 ポインタの知識が二次元的になって非常にすっきりした感じです。 有難うございました!!
- 正親町(@Ohgimachi)
- ベストアンサー率43% (110/252)
DATA *d[]; と宣言して malloc(m*n*sizeof(d[0])) と領域のサイズを計算します。 sizeof()を使用して領域を計算する時には型ではなくて、代入する変数を使用するのが暗黙のルールです。理由は変数の型を変更した場合に、sizeof()を修正するのを忘れてもコンパイラは何もエラーを出さないので、バグになる可能性を小さくするためです。
お礼
御礼が遅くなり申し訳ありません。 コンパイルが通りました!有難うございました。 領域サイズ計算は教えていただいたものに全て変更しました。バグの可能性を減らすのは精神衛生上、本当に良い事ですね(笑)。 二次元配列なので、宣言としては DATA ***d; あるいは DATA **d[]; だったようです。
補足
あれ?何を勘違いしていたんでしょう・・・。 すみません。お礼の下のほうは無視してくださいw というか以下に差し替えてくださいorz 正しい回答を頂いた(むしろ僕の最初の質問の趣旨に合わせていただいた)のに・・・。 ホントにすみません・・・。 -- 今回は、最終的には DATA ***d; と宣言する方法を採らせて頂きました。
お礼
御礼が遅くなり申し訳ありません。 コンパイルが通りました!有難うございました。 この「T」がint でも int* でも int** でも使い方は同じなんですね。 実装してみて理解することができました。 これでプログラム内の動的確保の配列全てに関して、宣言の表記とメモリ確保の方法が統一できました。 ソースコードも非常にすっきりして、心晴れやかです。 重ね重ね感謝いたします。 今回は回答を5件頂きました。Tacosan様の回答をベストアンサーに選ばせて頂きました。