определить 2D массив с помощью malloc и изменить его - PullRequest
8 голосов
/ 27 августа 2010

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

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

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

спасибо!

Ответы [ 7 ]

10 голосов
/ 27 августа 2010

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

Однако в конечном итоге это зависит от вашего варианта использования.


Поскольку некоторые люди испытывают трудности с пониманием действий, выполняемых индексной операцией для array, давайте посмотрим, что 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)))
5 голосов
/ 27 августа 2010

Хотя 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];
3 голосов
/ 27 августа 2010
// 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, хотя, вероятно, будет проще восстановить матрицу другого размера и скопировать значения.

0 голосов
/ 04 мая 2018

Хотя это старый вопрос, вот мое другое решение.

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

int main(int arvc, char* argv[])
{
    int (*a)[5][8];
    int i, j;

    a = (int (*)[5][8])calloc(5*8, sizeof(int));        
    for (i = 0; i < 5; i++) {
        for (j = 0; j < 8; j++)
            (*a)[i][j] = i *10 + j;
    }

    for (i = 0; i < 5; i++) {
        for (j = 0; j < 8; j++)
            printf("%d ", (*a)[i][j]);
        printf("\n");
    }

    return 0;
}

Скомпилируйте и запустите

[user@buzz ~]$ gcc main.c -o main
[user@buzz ~]$
[user@buzz ~]$ ./main
0 1 2 3 4 5 6 7
10 11 12 13 14 15 16 17
20 21 22 23 24 25 26 27
30 31 32 33 34 35 36 37
40 41 42 43 44 45 46 47
[user@buzz ~]$
0 голосов
/ 27 августа 2010

Вместо использования int[row][col] вам лучше "обернуть свою матрицу" в одномерный массив int[row*col].

Вот пример кода:

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

#define DET_MALLOC_FAIL -1
#define DET_READ_FAIL -2
#define DET_WRITE_FAIL -3

typedef struct det_matrix_s {
    double * vect;
    size_t order;
} det_matrix;

void *det_sf_malloc(size_t dsize);
det_matrix * det_matrix_new(size_t order);
#define DET_MAT_ELEM(matr, i, j) \
    ((matr)->vect[((matr)->order * (i)) + (j)])
int det_matrix_read(det_matrix * matr, FILE * src);
int det_matrix_write(det_matrix * matr, FILE * dest);
void det_matrix_delete(det_matrix * matr);

/**
* Malloc wrapper
*/
void * det_sf_malloc(size_t dsize)
{
    void *data = malloc(dsize);
    if(NULL == data){
        exit(DET_MALLOC_FAIL);
    }
    return (data);
}

/**
* Allocates memory for a new matrix
*/
det_matrix * det_matrix_new(size_t order)
{
    det_matrix * res = det_sf_malloc(1 * sizeof(*res));
    double * vect = det_sf_malloc(order * order * sizeof(*vect));
    res->order = order;
    res->vect = vect;
    return (res);
}

/**
* Reads matrix 
*/
int det_matrix_read(det_matrix * matr, FILE * src)
{
    size_t i, j;
    if(NULL == matr || NULL == src){
        return (DET_READ_FAIL);
    }
    for(i = 0; i < matr->order; ++i){
        for(j = 0; j < matr->order; ++j){
            if(stdin == src){
                fprintf(stdout, "mat[%d][%d] = ", i, j);
            }
            fscanf(src, "%lf", &DET_MAT_ELEM(matr, i, j));
        }
    }
    return (EXIT_SUCCESS);
}

/**
* Writes matrix
**/
int det_matrix_write(det_matrix * matr, FILE * dest)
{
    size_t i, j;
    if(NULL == matr || NULL == dest){
        return (DET_WRITE_FAIL);
    }
    for(i = 0; i < matr->order; ++i){
        for(j = 0; j < matr->order; ++j){
            fprintf(dest, "%5.2lf ", DET_MAT_ELEM(matr, i, j));
        }
        fprintf(dest, "\n");    
    }
    return (EXIT_SUCCESS);
}

/**
* Free memory for matrix
*/
void det_matrix_delete(det_matrix * matr)
{
    free(matr->vect);
    free(matr);
}

/**
* Main
*/ 
int main(int argc, char * argv[])
{
    det_matrix * mat = det_matrix_new(3);
    det_matrix_read(mat, stdin);
    det_matrix_write(mat, stdout);
    det_matrix_delete(mat);
    return (EXIT_SUCCESS);
}

Если перераспределение является проблемой, могут возникнуть проблемы. И вы должны использовать двухмерную версию.

0 голосов
/ 27 августа 2010

2D-массив - это одномерный массив одномерных массивов. Поскольку массив - это просто указатель, массив массивов - это массив указателей. Таким образом, вы используете 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-фу как бы ржавый :)

0 голосов
/ 27 августа 2010

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

Нет, вы не можете изменить размер массива. Что вы можете сделать, это использовать указатели и realloc для этого.

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