Как определить двумерный массив с помощью malloc? (допустим, 10X20).
Во-вторых, могу ли я увеличить количество строк или столбцов, не создавая новый увеличенный массив и не копируя все данные в него? Например,
, как мне выделить память, чтобы массив был 10x30 или 15x20?
спасибо!
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)))
// 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
, хотя, вероятно, было бы проще перегенерировать матрицу другого размера и скопировать значения.
Двумерный массив — это одномерный массив одномерных массивов. Поскольку массив — это просто указатель, массив массивов — это массив указателей. Итак, вы используете 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 немного заржавел :)
Хотя 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];