Ver Mensaje Individual
  #2 (permalink)  
Antiguo 15/07/2015, 03:35
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 9 años, 7 meses
Puntos: 204
Respuesta: Función que devuelve un puntero

Para entender mejor tu problema, quita los punteros. Imagínate este código:

Código C++:
Ver original
  1. int func( )
  2. {
  3.   return 4;
  4. }
  5.  
  6. int main( )
  7. {
  8.   int variable = 10;
  9.   variable = func( );
  10.   printf( "%d\n", variable );
  11. }

¿Qué valor almacena variable al final del programa? queda claro que valdrá 4.

Vale, pero esto era muy facil... y si le ponemos un puntero doble? Veamos

Código C++:
Ver original
  1. int** func( )
  2. {
  3.   return (int**)4;
  4. }
  5.  
  6. int main( )
  7. {
  8.   int** variable = (int**)10;
  9.   variable = func( );
  10.   printf( "%d\n", (int)variable );
  11. }

He añadido algunos cast para evitar warnings, por lo demás queda claro que el programa es el mismo... ¿qué valor se imprimirá ahora? Nuevamente, la respuesta vuelve a ser 4.

Un operador de asignación sustituye un valor por otro... así de simple. Si estamos usando variables por valor ( int, char, double, etc ) se machacará el valor de la variable... si usamos punteros, dado que los punteros almacenan posiciones de memoria, se sustituirá la posición de memoria gestionada por el puntero.

En tu programa lo que sucede es que en la línea 4 haces una reserva de memoria y almacenas la posición de dicha reserva en variable. Pero luego, en la línea 6 haces que variable apunte a otra región de memoria, que será la que te devuelve myfunction. Esto provoca que la memoria reservada en la línea 4 ya no sea accesible (no tienes ninguna variable que te diga dónde se encuentra), por lo que no podrás liberar esa memoria... esto es una fuga de memoria o laguna de memoria y es uno de los problemas más comunes al trabajar con memoria dinámica.

¿Soluciones? tranquilo que las hay. Te expongo un par de ellas:

1. Haces que myfunction se encargue de reservar la memoria:

Código C:
Ver original
  1. char** myfunction( )
  2. {
  3.   char** to_return = (char**)malloc(10*sizeof(char*));
  4.  
  5.   // ... operaciones sobre to_return ...
  6.  
  7.   return to_return;
  8. }
  9.  
  10. int main( )
  11. {
  12.   char ** variable = myfunction();
  13.  
  14.   return 0;
  15. }

2. myfunction recibe como parámetro el puntero sobre el que debe operar. Al recibir un puntero, los cambios que se hagan en la memoria apuntada se verán reflejados al abandonar la función.

Nota que ahora, myfunction recibe también el número de elementos, esto te permite trabajar con arrays de diferentes tamaños.

Código C:
Ver original
  1. void myfunction( char** matriz, int numElementos )
  2. {
  3.   // ... operaciones sobre matriz ...
  4. }
  5.  
  6. int main( )
  7. {
  8.   char ** variable = (char**)malloc(10*sizeof(char*));
  9.  
  10.   myfunction( variable, 10 );
  11.  
  12.   return 0;
  13. }

Y, por cierto, que no se te olvide liberar toda la memoria que hayas reservado. Empieza a adquirir esta costumbre desde el principio para evitar sorpresas desagradables con programas más grandes.

Un saludo.