重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

アドレス格納のための二次元配列のメモリ動的確保

二次元配列のためにメモリを動的確保しなければならないのですが、
その配列に格納したいものが
「DATA型のポインタ」です。(DATA型はtypedefした構造体です。)

プログラム実行中にmallocで確保した、数あるDATA型の構造体の、その先頭アドレスを
リストアップするための配列です。

この場合、どのような形でmallocすればよいのでしょうか?
教えていただけるとありがたいです。よろしくお願いいたします。

--

たとえば m×n のint型の配列は、
◆ int *i;
◆ i = (int *)malloc( m * n * sizeof(int) );
となりますよね。
この要領がでやるのが一般的にわかりやすいものだとするならその方法でやりたい
(後発の人が自分のソースコードを読む可能性があるため)のです。

--

同様にm×nの「DATA型のポインタを格納するための二次元配列」を動的確保したい場合、

◆ DATA *d;
◆ d = (DATA *)malloc( m * n * sizeof(DATA) );

この文にどのように付け加えたら良いのでしょう?



もうあと一歩な気がするのですが(笑)。しかし参考書等で勉強しましたがわかりませんでした・・・。
わかる方、どなたかよろしくお願いいたしますm(_ _)m
あとこれだけ通ればコンパイルが通るんです!!!!! たぶん(笑)

A 回答 (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」に, 適切なものを入れればいい. そんだけ.
    • good
    • 0
この回答へのお礼

御礼が遅くなり申し訳ありません。

コンパイルが通りました!有難うございました。

この「T」がint でも int* でも int** でも使い方は同じなんですね。
実装してみて理解することができました。
これでプログラム内の動的確保の配列全てに関して、宣言の表記とメモリ確保の方法が統一できました。
ソースコードも非常にすっきりして、心晴れやかです。
重ね重ね感謝いたします。

今回は回答を5件頂きました。Tacosan様の回答をベストアンサーに選ばせて頂きました。

お礼日時:2010/11/05 11:07

>アドレス格納のための二次元配列



この部分、もし動的確保を使わないとすると、例えば

int *p[m][n]; // pは、int型へのポインタを格納する二次元配列

のようになります。
これに類することを動的確保を使って行ないたいのですか?
だとすると、まず定義すべきは

int ***p;

ですね。
    • good
    • 0
この回答へのお礼

御礼が遅くなり申し訳ありません。

コンパイルが通りました!有難うございました。

じつは勘違いしていて、問題は3次元配列だったのですが、
それでも宣言は
int *p[m][n][o];

int ****p;
となる、ということで同じものだったということがわかりました。

非常に勉強になりました。有難うございます。

お礼日時:2010/11/05 11:23

二次元配列って


a[m][n]
みたいに、添字2つを使うもので、 malloc(m*n*sizeof(T)) は、あくまで「 m*n の1次元配列」だと思うんですけど。
たとえ、それを [i*n+j]と2次元的に使うとしても。


DATA *の一次元配列を動的に用意するなら
・DATA *の容器を用意するのだから、sizeof(DATA *) (あるいはDATA*型で宣言された変数)
・帰ってくるのは DATA *用に確保した領域へのポインタだから、 DATA * にポインタの*を付けた DATA ** 型
    • good
    • 0
この回答へのお礼

御礼が遅くなり申し訳ありません。

コンパイルが通りました!有難うございました。

>>上の段
Cはメモリを確保した際、箱の大きささえ合っていればどうとでも使えてしまうので、本質的には同じだと思いますよ。
その意味で、Cには多次元配列は存在しないという主張もあるくらいです。

>>下の段
わかりやすい解説を有難うございました m(_ _)m
おかげで他の回答者様方々の回答のソースの読み方を理解することができました。

お礼日時:2010/11/05 11:20

「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));
}
}
    • good
    • 0
この回答へのお礼

御礼が遅くなり申し訳ありません。

コンパイルが通りました!有難うございました。

今回は、最終的には DATA ***d; と宣言する方法を採らせて頂きましたが、
上記のソースの意味も今なら読めます。
ポインタの知識が二次元的になって非常にすっきりした感じです。
有難うございました!!

お礼日時:2010/11/05 11:00

DATA *d[];


と宣言して
malloc(m*n*sizeof(d[0]))
と領域のサイズを計算します。

sizeof()を使用して領域を計算する時には型ではなくて、代入する変数を使用するのが暗黙のルールです。理由は変数の型を変更した場合に、sizeof()を修正するのを忘れてもコンパイラは何もエラーを出さないので、バグになる可能性を小さくするためです。

この回答への補足

あれ?何を勘違いしていたんでしょう・・・。
すみません。お礼の下のほうは無視してくださいw
というか以下に差し替えてくださいorz

正しい回答を頂いた(むしろ僕の最初の質問の趣旨に合わせていただいた)のに・・・。
ホントにすみません・・・。

--

今回は、最終的には DATA ***d; と宣言する方法を採らせて頂きました。

補足日時:2010/11/05 11:13
    • good
    • 0
この回答へのお礼

御礼が遅くなり申し訳ありません。

コンパイルが通りました!有難うございました。

領域サイズ計算は教えていただいたものに全て変更しました。バグの可能性を減らすのは精神衛生上、本当に良い事ですね(笑)。
二次元配列なので、宣言としては
DATA ***d;
あるいは
DATA **d[];
だったようです。

お礼日時:2010/11/05 10:55

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