Использование 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);
8 ответов:
во-первых, вам нужно выделить массив указателей, таких как
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's 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
) вы можете сделать это в одном распределении.
типичная форма для динамического выделения массива 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); } }
эквивалентное выделение памяти для
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));
Я надеюсь, что это выглядит просто понять.
другой подход заключается в выделении одного непрерывного куска памяти, содержащего блок заголовка для указателей на строки, а также блок тела для хранения фактических данных в строках. Затем просто размечайте память, назначая адреса памяти в теле указателям в заголовке на основе каждой строки. Это будет выглядеть следующим образом:
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 массива.
Если каждый элемент B имеет разную длину, то вам нужно сделать что-то вроде:
int totalLength = 0; for_every_element_in_b { totalLength += length_of_this_b_in_bytes; } return (char **)malloc(totalLength);
Я думаю, что 2-шаговый подход является лучшим, потому что c 2-d массивы просто и массив массивов. Первым шагом является выделение одного массива, а затем цикл через него выделения массивов для каждого столбца, как вы идете. в этой статье дает хорошую деталь.
2-D Массив Динамического Выделения Памяти
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));
malloc не выделяет на определенных границах, поэтому следует предположить, что он выделяет на границе байта.
возвращенный указатель не может быть использован при преобразовании в любой другой тип, так как доступ к этому указателю, вероятно, приведет к нарушению доступа к памяти процессором, и приложение будет немедленно закрыто.