Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: NextByte en 5 Marzo 2019, 04:11 am



Título: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 5 Marzo 2019, 04:11 am
Buenas a todos, teniendo en cuenta el siguiente programa:

Código
  1. #include <iostream>
  2.  
  3. using namespace std;
  4. int *ptr;
  5.  
  6. void h(){
  7.     int a = 333;
  8.     ptr = &a;
  9.     cout << "Direccion de memoria" << ptr << endl;
  10. }
  11.  
  12.  
  13. int main(){
  14.  
  15.     h();
  16.     cout << *ptr << endl;
  17. }
  18.  

A través del programa anterior tengo un puntero global, este puntero lo hago que apunte a una variable y simplemente despues verifico que realmente si apunte a ella. Mi pregunta es... la variable 'a' que esta declarada en la función 'h' a la cual hago que apunte ptr dentro de la función tiene un tiempo de vida que se ve limitada por las llaves de la función, cuando yo regreso al main el tiempo de vida de la variable 'a' ha terminado sin embargo el espacio de memoria donde estaba contenido y que ahora es apuntado por el puntero ¿sigue estando reservado?, es decir, ¿ese espacio de memoria sigue siendo considerado como ocupado por una variable? o fue liberado al mismo tiempo que termino el tiempo de vida de la variable 'a'. Tengo la incertidumbre de si ese pedazo de memoria regreso al conjunto de la memoria disponible pero sin embargo sigue teniendo los valores que anteriormente fueron utilizados para representar a la variable 'a' y que pueda ser posible que por ahora el apuntador me siga mostrando ese valor pero sin embargo conforme vaya avanzando un programa y se reserve memoria etc... Ese segmento de memoria pueda llegar a ser sobrescrito por un nuevo valor de una variable .


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: srWhiteSkull en 5 Marzo 2019, 05:15 am
No, no se destruye y tampoco puedes reservar en ese espacio que se encuentra en la pila del programa. Las variables además no son punteros son una referencia a ese espacio que se reemplazan al compilar. Cuando compilas A ya no existe, solo en el codigo fuente.

Por otro lado cuando un espacio es liberado, trabajando con punteros, el espacio sigue manteniendo el contenido que tenía, no se rellena con ceros.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 5 Marzo 2019, 05:49 am
No, no se destruye y tampoco puedes reservar en ese espacio que se encuentra en la pila del programa. Las variables además no son punteros son una referencia a ese espacio que se reemplazan al compilar. Cuando compilas A ya no existe, solo en el codigo fuente.

Por otro lado cuando un espacio es liberado, trabajando con punteros, el espacio sigue manteniendo el contenido que tenía, no se rellena con ceros.
Cuando dices que "No, no se destruye y tampoco puedes reservar en ese espacio que se encuentra en la pila del programa. " haces referencia a que una vez que se termino el tiempo de vida de la variable aún se sigue preservando el espacio en la pila del programa debido a que el puntero hace referencia a esa zona de memoria ? . Comprendo que no se rellene con 0 una vez que se llega a liberar la memoria pero mi duda es como determina que segmentos de memoria deben regresarse al conjunto de memoria disponible . En el ejemplo anterior yo  pensaria  que tal vez en tiempo de compilacion la memoria a la que hacia referencia la variable 'a' va ser liberada o pasada al conjunto de memoria disponible cuando se termina el bloque de codigo donde fue declarada sin embargo en el caso de que un puntero global haya hecho referencia ese segmento de memoria antes... el compilador detecta que aunque el tiempo de vida de la referencia("variable a") ha terminado se tiene un puntero que apunta a ese segmento de memoria y por lo tanto ese segmento de memoria permanece en la pila del programa.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: srWhiteSkull en 5 Marzo 2019, 05:58 am
Mira es fácil de entender, la pila del programa es un espacio estático, lo reserva el compilador, no se reserva en tiempo de ejecución. Mientras que cuando reservas memoria dinámica, con new, malloc o lo que sea, le pides al sistema dinamicamente que te reserve un espacio el cual es neceserio liberar, y la pila se libera al finalizar el programa.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: Loretz en 5 Marzo 2019, 06:04 am
Citar
El espacio de memoria donde estaba contenido y que ahora es apuntado por el puntero ¿sigue estando reservado?
No, al volver de h() ya no está reservado.

Citar
es decir, ¿ese espacio de memoria sigue siendo considerado como ocupado por una variable?
No, ya no.

Citar
o fue liberado al mismo tiempo que termino el tiempo de vida de la variable 'a'.
Sí, así es.

Citar
Tengo la incertidumbre de si ese pedazo de memoria regreso al conjunto de la memoria disponible...
Sí, vuelve a estar disponible (es una porción de memoria en la stack, automática).

Citar
... pero sin embargo sigue teniendo los valores que anteriormente fueron utilizados para representar a la variable 'a' ...
Puede tenerlos o no, después de volver de h() su valor es "indefinido" (quizá sí, quizá no), algunos compiladores le asignarán un cero, otros lo dejarán como está, en otros contendrá cualquier cosa al azar; para el lenguaje su valor es "indefinido".

Citar
... y que pueda ser posible que por ahora el apuntador me siga mostrando ese valor pero sin embargo conforme vaya avanzando un programa y se reserve memoria etc...
Puede ser posible, pero depende del compilador y de la suerte que tengas ese día. Es lo que el estándar C++ califica como "Undefined Behavior" (comportamiento indefinido, si pretender leerlo o desreferenciarlo puede pasar cualquier cosa, normalmente mala).

Citar
Ese segmento de memoria pueda llegar a ser sobrescrito por un nuevo valor de una variable .
Sí, es memoria disponible para el programa, ¿por qué no?


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 5 Marzo 2019, 06:05 am
Mira es fácil de entender, la pila del programa es un espacio estático, lo reserva el compilador, no se reserva en tiempo de ejecución. Mientras que cuando reservas memoria dinámica, con new, malloc o lo que sea, le pides al sistema dinamicamente que te reserve un espacio el cual es neceserio destruir.
Ohh... Ahora entiendo... Entonces cuando en los cursos basicos hablan sobre el tiempo de vida de una variable solo hacen referencia a la zona o area donde vas a poder acceder a una direccion de memoria a la cual hace referencia esa variable pero sin embargo cuando sale de ese tiempo de vida no es que exista una liberacion de memoria sino que simplemente ya no se puede acceder con el nombre de esa variable. Supongo entonces que el hecho de que se crearan los tiempos de vida fue por el hecho de intentar crear programas mas faciles de mantener y evitar todo global por que realmente no es que se este haciendo alguna optimizacion de memoria en el sentido de que se esta liberando memoria con las variables que sobrepasaron su tiempo de vida.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 5 Marzo 2019, 06:42 am
No, al volver de h() ya no está reservado.
 No, ya no.
 Sí, así es.
 Sí, vuelve a estar disponible (es una porción de memoria en la stack, automática).
 Puede tenerlos o no, después de volver de h() su valor es "indefinido" (quizá sí, quizá no), algunos compiladores le asignarán un cero, otros lo dejarán como está, en otros contendrá cualquier cosa al azar; para el lenguaje su valor es "indefinido".
 Puede ser posible, pero depende del compilador y de la suerte que tengas ese día. Es lo que el estándar C++ califica como "Undefined Behavior" (comportamiento indefinido, si pretender leerlo o desreferenciarlo puede pasar cualquier cosa, normalmente mala).
 Sí, es memoria disponible para el programa, ¿por qué no?

Desde tu punto de vista entonces a diferencia de "srWhiteSkull" hablas de que la pila de variables que el menciona como estatica tu haces referencia de que puede llegar a comportarse de manera dinamica de manera que cuando entra-sale de la funcion todos lo segmentos de memoria que componen a las variables declaradas en ella son regresadas a memoria disponible incluso cuando existe un puntero que tiene un ambito global y que hace referencia a un segmento de memoria que era parte de una variable de la cual su ambito o su tiempo de vida ya ha terminado. ¿Algo asi ?, o ¿estoy mal interpretando alguna de las dos respuestas?


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: srWhiteSkull en 5 Marzo 2019, 09:37 am
No es una pila de variables... Look at this
_8-ht2AKyH4


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: MAFUS en 5 Marzo 2019, 14:24 pm
Imagínate que trabajas en un edificio de oficinas y tú y tu equipo trabajáis en una.
Vais a emprender un proyecto nuevo y necesitas más espacio así que se lo dices a tu jefe y os cede otro espacio, te da una llave para que puedas acceder a ella. Esa llave es tu puntero y la oficina nueva tu variable.
Trabajas con tu oficina, pones y quitas mobiliario cómo quieras. Trabajas con tu variable.
Tu proyecto termina y el jefe la libera de tu propiedad pero en vez de devolver la llave te la quedas. Eso es: la función termina pero tu puntero sigue apuntando allí.
Teniendo la llave puedes entrar y ver lo que hay o poner cosas ¿por qué no? tienes la llave. Si la oficina no ha sido asignada a nadie mas no haces daño a nadie, tan solo puede ocurrir que el jefe se enfade, pero si la oficina ha sido asignada a otro grupo ya los vas a molestar, incluso puede que mandes al traste el trabajo que están haciendo.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 5 Marzo 2019, 15:38 pm
Gracias a todos por su tiempo y comentarios, solo quisiera reafirmar si lo que pienso es correcto.
En el programa del inicio entonces tendria la siguiente situación.......
1. En la memoria 'stack' yo tendria inicialmente a la funcion main con todas su variables y en la memoria global tendria al puntero
2. Entra a la funcion 'h()' por lo cual en la memoria 'stack' se ve almacenada la informacion de la funcion y con ella la variable 'a'.( El proyecto dentro de una empresa empieza y me asigna una oficina ).
3. El puntero apunta a la dirección de memoria que tiene la variable 'a' . ( Tengo una llave que me ayuda a abrir la oficina ).
4. Termina la función 'h()' y por lo tanto se regresa a la funcion main con lo cual para el programa tanto las variables 'a' como el segmento de memoria que ella ocupaba ya no esta ocupado aun que yo tenga un puntero global apuntado anteriormente a ella ( El proyecto finaliza pero se me permite seguir conservando la llave ).
5. Finalmente se puede dar que con el puntero final yo pueda seguir accediendo a ese segmento de memoria y succeda algo de lo siguiente:
      -El segmento de memoria sigue conservando el valor que yo asigne a la variable 'a'.
      -El segmento de memoria contenga valores que el compilador asigno cuando se salio de la funcion para representar que esta vacio.
      -Que yo pueda seguir viendo el mismo valor de 'a' por gran parte del programa pero que pueda que tenga la mala suerte que ese segmento de memoria llegue a ser ocupado por el valor de una nueva variable y que al yo seguir haciendo referencia con el puntero global  no me puedo fiar en que ese segmento de memoria siga conteniendo el valor de 'a' que se le asigno inicialmente.


Finalmente entonces para asegurar que el puntero global pueda seguir conservando el valor 'a' sin problemas deberia hacer uso de una reservacion de memoria de manera dinamica con ayuda de new o malloc y asignarle el valor de la variable 'a'.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: Loretz en 5 Marzo 2019, 20:43 pm
Para seguir con el ejemplo de la oficina...

El puntero global es como si guardara una copia de la llave, una copia de la variable local a.

Pero al dejar la oficina, el nuevo inquilino puede
- Cambiar la cerradura; en ese caso ptr ya no sirve.
- Dejar la cerradura como estaba, pero como se dedica a experimentos de transmutación genética, en el cajón donde tú creías que habías dejado la botella, ahora hay... ahora hay.... (NOOOOOOOOO)


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: srWhiteSkull en 7 Marzo 2019, 04:15 am
1. En la memoria 'stack' yo tendria inicialmente a la funcion main con todas su variables y en la memoria global tendria al puntero.
En tú caso no se bien si tendrías algo en la pila porque main() lo declaras sin parámetros y el puntero está sin inicializar.

2. Entra a la funcion 'h()' por lo cual en la memoria 'stack' se ve almacenada la informacion de la funcion y con ella la variable 'a'.( El proyecto dentro de una empresa empieza y me asigna una oficina ).
Así es, en la pila los primeros elementos serían los conformados por el valor del entero, 333. Eso dependería del sistema, los bytes que ocupe en la pila, pero con un usigned char se vería más claro (1 byte).

3. El puntero apunta a la dirección de memoria que tiene la variable 'a' . ( Tengo una llave que me ayuda a abrir la oficina ).
Si, en ese momento se toma la referencia del primer elemento de la pila a.

Para probar ésto simplemente declara la variable pero no la inicialices y luego imprime su valor. Ejemplo:

Código
  1. #include <iostream>
  2.  
  3. char * p;
  4.  
  5. void fu() {
  6. char a;
  7. printf("a = %c", a); // Esta accion algunos compiladores no te lo permiten, ya que esta sin inicializar.
  8. a = 'A';
  9. p = &a;
  10. }
  11.  
  12. int main()
  13. {
  14. fu();
  15. printf("%c puntero %p\n",(*p), p);
  16. (*p) = 'F';
  17. fu(); // Verás que el valor de "a", aun sin inicializar ahora te da "F"...
  18. printf("%c puntero %p\n", (*p), p); // y sigue apuntando al mismo elemento.
  19.  
  20. return 0;
  21. }

4. Termina la función 'h()' y por lo tanto se regresa a la funcion main con lo cual para el programa tanto las variables 'a' como el segmento de memoria que ella ocupaba ya no esta ocupado aun que yo tenga un puntero global apuntado anteriormente a ella ( El proyecto finaliza pero se me permite seguir conservando la llave ).
Ojo, que la pila sigue ahí, ya que fue reservada al inicio del programa. La pila sólo es liberada al finalizar el programa.

5. Finalmente se puede dar que con el puntero final yo pueda seguir accediendo a ese segmento de memoria y succeda algo de lo siguiente:
      -El segmento de memoria sigue conservando el valor que yo asigne a la variable 'a'.
      -El segmento de memoria contenga valores que el compilador asigno cuando se salio de la funcion para representar que esta vacio.
      -Que yo pueda seguir viendo el mismo valor de 'a' por gran parte del programa pero que pueda que tenga la mala suerte que ese segmento de memoria llegue a ser ocupado por el valor de una nueva variable y que al yo seguir haciendo referencia con el puntero global  no me puedo fiar en que ese segmento de memoria siga conteniendo el valor de 'a' que se le asigno inicialmente.
Mientras no finalice el programa tú puntero conserva la referencia al primer elemento de la pila (ver ejemplo del tercer punto).

Finalmente entonces para asegurar que el puntero global pueda seguir conservando el valor 'a' sin problemas deberia hacer uso de una reservacion de memoria de manera dinamica con ayuda de new o malloc y asignarle el valor de la variable 'a'.
:-\ No, puedes conservar el puntero, no hay problema, pero cuando trabajas con punteros y quieres reservar memoria al usar new, alloc o lo que sea... el sistema te reserva memoria en otro segmento, no en el segmento de la pila. El segmento que te dan al reservar memoria dinámica es el que muestra en el vídeo como Heap o Monto. Trabajar con memoria dinámica o con la pila tiene sus ventajas y desventajas, por ejemplo con pila la gestión es más rápida pero en contra tienes que suele estar limitada a un tamaño pequeño, por ejemplo un mega o algo así (depende). La memoria dinámica siempre debes liberarla cuando no la uses porque podrías quedarte sin memoria.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: NextByte en 7 Marzo 2019, 05:16 am
Ojo, que la pila sigue ahí, ya que fue reservada al inicio del programa. La pila sólo es liberada al finalizar el programa.
Mientras no finalice el programa tú puntero conserva la referencia al primer elemento de la pila (ver ejemplo del tercer punto).

De antemano muchas gracias por tu tiempo , todo lo que anteriormente me mencionaste me ayudo mucho sin embargo aún sigo poniendo en duda esta parte. Entiendo que inicialmente el programa se incia en el main con lo cual en la pila se encuentra la funcion main con el respectivo almacenamiento de su variables sin embargo a la hora de hacerse un llamado a la función como 'h()' yo tengo entendido que realmente se crea un nuevo elemento en la pila que contiene informacion sobre la funcion 'h()' y ademas esa variable a la cual hago referencia mediante el apuntador global. El momento en donde entro en conflicto es cuando dices que la pila sigue ahi, te refieres a que una vez regresando al main la pila sigue ahi en el sentido de que la pila solo contiene la informacion relacionada con main o que ademas de seguir existiendo como primer elemento la informacion relacionada con 'main' se tiene que sigue existiendo todo lo relacionado con la funcion 'h()' que anteriormente fue llamada. El hecho de que sigan existiendo las dos funciones en las pila aun cuando ya se salio de la funcion 'h'[Mencionado que el puntero de la pila apunta a la funcion main] me hace dudar en el sentido de que:


1. Puedo interpretar que si se tiene muchas funciones en un programa lo mas seguro es que como mencionas que la pila se genera desde el comienzo y solo es eliminada hasta el final entonces yo tengo una pila con 'n' elementos que representan a cada funcion que posiblemente puede ser llamada desde mi funcion main.

2. En un programa donde se haga el llamado recursivo entonces el compilador deberia saber desde el comienzo del programa cuantos llamados a esa funcion se va realizar debido a que cada llamado a funcion debe tener distintos valores en sus variables y en dado caso rellenar la pila con informacion para cada uno de esos llamados lo que me lleva a que cuando termine de procesar todos los llamados a funciones no se va liberar/eliminar el elemento correspondiente a todas esas funciones en la pila.

3.Si no se libera entonces esta memoria que se vincula para cada llamado de funcion entonces yo podria estar seguro de que la zona de memoria que ocupo mi variable en alguna funcion no va poder ser modificada por una nueva demanda de memoria por parte del programa. En el caso de que realmente entonces si se vaya  liberando toda esa información vinculada a la funcion entonces caeria denuevo en cuenta de que es posible que realmente esa localidad en memoria que fue asignada para la variable 'a'  pueda ser modificada por alguien distinto al puntero, por ejemplo una asignación de memoria de una variable que fue utilizada en una función posterior.

Disculpame si soy algo terco, los casos anteriores solo son para la situación en la cual la pila sigue conservando todos los llamados a funciones aun cuando su llamado a finalizado que creo que es lo que he entendido  de tu anterior comentario.No descarto que tengas la razón pero en mi cabeza aún siguen sin encajar esas piezas. De nuevo te agradezco por tu tiempo.Todo lo anterior tambien lo digo por el hecho de que en los demas comentarios pareciera ser que la mayoria hagan inferencia de que no me puedo fiar de que la zona en donde apunta el apuntador  conserve el valor que yo asigne inicialmente en la funcion.


Título: Re: Preservacion del contenido de la memoria en contra de tiempo de vida de variable
Publicado por: srWhiteSkull en 7 Marzo 2019, 07:41 am
De antemano muchas gracias por tu tiempo , todo lo que anteriormente me mencionaste me ayudo mucho sin embargo aún sigo poniendo en duda esta parte. Entiendo que inicialmente el programa se incia en el main con lo cual en la pila se encuentra la funcion main con el respectivo almacenamiento de su variables sin embargo a la hora de hacerse un llamado a la función como 'h()' yo tengo entendido que realmente se crea un nuevo elemento en la pila que contiene informacion sobre la funcion 'h()' y ademas esa variable a la cual hago referencia mediante el apuntador global. El momento en donde entro en conflicto es cuando dices que la pila sigue ahi, te refieres a que una vez regresando al main la pila sigue ahi en el sentido de que la pila solo contiene la informacion relacionada con main o que ademas de seguir existiendo como primer elemento la informacion relacionada con 'main' se tiene que sigue existiendo todo lo relacionado con la funcion 'h()' que anteriormente fue llamada. El hecho de que sigan existiendo las dos funciones en las pila aun cuando ya se salio de la funcion 'h'[Mencionado que el puntero de la pila apunta a la funcion main] me hace dudar en el sentido de que:
A ver la información que exista de las funciones y variables en la pila permanece, de ahí que dijera que no se destruye(la prueba es contenido del puntero), lo que pasa es que la pila tiene un mecanismo que gestiona la pila como si fuera un array. Hay una serie de índices que indican a la máquina en que parte de la pila esta la información que necesita etc...

1. Puedo interpretar que si se tiene muchas funciones en un programa lo mas seguro es que como mencionas que la pila se genera desde el comienzo y solo es eliminada hasta el final entonces yo tengo una pila con 'n' elementos que representan a cada funcion que posiblemente puede ser llamada desde mi funcion main.

Un caso así sería la recursión, la pila va acumulando dinamicamente los valores en las sucesivas llamadas hasta tal punto que el indice de la pila sale del segmento, espacio reservado, y se genera el famoso stack overflow o desbordamiento de la pila.

2. En un programa donde se haga el llamado recursivo entonces el compilador deberia saber desde el comienzo del programa cuantos llamados a esa funcion se va realizar debido a que cada llamado a funcion debe tener distintos valores en sus variables y en dado caso rellenar la pila con informacion para cada uno de esos llamados lo que me lleva a que cuando termine de procesar todos los llamados a funciones no se va liberar/eliminar el elemento correspondiente a todas esas funciones en la pila.

No, cuando hay una función se cargan sus datos dinamicamente en la pila y el índice va sumando para que la siguiente información de la función no solape la anterior(se apila). Liberar espacio en la pila simplemente se traduce en mover el índice hacia atrás o restar. La función ya existe en el segmento de código pero un mecanismo interno va registrando que parte de la pila tiene asignada cada llamada.

3.Si no se libera entonces esta memoria que se vincula para cada llamado de funcion entonces yo podria estar seguro de que la zona de memoria que ocupo mi variable en alguna funcion no va poder ser modificada por una nueva demanda de memoria por parte del programa. En el caso de que realmente entonces si se vaya  liberando toda esa información vinculada a la funcion entonces caeria denuevo en cuenta de que es posible que realmente esa localidad en memoria que fue asignada para la variable 'a'  pueda ser modificada por alguien distinto al puntero, por ejemplo una asignación de memoria de una variable que fue utilizada en una función posterior.

Está explicado en los puntos anteriores, son registros que actúan como índices en la pila y diversos mecanismos que se me hacen difícil explicar y puedes hallar en documentación referentes a ensamblador, gestión de la pila, llamadas a funciones, etc..

Disculpame si soy algo terco, los casos anteriores solo son para la situación en la cual la pila sigue conservando todos los llamados a funciones aun cuando su llamado a finalizado que creo que es lo que he entendido  de tu anterior comentario.No descarto que tengas la razón pero en mi cabeza aún siguen sin encajar esas piezas. De nuevo te agradezco por tu tiempo.Todo lo anterior tambien lo digo por el hecho de que en los demas comentarios pareciera ser que la mayoria hagan inferencia de que no me puedo fiar de que la zona en donde apunta el apuntador  conserve el valor que yo asigne inicialmente en la funcion.
Si, ya veo que eres duro de molleja pero hasta aquí puedo ayudarte. Quizás deberías aprender ensamblador de cualquier arquitectura para comprenderlo mejor cosa que toma tiempo.

Bueno te deseo suerte con el tema, saludos.