2008-09-19 11 views
6

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?matriz int con punteros en confusión de asignación de memoria C

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]); 
} 

Respuesta

9

¡El hecho de que la memoria haya sido liberada no significa que no pueda acceder a ella! Por supuesto, es una muy mala idea acceder a ella después de que ha sido liberada, pero es por eso que funciona en su ejemplo.

Tenga en cuenta que free(*first_matrix) solo first_matrix[0] gratis, 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 así 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; 
} 

Entonces, cuando usted los está liberando:

// keep looping until you find the NULL one 
for(int i=0; first_matrix[i] != NULL; i++) { 
    free(first_matrix[i]); 
} 
free(first_matrix); 
+0

parece que el bucle hasta la matriz [i]! = NULL funciona incluso si no configuro el último apuntador a NULL, ¿es esta coincidencia/algo diferente? – Fredrik

+0

Si asigna un puntero adicional y no lo establece, * puede * predeterminado a NULL, dependiendo del sistema operativo (Windows borra la memoria asignada, Unix no lo hace). Si no es así, se ejecutará fuera del final de la matriz asignada y seguirá liberando cosas hasta que golpee un puntero NULL o (más probable) bloquee. –

+1

calloc siempre establece la memoria en nulo. – quinmars

2

necesita liberar cada fila individual:


void free_matrix(int **matrix, int size_x) 
{ 
    for(int i = 0; i < size_x; i++) 
     free(matrix[i]); 
    free(matrix); 
} 
+0

No puede declarar una variable en el ciclo for en C. – terminus

+2

Puede hacerlo en C99, pero su código no será back-portable. –

0

Sólo se liberó la primera fila (o columna) de first_matrix. Escribir 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 hacer la matriz en una estructura para almacenar su fila y número de columnas.

1

Liberar la memoria no la hace desaparecer, solo significa que otra asignación podría capturar ese mismo pedazo de memoria. Lo que sea que pongas, seguirá ahí hasta que algo más lo sobrescriba.

Además, no está liberando todo lo que asignó. 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?

+0

solo quería hacer eso para mostrar que la memoria era libre, pero aprendí que la culpa estaba en mi pensamiento allí, no puedo ejecutar valgrind ya que estoy en ON X y quería ver si realmente lo había liberado – Fredrik

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

+0

estoy en OS X, así que no puedo ejecutar valgrind, de lo contrario lo haría:/ ¿conoce alguna alternativa que funcione en mac? – Fredrik

0

Usted está consiguiendo pérdidas de memoria, ya que 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.

Hay un par de alternativas, sin embargo: - Asignar sizeof (int *) filas + filas cols * sizeof (int) bytes y utilizar los primeros bytes de 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 va con la segunda opción, puede usar una estructura como esta en cualquier compilador C99, y otra vez solo tiene que asignar un solo bloque de memoria (de tamaño numints * sizeof (int) + sizeof (int)) :

struct matrix { 
    int rows; 
    int data[0]; 
} 
0

El concepto se echa en falta aquí, es que por cada calloc, tiene que haber una conexión. y que libre debe aplicarse al puntero pasado de calloc.

recomiendo crear una función (delete_matrix llamado) que utiliza un bucle para liberar a todos los punteros que se puede asignar aquí

for (int i = 0; i < size_x; i ++) { matriz [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 está haciendo ahora,

libre (* first_matrix); gratis (first_matrix);

no hará lo que quiera que haga.

Cuestiones relacionadas