Использование 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));