Los Segmentos de Memoria Cada vez que se ejecuta cualquier
programa, el mismo deberá pasar a memoria. Los programas
en memoria tienen varias secciones o segmentos, los cuales sirven
para organizar el manejo de la memoria por el programa.
Segmentos de Memoria Los Segmentos de Memoria son: CS ? Code
Segment (Segmento de Código) DS ? Data Segment (Segmento
de Datos) SS ? Stack Segment (Segmento de Pila) HS ? Heap Segment
(Segmento de Heap) Cada Segmento tiene asignado una
“cosa” del programa
Segmentos de Memoria Segmento de Código (CS = Code
Segment) Segmento de Datos (DS = Data Segment) Segmento de Pila
(SS = Stack Segment) Segmento del Heap (HS = Heap Segment)
Segmento de Código En este segmento se guardan las
instrucciones, en lenguaje máquina, de nuestro
programa.
Segmento de Datos En este Segmento se guardan las variables
globales del programa.
Segmento de Pila En este segmento se guardan: Los Llamados a las
funciones: Los parámetros de las funciones llamadas Las
variables locales Otra información necesaria para el
funcionamiento del programa. Cada vez que se llama a una
función entra en este segmento con toda su
información.
Segmento del Heap En este segmento se guardan los objetos que han
sido creados dinámicamente en tiempo de corrido.
El Segmento de Pila y el Llamado de Funciones (Call Stack) void
a(); void b(); void c(); void d(); int main() { a(); // fin
return 0; } void a(){ b(); c(); } void b(){ d(); } void c() {}
void d() {} main() a() b() d() Al terminar la función d()
ella sale del stack Al terminar la función b() ella sale
del stack c() Al terminar la función c() ella sale del
stack Al terminar la función a() ella sale del stack Al
terminar el main() se acaba el programa
Parámetros por Valor y por Referencia Los
parámetros, por defecto, son pasados a las funciones por
valor. Cuando los parámetros son pasados por valor lo que
sucede es que se hace una copia de lo que se manda. Los
parámetros por referencia NO HACEN UNA COPIA, sino que se
refieren a los objetos que fueron enviados como
parámetro.
Parámetros por Valor void f(int x) { x = 5; } … int y =
10; f(y); cout << y << endl; La Memoria (Gp:) 10
(Gp:) y Al declarar y (Gp:) 10 (Gp:) x Al llamar a la
función f, se hace una copia de y (Gp:) 5 (Gp:) x La
función f, cambia el valor de x Al Terminar la
función f: ¿Cuánto queda en la variable
y?
Parámetros por Referencia void f(int& x) { x = 5; }
… int y = 10; f(y); cout << y << endl; La Memoria
(Gp:) 10 (Gp:) y Al declarar y x Al llamar a f crea una
Referencia x 5 Cambia el valor de x
Recursión La Recursión es cuando una función
se llama a si misma. Viene de las definiciones
matemáticas, que por naturaleza son recursivas. Existen
dos partes de una función recursiva: El Caso Base El Caso
Recursivo
Las Partes… El Caso Base Por medio de este caso es que
termina la función recursiva. Es indispensable para evitar
la recursión infinita. El Caso Recursivo Es la parte de la
función en la que se llama a la función otra
vez.
Ejemplo de Hierro… La función factorial está
definida matemáticamente:
Ahora, la función: long int factorial(unsigned int n) { if
(n == 1 || n == 0) return 1; else return n * factorial(n-1);
}
Prueba de Escritorio de factorial Vamos a suponer el llamado a:
factorial(5) Segmento de Pila Llamados a Funciones Anteriores
factorial(5) factorial(4) factorial(3) factorial(1) 1 6 24 120 5
== 0 || 5 == 1 NO 5 * factorial(4) 4 == 0 || 4 == 1 NO 4 *
factorial(3) 3 == 0 || 3 == 1 NO 3 * factorial(2) factorial(2) 2
== 0 || 2 == 1 NO 2 * factorial(1) 1 == 0 || 1 == 1 ¡SI! 1
2
El Segmento de Pila Cuando se llama a una función
recursiva, cada llamado que se haga irá entrando al
segmento de pila. Si la recursión es demasiado
“profunda”, corremos el riesgo de llenar la pila, y
revalsarla: Este es un error de tiempo de corrido llamado
Desbordamiento de Pila (Stack Overflow)