Ver Mensaje Individual
  #4 (permalink)  
Antiguo 28/11/2013, 16:20
vosk
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 4 meses
Puntos: 83
Respuesta: Como iniciar una Matriz Dinamica en una Funcion???

"...solo que tengo el detalle que con free no se libera del todo la memoria..."

Correcto, tal como te comenté para cada malloc necesitas un free, es decir que cada elemento que reservas con malloc necesitas liberarlo con free; dicho de otra forma, una matriz de 'y' por 'x', ejecutas 1 malloc para reservar las 'y' filas y para cada fila ejecutas un malloc para las 'x' columnas, eso es que necesitas (1+y) mallocs para reservar y (y+1) free para liberar. En el ejemplo que te puse y=2, luego se ejecutan 1+2 mallocs y por lo tanto se requieren los mismos free; algo de codigo:

Código C:
Ver original
  1. void nueva(int **mat, int fil, int col) {
  2.     int i, mallocs = 0;
  3.  
  4.     *mat = malloc(col * sizeof(int *));
  5.     mallocs++;
  6.  
  7.     for(i = 0; i < col; i++){
  8.         (*mat)[i] = malloc(fil * sizeof(int *));
  9.         mallocs++;
  10.     }
  11.  
  12.     printf("Ejecuto %d mallocs\n", mallocs);
  13. }
  14.  
  15.  
  16. void libera(int **mat, int fil, int col) {//aquí solo sirve el nº de columnas
  17.     int i, frees = 0;
  18.  
  19.     for(i = 0; i < col; i++) {
  20.         free((*mat)[i]);
  21.         frees++;
  22.     }
  23.  
  24.     free((*mat));
  25.     frees++;
  26.     *mat = 0;
  27.  
  28.     printf("Ejecuto %d frees\n", frees);
  29. }

Y ahora las llamadas para crear y liberar la matriz:

Código C:
Ver original
  1. int **matriz = 0;
  2.  
  3. nueva(&matriz, 2, 3);
  4. libera(&matriz, 2, 3);

En este caso el numero de llamadas es nº de filas + 1 porque primero reservo las filas (y), y para cada fila las columnas (x); puedes cambiar la forma de implementar: puedes crear primero las columnas y para cada columna reservas las filas, entonces el nº de llamadas a malloc y free serán el nº de columnas + 1. Este orden es importante a la hora de recorrer la matriz y a la hora de liberarla (excepto para matrices cuadradas, pero incluso en esas tiene que quedar claro que son las filas y que son las columnas).


"...Una duda, en el primer bloque de código que pones, no debería la función de recivir a la matriz como (int ***mat) ???..."

Si y no me había dado cuenta; en este caso compila bien porque quiero que genere memoria en el puntero que le envio y da igual *** que ** (es un puntero vacío), pero no es correcto porque no representa lo que indica (un puntero a un doble puntero vacio pero que terminará siendo un puntero a un puntero de punteros). Creo que si tienes que presentarlo ante algun profesor mejor pongas *** tal como tu comentas.


"...Y bueno tambien pensé en eso que dices de una función que retorne el bloque de memoria pero me gustaba mas la idea de retornar 0 o -1..."

Ok es una buena opcion, excepto que te será mas util declarar 0 como ok y >0 como error; observa en siguiente ejemplo:

Código C:
Ver original
  1. typedef unsigned int ERRCHK;
  2. enum ERROR_CODES {
  3.     ERROR_SUCCESS,
  4.     ERROR_NOMEM,
  5.     ERROR_COUNT
  6. };
  7. static char *ERROR_STRINGS[ERROR_COUNT] = {
  8.     "OK",
  9.     "Memoria insuficiente para la operacion"
  10. };
  11.  
  12. ERRCHK ejecuta() {
  13.     if(hay un error) {
  14.         return ERROR_NOMEM;
  15.     }
  16.     return ERROR_SUCCESS;
  17. }
  18.  
  19. int main() {
  20.     ERRCHK errcode;
  21.  
  22.     if((errcode = ejecuta())) {
  23.         printf("Se produjo un error: %s", ERROR_STRINGS[errcode]);
  24.     }
  25.     ...
  26. }

Esto es lo que suele usarse en las librerias que llevan la funcion de get_last_error o get_last_error_message; como ves con nº negativos no puedes usar el contador para iniciar el char *[] (puedes contarlo manualmente pero no es lo mismo).

Saludos
vosk