Foro con Clase C/C++

Como liberar una estructura desde otra función a la que se le pa

Manu Exposito

Nº de hilos:5

Nº de mensajes:13

martes, 23 de febrero de 2021


Hola Salvador. Qué hago mal?

Yo tengo una estructura con varios miembros de diferentes tipos.
Esa estructura la paso como un puntero a diferentes funciones y aparentemente todo funciona pero una de las funciones la libera y le asigna NULL.
Pero cuando pregunto desde la función la llama la estructura no es NULL pero sus miembros si.
Ejemplo

Supón que la estructura miSt y el puntero que apunta a la misma pMiSt
 // En main
...
liberaSt( pMiSt );

// Esta funcion muestra SI siempre  POR QUE? si le asigne NULL. Pero si intento usar cualquier miembro me da un bonito GPF de windows
msg( pMiSt ? "SI": "NO" ) // msg es una funcion que muestra la cadena por pantalla
...
//-------------------------------------
void liberaSt( PMIST pMiSt )
{
       // Libero todos los miembros de la estructura
       ....
      // Y ahora a la propia estructura
      free( pMiSt );
      // Y le asigno NULL
      pMiSt = NULL;
}

El programa es mas complejo que esto, lo que pongo aquí es para explicarme....

Saludos

Tema cerrado

Salvador Pozo

Nº de hilos:0

Nº de mensajes:15

miércoles, 24 de febrero de 2021


Hola:

Los punteros, como cualquier otra variable C, pueden ser pasados a las funciones como parámetros por valor o por referencia.

Cuando un parámetro se pasa por valor, en la función se hace una copia local de ese valor, es posible operar con él, pero al retornar al punto de llamada, la copia local se destruye y su valor no se copia de vuelta a su variable original.

Por ejemplo:

--------
void funcion(int xv)
{
    xv += 100;
   return;
}
...
x = 10;
funcion(x);
/* x sigue valiendo 10 */
--------

En éste ejemplo el valor de x sigue siendo el mismo al retornar de la función, y así debe ser, porque hemos pasado el valor de x, y no el propio x. De otro modo sería imposible invocar esta función con un valor constante: funcion(10).

Con los punteros pasa exactamente lo mismo. En tu caso, la función void libreraSt( PMIST pMiSt) pasa como parámetro el puntero pMiSt por valor, así que cualquier modificación de su valor se pierde al retornar.

En la función se libera la memoria apuntada por pMiSt, ya que su valor es el mismo que el del puntero en el punto de llamada, pero aunque le asignemos el valor NULL, ese valor no se transfiere al puntero original, ya que lo estamos asignando a una variable local.

La solución es simple, basta con pasar el puntero por referencia. En C++ se usa el operador de referencia, pero en C no existe ese operador. En C las referencias se crean mediante punteros, o sea, que tenemos que pasar un puntero al puntero que queremos pasar por referencia.

------
// Solución en C:
void liberaSt( PMIST* pMiSt)
{
       // Libero todos los miembros de la estructura
       ....
       // Y ahora a la propia estructura
       free( *pMiSt );
       // Y le asigno NULL
       *pMiSt = NULL;
}
...
PMIST puntero;
...
liberaSt( &puntero );
------

------
// Solución en C++ (aunque en este caso habría que usar los operadores new y delete en lugar de las funciones malloc y free):
void liberaSt( PMIST& pMiSt)
{
       // Libero todos los miembros de la estructura
       ....
       // Y ahora a la propia estructura
       free( pMiSt );
       // Y le asigno NULL
       pMiSt = NULL;
}
...
PMIST puntero;
...
liberaSt( puntero );
------

Como puedes comprobar, esto hace que la función no pueda ser usada con parámetros constantes, ya que obtendríamos un error al intentar liberar la memoria y al intentar asignar un valor a una constante.

Otra posible solución es usar el valor de retorno para devolver el valor final del puntero, pero a mi modo de ver, esa solución hace más complicado comprender el funcionamiento del programa ante posteriores revisiones o depuraciones.

Esto se explica en el curso, en el capítulo 15:

http://conclase.net/c/curso/cap15#FUN2_PunteParam

Hasta pronto.

Tema cerrado

Manu Exposito

Nº de hilos:5

Nº de mensajes:13

miércoles, 24 de febrero de 2021


Muchas gracias Salvador.
Pensaba que como le pasaba el puntero con eso bastaba.
Miraré el capitulo 15 para ampliar conocimientos

Muchas gracias

Hola:

Los punteros, como cualquier otra variable C, pueden ser pasados a las funciones como parámetros por valor o por referencia.

Cuando un parámetro se pasa por valor, en la función se hace una copia local de ese valor, es posible operar con él, pero al retornar al punto de llamada, la copia local se destruye y su valor no se copia de vuelta a su variable original.

Por ejemplo:

--------
void funcion(int xv)
{
    xv += 100;
   return;
}
...
x = 10;
funcion(x);
/* x sigue valiendo 10 */
--------

En éste ejemplo el valor de x sigue siendo el mismo al retornar de la función, y así debe ser, porque hemos pasado el valor de x, y no el propio x. De otro modo sería imposible invocar esta función con un valor constante: funcion(10).

Con los punteros pasa exactamente lo mismo. En tu caso, la función void libreraSt( PMIST pMiSt) pasa como parámetro el puntero pMiSt por valor, así que cualquier modificación de su valor se pierde al retornar.

En la función se libera la memoria apuntada por pMiSt, ya que su valor es el mismo que el del puntero en el punto de llamada, pero aunque le asignemos el valor NULL, ese valor no se transfiere al puntero original, ya que lo estamos asignando a una variable local.

La solución es simple, basta con pasar el puntero por referencia. En C++ se usa el operador de referencia, pero en C no existe ese operador. En C las referencias se crean mediante punteros, o sea, que tenemos que pasar un puntero al puntero que queremos pasar por referencia.

------
// Solución en C:
void liberaSt( PMIST* pMiSt)
{
       // Libero todos los miembros de la estructura
       ....
       // Y ahora a la propia estructura
       free( *pMiSt );
       // Y le asigno NULL
       *pMiSt = NULL;
}
...
PMIST puntero;
...
liberaSt( &puntero );
------

------
// Solución en C++ (aunque en este caso habría que usar los operadores new y delete en lugar de las funciones malloc y free):
void liberaSt( PMIST& pMiSt)
{
       // Libero todos los miembros de la estructura
       ....
       // Y ahora a la propia estructura
       free( pMiSt );
       // Y le asigno NULL
       pMiSt = NULL;
}
...
PMIST puntero;
...
liberaSt( puntero );
------

Como puedes comprobar, esto hace que la función no pueda ser usada con parámetros constantes, ya que obtendríamos un error al intentar liberar la memoria y al intentar asignar un valor a una constante.

Otra posible solución es usar el valor de retorno para devolver el valor final del puntero, pero a mi modo de ver, esa solución hace más complicado comprender el funcionamiento del programa ante posteriores revisiones o depuraciones.

Esto se explica en el curso, en el capítulo 15:

http://conclase.net/c/curso/cap15#FUN2_PunteParam

Hasta pronto.

Tema cerrado