que - matriz int con punteros en confusión de asignación de memoria C
punteros c++ (7)
Tengo algunos problemas para producir una matriz int sin crear pérdidas de memoria. Quiero poder hacer una matriz dada (global) en cualquier tamaño dinámicamente a través de read_matrix (). Pero luego quiero poder liberar la memoria más adelante. Por lo tanto, en mi método principal, la segunda impresión debería dar como resultado un error de bus ya que no debería tener ninguna memoria asignada. ¿Cómo podría crear esto?
int** first_matrix;
int** second_matrix;
int** result_matrix;
int** read_matrix(int size_x, int size_y)
{
int** matrix;
matrix = calloc(size_x, sizeof(int*));
for(int i = 0;i<size_x;i++) {
matrix[i] = calloc(size_y, sizeof(int));
}
for(int i = 0;i<size_x;i++) {
for(int j = 0;j<size_y;j++) {
matrix[i][j] = i*10+j;
}
}
return matrix;
}
int main(int stackc, char** stack)
{
first_matrix = read_matrix(10,10);
printf("9:3 %d - 4:6 %d /n", first_matrix[9][3], first_matrix[4][6]);
free(*first_matrix);
free(first_matrix);
printf("9:3 %d - 4:6 %d /n", first_matrix[9][3], first_matrix[4][6]);
}
¡Solo porque la memoria haya sido liberada no significa que no puedas acceder! Por supuesto, es una muy mala idea acceder después de que ha sido liberado, pero es por eso que funciona en tu ejemplo.
Tenga en cuenta que free( *first_matrix )
solo first_matrix[0]
libre, no las otras matrices. Es probable que desee algún tipo de marcador para indicar el último conjunto (a menos que siempre sepa cuándo libera el conjunto externo cuántas matrices internas asignó). Algo como:
int** read_matrix(int size_x, int size_y)
{
int** matrix;
matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
for(int i = 0;i<size_x;i++) {
matrix[i] = calloc(size_y, sizeof(int));
}
matrix[size_x] = NULL; // set the extra ptr to NULL
for(int i = 0;i<size_x;i++) {
for(int j = 0;j<size_y;j++) {
matrix[i][j] = i*10+j;
}
}
return matrix;
}
Luego, cuando los liberes:
// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
free( first_matrix[i] );
}
free( first_matrix );
Debe liberar cada fila individualmente:
void free_matrix(int **matrix, int size_x)
{
for(int i = 0; i < size_x; i++)
free(matrix[i]);
free(matrix);
}
El concepto que te falta aquí, es que para cada calloc, debe haber un gratis. y ese libre se debe aplicar al puntero pasado de calloc.
Te recomiendo que crees una función (llamada delete_matrix) que utiliza un bucle para liberar todos los punteros que asignas aquí
for (int i = 0; i <size_x; i ++) {matrix [i] = calloc (size_y, sizeof (int)); }
luego, una vez hecho esto, libere el puntero asignado por este.
matrix = calloc (size_x, sizeof (int *));
La forma en que lo haces ahora,
gratis (* first_matrix); libre (first_matrix);
no hará lo que quieras que haga.
Liberar la memoria no la hace desaparecer, solo significa que otra asignación podría atrapar ese mismo pedazo de memoria. Lo que sea que pongas, seguirá ahí hasta que algo más lo sobrescriba.
Además, no estás liberando todo lo que asignaste. Solo está liberando la matriz de punteros y la primera fila. Pero incluso si liberas todo correctamente, aún tendrías el mismo efecto.
Si desea crear un "error de bus", debe señalar a la memoria que no pertenece a su proceso. ¿Por qué quieres hacer eso de todos modos?
Obtendrá pérdidas de memoria porque está liberando la primera fila de la matriz y la lista de filas, pero ninguna de las filas 1 a n. Debe llamar gratis en un bucle.
Sin embargo, hay un par de alternativas: - Asignar sizeof (int *) rows + rows cols * sizeof (int) bytes y usar los primeros bytes para los punteros de fila. De esta forma, solo tiene un trozo de memoria libre (y también es más fácil para el asignador): use una estructura que contenga el número de filas. Entonces puede evitar la lista de filas por completo (guardando memoria). El único inconveniente es que debe usar una función, una macro o alguna notación desordenada para abordar la matriz.
Si elige la segunda opción, puede usar una estructura como esta en cualquier compilador C99, y nuevamente solo tiene que asignar un solo bloque de memoria (de tamaño numints * sizeof (int) + sizeof (int)):
struct matrix {
int rows;
int data[0];
}
Recomiendo usar valgrind para rastrear la memoria no liberada, en lugar de tratar de hacer que ocurra un error de bus. También es bueno para muchas otras cosas.
Sam
Solo liberaste la primera fila (o columna) de first_matrix. Escribe otra función como esta:
void free_matrix(int **matrix, int rows)
{
int i;
for(i=0; i<rows; i++)
{
free(matrix[i]);
}
free(matrix);
}
Es posible que desee convertir la matriz en una estructura para almacenar su recuento de filas y columnas.