Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Como iniciar una Matriz Dinamica en una Funcion???

Estas en el tema de Como iniciar una Matriz Dinamica en una Funcion??? en el foro de C/C++ en Foros del Web. Hola buen dia tengan todos ustedes. Veran, tengo que hacer una matriz del tamaño [2^n] x [n] y bueno, lo que hago es que paso ...
  #1 (permalink)  
Antiguo 15/11/2013, 21:31
 
Fecha de Ingreso: febrero-2012
Mensajes: 56
Antigüedad: 12 años, 9 meses
Puntos: 1
Pregunta Como iniciar una Matriz Dinamica en una Funcion???

Hola buen dia tengan todos ustedes.

Veran, tengo que hacer una matriz del tamaño [2^n] x [n] y bueno, lo que hago es que paso la n a una funcion para inicializar; utilizo una matriz dinamica, entonces en main declaro una variable "int **mat" y le paso mat a la funcion. con esto esperaba conseguir la matriz nueva generada por referenciacion en main, sin embargo me lleve la sorpresa que no era asi, uso malloc en la funcion de generacion y el apuntador que me regresa malloc no lo consigue el apuntador de apuntador a mat

Paso directo al código:

Este fue mi primer código

Código C:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4.  
  5. int newMatDin(int **mat, int tam){
  6.     int i,j;
  7.     long int tot = (long int)pow(2,tam); //tam = columnas (J); //tot = 2^col (I)
  8.  
  9.     mat = (int **) malloc(tot * sizeof(int*));
  10.  
  11.     if (mat == NULL)
  12.         return -1;
  13.     else
  14.         printf("Comprobamos nueva direccion %p\n", mat); //Vemos que ya apunta a una direccion
  15.  
  16.  
  17.     for(i=0; i<tot; i++) {
  18.         mat[i] = (int *) malloc(tam * sizeof(int));
  19.         if (mat[i] == NULL)
  20.             return -1;
  21.     }
  22.  
  23.     for(i=0; i<tot; i++) {
  24.         for(j=0; j<tam; j++)
  25.             mat[i][j] = 0;
  26.     }
  27.     return 0;      
  28. }
  29.  
  30.  
  31. //****MAIN
  32. main() { //***TEST***
  33.     int **mat = NULL;
  34.     int n = 4, k=1, i,j, temp;
  35.  
  36.     temp = newMatDin(mat, n);
  37.     if (temp == 0) 
  38.         for(i=0; i<(int)pow(2,n); i++) {
  39.             for(j=0; j<n; j++)
  40.                 printf("%d  - ", mat[0][0]); //Violacion de Segmento, ya que mat = NULL, porque?
  41.             printf("\n");
  42.         }
  43.     else
  44.         printf("ERROR AL GENERAR MATRIZ\n");
  45.  
  46.     //Se generó bien la matriz, sin embargo **mat sigue apuntando a NULL
  47.     printf("**mat apunta a: %p", mat); // NULL  ---  Porque no apunta a la nueva dir dada en malloc??
  48. }






Entonces en lo que le movia a las cosas que se me ocurrian hice este otro, donde paso la direccion del puntero de puntero MAT, y cuando se termina la ejecución de la función, MAT ya cuenta con la direccion que nos dió malloc. Sin embargo ya se me hace muy dificil el manejo de los apuntadores dentro de la funcion y ahora la "Violacion de Segmento" se genera dentro de la funcion


Aca mi segundo código:

Código C:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4.  
  5. /** Generamos la matriz dinamica, todos los elementos en 0,
  6.  *  si hay error retorna -1, sino regresa 0.
  7.  */
  8. int newMatDin(int ***mat, int tam){
  9.     int i,j;
  10.     long int tot = (long int)pow(2,tam); //tam = columnas (J); //tot = 2^col (I)
  11.  
  12.     *mat = (int **) malloc(tot * sizeof(int*)); //No me da error
  13.  
  14.     if (*mat == NULL) //No hay problemas aca, ya tiene direccion
  15.         return -1;
  16.     else
  17.         printf("%p\n", *mat);
  18.  
  19.  
  20.     for(i=0; i<tot; i++) {
  21.         *mat[i] = (int *) malloc(tam * sizeof(int)); //En la segunda iteracion es cuando hay problemas
  22.         if (*mat[i] == NULL)
  23.             return -1;
  24.     }
  25.  
  26.     for(i=0; i<tot; i++) { //Ya no entra bien aca por los problemas anteriores
  27.         for(j=0; j<tam; j++)
  28.             *mat[i][j] = 0;
  29.     }
  30.     return 0;      
  31. }
  32.  
  33.  
  34.  
  35. //******
  36. main() {
  37.     int **mat = NULL;
  38.     int n = 4, k=1, i,j, temp;
  39.  
  40.     printf("MAT: %p\n",mat); //Apunta a NULL
  41.     temp = newMatDin(&mat, n); //Creamos la matriz
  42.     printf("MAT: %p\n",mat); //Apunta a la direccion asigana por MALLOC
  43.  
  44.     //Ya tengo bien el apuntador a la matriz dinamica inicializada en 0s solo que
  45.     //adentro de la funcion hay problemas y no termina el resto bien
  46.  
  47.     printf("%d\n\n", **mat); // ERROR: Violacion de Segmento
  48.  
  49.  
  50. }



Algun experto en el tema que pueda ayudarme?


Gracias
  #2 (permalink)  
Antiguo 16/11/2013, 07:13
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: Como iniciar una Matriz Dinamica en una Funcion???

"...Algun experto en el tema que pueda ayudarme?..."

Bueno no soy un experto pero te puedo echar un cable :))

Tienes que trabajar con la referencia tanto en la llamada como en las asignaciones de la funcion:

Código C:
Ver original
  1. void nueva(int **mat) {
  2.     int i;
  3.  
  4.     *mat = malloc(2 * sizeof(int *));
  5.     for(i=0;i<2;i++){
  6.         (*mat)[i] = malloc(2 * sizeof(int *));
  7.     }
  8. }

Y para la llamada envias la referencia:

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

Alternativamente puedes crear una funcion que retorne el nuevo bloque de memoria:

Código C:
Ver original
  1. int **nueva() {
  2.     int **mat, i;
  3.  
  4.     if(!(mat = malloc(2 * sizeof(int *)))) {
  5.         return 0;
  6.     }
  7.     for(i=0;i<2;i++){
  8.         if(!(mat[i] = malloc(2 * sizeof(int *)))) {
  9.             return 0;
  10.         }
  11.     }
  12.  
  13.     return mat;
  14. }

En este segundo metodo la llamada retorna el nuevo bloque:

Código C:
Ver original
  1. int **matriz = 0;
  2. matriz = nueva();

Lo del los valores de retorno es una buena practica; normalmente se usa el 0 como finalizado sin error, y >0 como indice de error.

En cualquier caso recuerda que para cada malloc necesitas un free.

Saludos
vosk
  #3 (permalink)  
Antiguo 28/11/2013, 14:22
 
Fecha de Ingreso: febrero-2012
Mensajes: 56
Antigüedad: 12 años, 9 meses
Puntos: 1
Respuesta: Como iniciar una Matriz Dinamica en una Funcion???

Muchisimas gracias vosk!!!

ya tenia tiempo que había visto tu respuesta pero estaba tan apretado (sigo) con las tareas de la universidad.

En verdad me ha servido grandemente tu respuesta y era exactamente lo que necesitaba, solo que tengo el detalle que con free no se libera del todo la memoria, pero bueno algo es algo.


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) ??? Creo que ese es el único detalle

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 (me acostumbre a usar -1 cuando comense a usar el sistema y declarabamos PIDs)


Pero en fin.

Nuevamente, muchas gracias!
  #4 (permalink)  
Antiguo 28/11/2013, 16:20
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 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

Etiquetas: apuntadores, dinamica, dinamicamente, dinamicas, dinamico, funcion, malloc, matrices, matriz, puntero
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 16:03.