strings - matrices en lenguaje c
Uso de malloc para la asignaciĆ³n de matrices multidimensionales con diferentes longitudes de fila (8)
Asignación de memoria dinámica de matriz 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));
Tengo el siguiente código C
:
int *a;
size_t size = 2000*sizeof(int);
a = (int *) malloc(size);
que funciona bien Pero si tengo lo siguiente:
char **b = malloc(2000*sizeof *b);
donde cada elemento de b
tiene diferente longitud.
¿Cómo es posible hacer lo mismo para b
que hice para a
; es decir, ¿el siguiente código sería correcto?
char *c;
size_t size = 2000*sizeof(char *);
c = (char *) malloc(size);
Creo que un enfoque de dos pasos es el mejor, porque los arreglos de c 2-d son justos y el conjunto de matrices. El primer paso es asignar una única matriz, luego recorrerla asignando matrices para cada columna sobre la marcha. Este artículo da buenos detalles.
El otro enfoque sería asignar un bloque contiguo de memoria que comprende un bloque de encabezado para punteros a filas, así como un bloque de cuerpo para almacenar datos reales en filas. A continuación, simplemente marque la memoria asignando direcciones de memoria en el cuerpo a los punteros en el encabezado por fila. Se vería de la siguiente manera:
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;
}
La ventaja de este enfoque es la elegante liberación de memoria y la capacidad de utilizar una notación similar a una matriz para acceder a los elementos de la matriz 2D resultante.
La asignación de memoria equivalente para char a[10][20]
sería la siguiente.
char **a;
a=(char **) malloc(10*sizeof(char *));
for(i=0;i<10;i++)
a[i]=(char *) malloc(20*sizeof(char));
Espero que esto parezca simple de entender.
La forma típica para asignar dinámicamente una matriz NxM de tipo T es
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * M);
}
}
Si cada elemento de la matriz tiene una longitud diferente, entonces reemplace M con la longitud apropiada para ese elemento; por ejemplo
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * length_for_this_element);
}
}
Primero, debe asignar una matriz de punteros como char **c = malloc( N * sizeof( char* ))
, luego asigne cada fila con una llamada separada a malloc
, probablemente en el ciclo:
/* 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'';
Si conoce la cantidad total de elementos (por ejemplo, N*M
), puede hacerlo en una única asignación.
Si cada elemento en b tiene diferentes longitudes, entonces debe hacer algo como:
int totalLength = 0;
for_every_element_in_b {
totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);
malloc no se asigna en límites específicos, por lo que se debe suponer que se asigna en un límite de bytes.
El puntero devuelto no se puede usar si se convierte a otro tipo, ya que el acceso a ese puntero probablemente producirá una violación de acceso a la memoria por parte de la CPU, y la aplicación se cerrará inmediatamente.