, определяющие 2D массив с помощью malloc и его изменение

Как определить двумерный массив с помощью malloc? (допустим, 10X20).

Во-вторых, могу ли я увеличить количество строк или столбцов, не создавая новый увеличенный массив и не копируя все данные в него? Например,

, как мне выделить память, чтобы массив был 10x30 или 15x20?

спасибо!

8
задан Asher Saban 27 August 2010 в 13:40
поделиться

4 ответа

10x30:

int(*array)[30] = malloc((sizeof *array) * 10);

15x20:

int(*array)[20] = malloc((sizeof *array) * 15);

Изменение размера до 20x25:

int(*array2)[25] = realloc(array, (sizeof *array2) * 20);

Внешний размер (10, 15, 20) можно определить во время выполнения, т.к. вычисление индекса компилятором. Внутреннее измерение (30, 20, 25) необходимо знать во время компиляции. Надеюсь, поможет.

Обратите внимание, что в отличие от решений с массивом указателей, это может быть обработано как единый блок памяти, потому что оно размещает все в одном фрагменте памяти, подобно реальному объявленному массиву:

memcpy(somewhere, array2, sizeof(int) * 20 * 25); // (sizeof *array2) * 20

Это в конечном счете зависит от вашего однако.


Поскольку у некоторых людей возникают трудности с пониманием действий, выполняемых индексной операцией над массивом, давайте посмотрим, что Clang дает нам для индексного выражения в следующем коде

int main() {
  int(*array)[10] = malloc((sizeof *array) * 5);
  array[4][9] = 0;

  int(*array1)[10][5] = malloc((sizeof *array1) * 20);
  array1[19][9][4] = 0;
}

Это хороший компилятор, который может печатать свои AST в легко читаемом виде

  // array[4][9] = 0;
  (BinaryOperator 0xba62cc0 <line:5:3, col:17> 'int' '='
    (ArraySubscriptExpr 0xba62c80 <col:3, col:13> 'int'
      (ImplicitCastExpr 0xba62c60 <col:3, col:10> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xba62c20 <col:3, col:10> 'int [10]'
          (DeclRefExpr 0xba62bdc <col:3> 'int (*)[10]' Var='array' 0xba62a00)
          (IntegerLiteral 0xba62c00 <col:9> 'int' 4)))
      (IntegerLiteral 0xba62c40 <col:12> 'int' 9))
    (IntegerLiteral 0xba62ca0 <col:17> 'int' 0))

  // array1[19][9][4] = 0;
  (BinaryOperator 0xba630b8 <line:8:3, col:22> 'int' '='
    (ArraySubscriptExpr 0xba63078 <col:3, col:18> 'int'
      (ImplicitCastExpr 0xba63058 <col:3, col:15> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xba63018 <col:3, col:15> 'int [5]'
          (ImplicitCastExpr 0xba62ff8 <col:3, col:12> 'int (*)[5]' <ArrayToPointerDecay>
            (ArraySubscriptExpr 0xba62fa0 <col:3, col:12> 'int [10][5]'
              (DeclRefExpr 0xba62f5c <col:3> 'int (*)[10][5]' Var='array1' 0xba62db0)
              (IntegerLiteral 0xba62f80 <col:10> 'int' 19)))
          (IntegerLiteral 0xba62fc0 <col:14> 'int' 9)))
      (IntegerLiteral 0xba63038 <col:17> 'int' 4))
    (IntegerLiteral 0xba63098 <col:22> 'int' 0)))

Обратите внимание, что каждое выражение нижнего индекса массива принимает указатель, добавляет значение индекса и возвращает адресный элемент. Если этот подэлемент является массивом, он распадается на указатель на его первый элемент.На самом деле это не отличается от шагов, выполняемых для объявленного массива

int main() {
  int array[5][10] = { };
  array[4][9] = 1;
}

Дает очень похожий AST, только самое внутреннее выражение сначала распадается на указатель на его первый элемент

  // array[4][9] = 1;
  (BinaryOperator 0xbf9f7e8 <line:5:3, col:17> 'int' '='
    (ArraySubscriptExpr 0xbf9f7a8 <col:3, col:13> 'int'
      (ImplicitCastExpr 0xbf9f788 <col:3, col:10> 'int *' <ArrayToPointerDecay>
        (ArraySubscriptExpr 0xbf9f748 <col:3, col:10> 'int [10]'
          (ImplicitCastExpr 0xbf9f728 <col:3> 'int (*)[10]' <ArrayToPointerDecay>
            (DeclRefExpr 0xbf9f6cc <col:3> 'int [5][10]' Var='array' 0xbfa81f0))
          (IntegerLiteral 0xbf9f6f0 <col:9> 'int' 4)))
      (IntegerLiteral 0xbf9f768 <col:12> 'int' 9))
    (IntegerLiteral 0xbf9f7c8 <col:17> 'int' 1)))
10
ответ дан 5 December 2019 в 09:23
поделиться
// first allocate the 20 rows, that contain pointers to int 
// (if the matrix contains int type values)
int **a = malloc(20 * sizeof(int *));

// now loop for each row and allocate data for the actual values
int i;
for(i = 0; i < 20; i++) {
    a[i] = malloc(10 * sizeof(int));
}

Для увеличения размера матрицы вы можете использовать realloc, хотя, вероятно, было бы проще перегенерировать матрицу другого размера и скопировать значения.

3
ответ дан 5 December 2019 в 09:23
поделиться

Двумерный массив — это одномерный массив одномерных массивов. Поскольку массив — это просто указатель, массив массивов — это массив указателей. Итак, вы используете malloc для выделения массива указателей (каждый из которых представляет собой столбец), а затем снова используете его для выделения отдельных массивов (каждый из которых представляет строку).

Чтобы увеличить/уменьшить массив, используйте realloc(ссылка). Вот пример кода:

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

int** alloc_matrix(int w, int h) {
    int** matrix;

    matrix = (int**) malloc(sizeof(int*) * h);
    for(int i = 0; i < h; i++) {
        matrix[i] = (int*) malloc(sizeof(int) * w);
    }

    return matrix;
}

void realloc_matrix(int*** matrix, int new_w, int new_h) {
    *matrix = (int**) realloc((void *)*matrix, sizeof(int*) * new_h);

    for(int i = 0; i < new_h; i++) {
        (*matrix)[i] = (int*) realloc((void *)(*matrix)[i], sizeof(int) * new_w);
    }
}

int main(int argc, char* argv[]) {
    // Allocating matrix
    int** m = alloc_matrix(10, 15);

    // Filling with some data
    for(int y = 0; y < 15; y++) {
        for(int x = 0; x < 10; x++) {
            m[y][x] = y * x; // Notice the index is [y][x] - NOT [x][y]!
        }
    }

    // Printing
    for(int y = 0; y < 15; y++) {
        for(int x = 0; x < 10; x++) {
            printf("%d\t", m[y][x]); // Notice the index is [y][x] - NOT [x][y]!
        }
        printf("\n");
    }

    // Reallocating
    realloc_matrix(&m, 20, 10);

    // Filling with some data
    for(int y = 0; y < 10; y++) {
        for(int x = 0; x < 20; x++) {
            m[y][x] = y * x; // Notice the index is [y][x] - NOT [x][y]!
        }
    }

    // Printing
    for(int y = 0; y < 10; y++) {
        for(int x = 0; x < 20; x++) {
            printf("%d\t", m[y][x]); // Notice the index is [y][x] - NOT [x][y]!
        }
        printf("\n");
    }
}

Извините, если что-то не так. Мой C-fu немного заржавел :)

0
ответ дан 5 December 2019 в 09:23
поделиться

Хотя malloc() напрямую не поддерживает мульти- Для многомерных массивов существуют обходные пути, такие как:

int rows = 10;
int cols = 30;
int *array = malloc(rows * cols * sizeof(int));

// Element (5,6)
int x = 5;
int y = 6;
int element = array [ x * cols + y ];

Хотя это и не двумерный массив напрямую, он работает и, на мой взгляд, самый простой. Но если вы хотите вместо этого использовать синтаксис [][] , вам придется делать указатели на указатели, например:

int rows = 10;
int cols = 30;
// Rows
int **array = malloc(rows * sizeof(int*));
// Cols
int i;
for(i = 0; i < rows; i++)
  array[i] = malloc(cols * sizeof(int));

// Element (5,6)
int x = 5;
int y = 6;
int element = array[x][y];
5
ответ дан 5 December 2019 в 09:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: