Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: eduu15 en 11 Abril 2018, 00:35 am



Título: No devolver nunca punteros a variables locales a una función en c
Publicado por: eduu15 en 11 Abril 2018, 00:35 am
No entiendo muy bien este concepto y he estado pensando acerca del tema.
Citar
Aclarar que el codigo funciona pero no estoy seguro de que sea correcto



Código:
#include <stdio.h>

int* funcion ()
{
    int resultado=9; //variable local de la funcion, al acabar la funcion se pierde el dato
    int*puntero=&resultado; //cuando termine la funcion puntero no sabra a donde apuntar

    return *puntero; //devuelvo el valor de resultado
}

int main(int argc, char *argv[])
{
    int* p=funcion();
    printf("%i",p); //9

    return 0;
}

Si he comentado mal el programa por favor comentenlo, yo creo que aunque funcione seria incorrecto, porque una vez acabe la funcion, puntero no sabra a donde apuntar y podrian sobreescribirse direcciones de memoria. Ustedes que opinan?


Título: Re: No devolver nunca punteros a variables locales a una función
Publicado por: Yuki en 11 Abril 2018, 00:42 am
Efectivamente la variable "p" apunta a la pila que puede ser sobreescrita.

Es más, creo que si establecieras un par de argumentos más a "printf" el valor seria reemplazado.


Título: Re: No devolver nunca punteros a variables locales a una función
Publicado por: eduu15 en 11 Abril 2018, 00:50 am
Acabo de hacer la prueba y no se esta sobreescibiendo probado en windows y ubuntu curioso el tema


Título: Re: No devolver nunca punteros a variables locales a una función
Publicado por: Yuki en 11 Abril 2018, 02:37 am
Estuve depurando y resulta que tu función retorna el valor "9" entero, no un puntero a la variable.

El ejemplo correcto seria el siguiente:

Código:
#include <stdio.h>

int funcion ()
{
    int resultado=9; //variable local de la funcion, al acabar la funcion se pierde el dato
    return (int)&resultado;
}

int main(int argc, char *argv[])
{
    int* p = (int*)funcion();
    printf("%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i",1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,*p); //9

    return 0;
}

Que de todas formas no funciona debido a la manera que tiene el compilador de generar el código.

¿Como lo hace? Básicamente preserva TODA la memoria necesaria en la pila para empujar los argumentos al arrancar el main, esto evita que se corrompa la pila al invocar funciones privadas y de tipo CDECL.

Esto es con DevC++.


Título: Re: No devolver nunca punteros a variables locales a una función
Publicado por: eduu15 en 11 Abril 2018, 09:07 am
Ok, gracias Yuki


Título: Re: No devolver nunca punteros a variables locales a una función en c
Publicado por: MAFUS en 11 Abril 2018, 09:41 am
Como te han dicho no has devuelto el puntero sino el valor al que apunta. Eso ha pasado por añadir el asterisco a la variable del return. Todavía tienes ahí lío con los operadores de punteros.

Ahora cuidado porque ese valor devuelto ha sido recogido por el puntero p de main y eso quiere decir que ahora apunta a la dirección 9. El programa ha funcionado porque en printf le has pedido la dirección a la que apunta, de haber querido acceder a su contenido el S.O. te habría detenido.

Respondiendo a tu pregunta: cuando se llama a una función previamente se forma un marco de esa función en la pila dónde se encuentran los argumentos, la dirección de retorno y todas las variables locales y el puntero de pila se mueve al final de todo. Cuando una función termina se devuelve el puntero de pila al inicio de todo eso, eso es al final de la función llamante, por esa razón esa memoria que hay después ya no es accesible.

Aunque eso último es mentira. Si devuelves un puntero a una variable local sigues apuntando en esa dirección de memoria que el sistema ya no puede tocar. Es posible y se te permite trabajar allí y mientras no llames a otra función esa memoria no se va a tocar y te parecerá válido lo que hagas. En el momento que llames a otra función harás que la pila aloje datos allí perdiendo todo loque hayas hecho.

Y sí, si me pasas ese puntero a la función puede corromperse a sí misma pues tendrá un puntero que apunta a una zona indeterminada de su marco.


Título: Re: No devolver nunca punteros a variables locales a una función en c
Publicado por: eduu15 en 11 Abril 2018, 15:52 pm
Entonces la conclusion es que aunque el SO te lo permita mejor no hacerlo

Aunque la primera funcion no tenga sentido ya que devuelve un int no un puntero a int esta parte

return *puntero; es como si hiciese return resultado no? estaria desreferenciando el puntero


Título: Re: No devolver nunca punteros a variables locales a una función en c
Publicado por: MAFUS en 11 Abril 2018, 16:08 pm
Así es, dereferencias el puntero antes de devolverlo.
Pero lo dicho. Lo recibe un puntero así que a partir de ese momento estás apuntando a la dirección 9 de la memoria.