Использование malloc для размещения многомерных массивов с разной длиной строк

У меня есть следующий код C:

int *a;
size_t size = 2000*sizeof(int);
a = (int *) malloc(size);

который отлично работает. Но если у меня есть следующее:

char **b = malloc(2000*sizeof *b);

где каждый элемент из b имеет разную длину.

Как можно сделать то же самое для b, как я сделал для a; то есть следующий код будет корректным?

char *c;
size_t size = 2000*sizeof(char *);
c = (char *) malloc(size);

Ответ 1

Сначала вам нужно выделить массив указателей типа char **c = malloc( N * sizeof( char* )), а затем выделить каждую строку с помощью отдельного вызова malloc, возможно, в цикле:


/* N is the number of rows  */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }

for ( i = 0; i < N; i++ )
{
  /* x_i here is the size of given row, no need to
   * multiply by sizeof( char ), it always 1
   */
  if (( c[i] = malloc( x_i )) == NULL )
  { /* error */ }

  /* probably init the row here */
}

/* access matrix elements: c[i] give you a pointer
 * to the row array, c[i][j] indexes an element
 */
c[i][j] = 'a';

Если вы знаете общее количество элементов (например, N*M), вы можете сделать это в одном распределении.

Ответ 2

Типичная форма для динамического выделения массива NxM типа T равна

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * M);
  }
}

Если каждый элемент массива имеет разную длину, то замените M соответствующей длиной для этого элемента; например

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * length_for_this_element);
  }
}

Ответ 3

Эквивалентное распределение памяти для char a[10][20] будет следующим.

char **a;

a=(char **) malloc(10*sizeof(char *));

for(i=0;i<10;i++)
    a[i]=(char *) malloc(20*sizeof(char));

Надеюсь, это выглядит просто, чтобы понять.

Ответ 4

Другим подходом было бы выделение одного непрерывного фрагмента памяти, содержащего блок заголовка для указателей на строки, а также блок body для хранения фактических данных в строках. Затем просто выделите память, назначив адреса памяти в теле указателям в заголовке на каждой строке. Это будет выглядеть следующим образом:

int** 2dAlloc(int rows, int* columns) {    
    int header = rows * sizeof(int*);

    int body = 0;
    for(int i=0; i<rows; body+=columnSizes[i++]) {  
    }
    body*=sizeof(int);

    int** rowptr = (int**)malloc(header + body);

    int* buf  = (int*)(rowptr + rows);
    rowptr[0] = buf;
    int k;
    for(k = 1; k < rows; ++k) {
        rowptr[k] = rowptr[k-1] + columns[k-1];
    }
    return rowptr;
}

int main() {
    // specifying column amount on per-row basis
    int columns[] = {1,2,3};
    int rows = sizeof(columns)/sizeof(int);
    int** matrix = 2dAlloc(rows, &columns);

    // using allocated array
    for(int i = 0; i<rows; ++i) {
        for(int j = 0; j<columns[i]; ++j) {
            cout<<matrix[i][j]<<", ";
        }   
            cout<<endl;
    }

    // now it is time to get rid of allocated 
    // memory in only one call to "free"
    free matrix;
}

Преимуществом этого подхода является изящное освобождение памяти и возможность использовать напоминающую массив опознавание для доступа к элементам полученного 2D-массива.

Ответ 5

Если каждый элемент из b имеет разные длины, вам нужно сделать что-то вроде:

int totalLength = 0;
for_every_element_in_b {
    totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);

Ответ 6

Я думаю, что двухступенчатый подход лучше всего, потому что c 2-d массивы - это просто массивы массивов. Первым шагом является выделение одного массива, а затем цикл его распределения массивов для каждого столбца, когда вы идете. Эта статья дает хорошие подробности.

Ответ 7

malloc не выделяет на определенных границах, поэтому следует предположить, что он выделяет границу байта.

Возвращенный указатель затем не может использоваться, если он преобразован в любой другой тип, поскольку доступ к этому указателю, вероятно, приведет к нарушению доступа к памяти CPU, и приложение будет немедленно отключено.

Ответ 8

Двумерное распределение динамической памяти массива

int **a,i;

// for any number of rows & columns this will work
a = (int **)malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
    *(a+i) = (int *)malloc(cols*sizeof(int));