C言語関係掲示板

過去ログ

No887 2次元配列の動的確保と関数渡し

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

2次元配列の動的確保と関数渡し
投稿者---くら(2003/12/17 03:51:17)


いつも掲示板を活用させていただいています。
今回、初めて書き込みをさせていただきますくらといいます。

2次元配列を動的確保(callocなどを使って)した上で、それを
関数に引数として渡したいのですが
どうすればいいのでしょうか?

普通の配列の方はうまくいったのですが
2次元になると良くわかりません。
もしよろしければ、教えて下さい。

No.11238

Re:2次元配列の動的確保と関数渡し
投稿者---NykR(2003/12/17 10:39:47)


"2次元配列"の動的確保はできませんが、
一次元配列を分割して、似たようなことはできます。
イメージ的には↓のようなのが近いと思いますが、array[i*m + j]のようにアクセスする方が簡単かもしれません。

#include <stdio.h>
#include <stdlib.h>

void print_array(int **array, int num_of_line, int num_of_col)
{
    int i, j;

    for (i = 0; i < num_of_line; i++) {
        for (j = 0; j < num_of_col; j++) {
            printf("%4d", array[i][j]);
        }
        putchar('\n');
    }
}

int main(void)
{
    int i, j, n, m;
    int *array, **array2;
    char buf[256];

    do {
        printf("行数\n>");
        fgets(buf, sizeof buf, stdin);
    } while (sscanf(buf, "%d", &n) != 1);

    do {
        printf("列数\n>");
        fgets(buf, sizeof buf, stdin);
    } while (sscanf(buf, "%d", &m) != 1);

    array = malloc(sizeof(int) * n * m);
    array2 = malloc(sizeof(int *) * n);  /* 二次元配列の各行の先頭へのポインタの配列を確保する */

    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            array2[i] = array + i * m;
            do {
                printf("array2[%d][%d] = ", i, j);
                fgets(buf, sizeof buf, stdin);
            } while (sscanf(buf, "%d", &array2[i][j]) != 1);
        }
    }
    print_array(array2, n, m);

    return 0;
}


あるいは、行の数だけのポインタ配列を先に確保して
for (i = 0; i < n; i++) {
    array2[i] = malloc(sizeof(int) * m)
}

としてもarray2[i][j]で二次元配列と同じようにアクセスできます。
ただし、この場合は、全く同じようには扱えません。
例えば、通常の二次元配列
vector[3][4]
では、vector[0][5]は、vector[1][2]と同じですが(あまりやらないけど)、
行毎にmallocする方法では、違います。

No.11250

Re:2次元配列の動的確保と関数渡し
投稿者---くら(2003/12/17 17:13:13)


早速のレスありがとうございます。
>あるいは、行の数だけのポインタ配列を先に確保して
><pre>
for (i = 0; i < n; i++) {
array2[i] = malloc(sizeof(int) * m)
}</pre>
>としてもarray2[i][j]で二次元配列と同じようにアクセスできます。
なるほど、連続した領域を確保するか
個々に確保するかとうことでしょうか・・・・

>ただし、この場合は、全く同じようには扱えません。
>では、vector[0][5]は、vector[1][2]
上記のような使い方をすることはないので
行の数だけ先にポインタを確保するやりかたで
やろうと思います。
**array2、*arrayと2つ宣言する必要もなさそうなので・・
とりあえず
int **test;
test = (int **)calloc(n,sizeof(int *));
for(i=0 ;i<n ;i++){
test[i] = (int *)calloc(m,sizeof(int *));
}
で問題なければ行こうとおもいます。

初歩的な質問になってしまうかもしれませんが
上記のような方法作成したarray2が
array2[i][j]で内容を参照できるのかが良く分かりません。
ポインタで宣言しているだけなのに、配列になっている?
(といっても、実際にできてるんだから出来るのでしょうが)
array[i]のアドレスからj番目のものを
参照しているというように解釈していいのでしょうか。

No.11252

Re:2次元配列の動的確保と関数渡し
投稿者---NykR(2003/12/17 18:04:17)


>**array2、*arrayと2つ宣言する必要もなさそうなので・・

array2 = calloc(sizeof(int *) * n);
*array2 = malloc(sizeof(int) * n * m);

とすれば上の方法でも2つ宣言する必要はないですよ。
#それにfreeも2度で済むし


>ポインタで宣言しているだけなのに、配列になっている?

ポインタはポインタです。

>array[i]のアドレスからj番目のものを
>参照しているというように解釈していいのでしょうか。

いいのです。添字演算子[]が元々そういう意味ですから。
array[i]は*(array + i)のsyntax sugar(人間が読みやすいように、
表記だけ変えたもの。意味は変わらない)です。
array2[i][j]は*(*(array2 + i) + j)と同じ意味になります。

No.11301

Re:2次元配列の動的確保と関数渡し
投稿者---くら(2003/12/18 21:57:33)


>array2[i][j]は*(*(array2 + i) + j)と同じ意味になります。
なるほど、そんな意味だったんですね。
ようやく、しっくりきました。

丁寧な説明本当にありがとうございました。

No.11248

Re:2次元配列の動的確保と関数渡し
投稿者---YuO(2003/12/17 13:15:07)


>2次元配列を動的確保(callocなどを使って)した上で、それを
>関数に引数として渡したいのですが
>どうすればいいのでしょうか?

型T (*)[N]を受けるのだから,関数の引数宣言は
T (*p)[N]
となります。また,関数の引数宣言であれば,
T p[][N]
でも同じことです。


>普通の配列の方はうまくいったのですが
>2次元になると良くわかりません。

型Tの値を受け取りたい場合,引数の宣言は常にT pになりますし,
型Tへのポインタを受け取りたい場合,引数の宣言は常にT *pになります。


No.11251

Re:2次元配列の動的確保と関数渡し
投稿者---くら(2003/12/17 17:16:53)


早い解答ありがとうございました。

型がきまっていれば
そう受ければいいのですね。