17

配列の配列を動的に割り当てるなど、C のいくつかの基本的なことを本当に理解していません。私はあなたができることを知っています:

int **m;

2 次元配列を宣言するためです (その後、*alloc 関数を使用して割り当てられます)。また、実行することで「簡単に」アクセスできます*(*(m + line) + column)。しかし、その配列から要素に値を割り当てるにはどうすればよいでしょうか? gcc を使用すると、次のステートメントm[line][column] = 12;はセグメンテーション違反で失敗します。

任意の記事/ドキュメントをいただければ幸いです。:-)

4

7 に答える 7

35

m[line][column] = 12構文は問題ありません (提供されlinecolumn範囲内にあります)。

ただし、割り当てに使用するコードを作成したわけではないため、間違っているか正しいかを判断するのは困難です。それは次のようなものでなければなりません

m = (int**)malloc(nlines * sizeof(int*));

for(i = 0; i < nlines; i++)
  m[i] = (int*)malloc(ncolumns * sizeof(int));

いくつかの補足事項:

  • このようにして、各行を異なる長さで割り当てることができます (例: 三角配列)
  • 配列を使用しているときに、後で個々の行を realloc() または free() できます
  • 配列全体を free() するときは、すべての行を free() する必要があります
于 2009-01-18T21:53:24.850 に答える
5

あなたの構文 m[line][column] は正しいです。ただし、C で 2D 配列を使用するには、メモリを割り当てる必要があります。たとえば、このコードは、指定された行と列のテーブルにメモリを割り当てます。

int** AllocateArray(int line, int column) {
  int** pArray = (int**)malloc(line*sizeof(int*));
  for ( int i = 0; i < line; i++ ) {
    pArray[i] = (int*)malloc(column*sizeof(int));
  }
  return pArray;
}

簡潔にするために、malloc のエラー チェックを省略したことに注意してください。実際のソリューションにはそれらを含める必要があります。

于 2009-01-18T21:53:54.257 に答える
3

これは 2 次元配列ではなく、配列の配列であるため、複数の割り当てが必要です。

于 2009-01-18T21:57:55.263 に答える
3

これはquinmars のソリューションの修正版で、メモリの単一ブロックのみを割り当て、の厚意により一般的な値で使用できますvoid *

#include <stdlib.h>
#include <string.h>
#include <assert.h>

void ** array2d(size_t rows, size_t cols, size_t value_size)
{
    size_t index_size = sizeof(void *) * rows;
    size_t store_size = value_size * rows * cols;

    char * a = malloc(index_size + store_size);
    if(!a) return NULL;

    memset(a + index_size, 0, store_size);
    for(size_t i = 0; i < rows; ++i)
        ((void **)a)[i] = a + index_size + i * cols * value_size;

    return (void **)a;
}

int printf(const char *, ...);

int main()
{
    int ** a = (int **)array2d(5, 5, sizeof(int));
    assert(a);
    a[4][3] = 42;
    printf("%i\n", a[4][3]);
    free(a);
    return 0;
}

void **キャストするのが本当に安全かどうかはわかりませんint **(標準では、変換時に変換が許可されていると思いますvoid *か?) が、gcc で動作します。安全のために、出現するすべての文字列void *int *...に置き換える必要があります。


次のマクロは、前のアルゴリズムのタイプ セーフ バージョンを実装します。

#define alloc_array2d(TYPE, ROWS, COLS) \
    calloc(sizeof(TYPE *) * ROWS + sizeof(TYPE) * ROWS * COLS, 1)

#define init_array2d(ARRAY, TYPE, ROWS, COLS) \
    do { for(int i = 0; i < ROWS; ++i) \
        ARRAY[i] = (TYPE *)(((char *)ARRAY) + sizeof(TYPE *) * ROWS + \
        i * COLS * sizeof(TYPE)); } while(0)

次のように使用します。

int ** a = alloc_array2d(int, 5, 5);
init_array2d(a, int, 5, 5);
a[4][3] = 42;
于 2009-01-19T00:41:54.370 に答える
1

うーん。オプションとして昔ながらの煙と鏡はどうですか?

#define ROWS  5
#define COLS 13
#define X(R, C) *(p + ((R) * ROWS) + (C))

int main(void)
{
    int *p = (int *) malloc (ROWS * COLS * sizeof(int));
    if (p != NULL)
    {
        size_t r;
        size_t c;
        for (r = 0; r < ROWS; r++)
        {
            for (c = 0; c < COLS; c++)
            {
                 X(r,c) = r * c;  /* put some silly value in that position */ 
            }
        }

        /* Then show the contents of the array */ 
        for (r = 0; r < ROWS; r++)
        {
            printf("%d ", r);   /* Show the row number */ 

            for (c = 0; c < COLS; c++)
            {
                 printf("%d", X(r,c));
            }

            printf("\n");
        }

        free(p);
    }
    else
    {
        /* issue some silly error message */ 
    }

    return 0;
}
于 2009-01-19T00:15:59.073 に答える
1

他の回答にも同意しますが、malloc はかなり遅いため、ほとんどの場合、配列全体を一度に割り当てる方が適切です。


int **
array_new(size_t rows, size_t cols)
{
    int **array2d, **end, **cur;
    int *array;

    cur = array2d = malloc(rows * sizeof(int *));
    if (!array2d)
        return NULL;

    array = malloc(rows * cols * sizeof(int));
    if (!array)
    {
        free(array2d);
        return NULL;
    }

    end = array2d + rows;
    while (cur != end)
    {
        *cur = array;
        array += cols;
        cur++;
    }

    return array2d;
}

配列を解放するには、次のようにします。 free(*array); free(array);

注: この解決策は、行の順序を変更したくない場合にのみ機能します。これは、後で配列を解放する必要がある最初の要素のアドレスを失う可能性があるためです。

于 2009-01-18T23:09:47.317 に答える
0

最初の配列の割り当てに使用malloc(3)し、 によって作成されたポインターをそこに配置すると、C 標準にあると同等である必要があるため、malloc(3)動作するはずです。array[r][c]*(*(array + r) + c)

于 2009-01-18T21:53:22.480 に答える