El documento describe los conceptos de memoria estática y dinámica en C++. La memoria estática asigna un espacio de memoria fijo durante la compilación, mientras que la memoria dinámica permite cambiar el tamaño de la memoria asignada durante la ejecución usando los operadores new y delete. Se proveen ejemplos de cómo declarar y usar arreglos estáticos y dinámicos para ilustrar estas dos formas de administración de memoria.
2. ¿Qué es la memoria?
Es un lugar donde se guarda información a usar.
Cuando declaramos una variable o un arreglo, el
programa indica que se debe reservar un espacio
de memoria (la cantidad depende del tipo de
dato) desde antes de compilar
Esta memoria permanecerá apartada para ser
usada durante el tiempo que el programa lo
requiera
08/10/20152 Mtl. Lourdes Cahuich
7. Para ilustrar la administración de
memoria…
Usemos un ejemplo en donde tengamos que
usar mucha memoria.
08/10/20157 Mtl. Lourdes Cahuich
8. ¿Recuerdas cómo se almacena un
arreglo en memoria?
08/10/20158 Mtl. Lourdes Cahuich
9. Sabemos que podemos hacer un arreglo tan
grande como queramos.
¿Recuerdas cómo crear, llenar y mostrar un
arreglo en C++?
Hagamos un ejemplo en Visual Studio…
08/10/20159 Mtl. Lourdes Cahuich
10. Si lo hiciéramos como procedimiento
definido por el usuario…
void arregloEstatico(void){
int aE[TAM]; //aquí se declara el arreglo estático cuyo tamaño fijo
//está definido por la constante TAM
cout << "nARREGLO ESTATICOn";
//ciclo para llenar el arreglo estático
for (int i = 0; i < TAM; i++){
cout << "nEscribe elemento " << i << " del arreglo: ";
cin >> aE[i];
}
cout << "n";//imprime en pantalla una línea en blanco
//ciclo para mostrar arreglo estático
for (int i = 0; i < TAM; i++)
cout << aE[i] << " ";
cout << "n";//imprime en pantalla una línea en blanco
}//fin procedimiento arregloEstatico
08/10/201510 Mtl. Lourdes Cahuich
11. Pero …
¿Qué pasa si queremos cambiar el tamaño del
arreglo durante ejecución?
C++ permite cambiar la memoria según se va
necesitando
A esto se llama “memoria dinámica”
Las ventajas de la memoria dinámica es que se
aprovecha mejor la memoria de la máquina,
apartando solamente lo que se necesita
08/10/201511 Mtl. Lourdes Cahuich
12. Operadores “new” y “delete”
new() permite reservar memoria de almacén libre
delete() permite librear la memoria cuando ya no
se necesita
08/10/201512 Mtl. Lourdes Cahuich
13. NEW
Permite reservar un bloque de memoria y
devuelve la dirección de comienzo de dicho
bloque
<variable_apuntador> = new <tipo_dato>;
char *p = NULL;
p= new char;
08/10/201513 Mtl. Lourdes Cahuich
14. NEW
Con este operador también se pueden reservar
bloques de memoria para arreglos.
Estos se conocen como arreglos dinámicos.
Si el operador “new” falla, devuelve un nulo, por
lo que es obligatorio comprobar que el
compilador ha podido realizar la reserva de
memoria.
08/10/201514 Mtl. Lourdes Cahuich
15. Ejemplo práctico
Ahora realicemos un arreglo dinámico en C++
usando Visual Studio…
08/10/201515 Mtl. Lourdes Cahuich
16. Si lo escribiéramos como un procedimiento
definido por el usuario, quedaría…
08/10/201516 Mtl. Lourdes Cahuich
17. void arregloDinamico(void){
int tamDin = 0; //variable para que el usuario indique el tamaño del arreglo que quiere
cout << "nARREGLO DINAMICOn";
cout << "Escribe el tamaño del arreglo de enteros: ";//pide a usuario tamaño deseado
cin >> tamDin; //se guarda el tamaño en variable tamDin
int *pArregloDin; //apuntador para guardar dirección de inicio del arreglo dinámico
pArregloDin = new int[tamDin]; //se aparta memoria dinámica para el arreglo pArregloDin
//ciclo para llenar los elementos del arreglo dinámico
for (int i = 0; i < tamDin; i++){
cout << "nElemento " << i << " ";//pide al usuario ingrese cada uno de
//los elementos del arreglo
cin >> pArregloDin[i];
}//fin for
cout << "n";//imprime en pantalla una línea en blanco
//ciclo para mostrar arreglo dinámico
for (int i = 0; i < tamDin; i++)
cout << pArregloDin[i] << " "; //fin for
cout << "n";//imprime en pantalla una línea en blanco
delete pArregloDin; //librea la memoria dinámica reservada para el arreglo
}//fin procedimiento arreglo dinámico
08/10/201517 Mtl. Lourdes Cahuich
18. La estructura de un programa que
use ambos procedimientos
mostrados es:
#include <iostream>
using namespace std;
#define TAM 10
void arregloEstatico(void);
void arregloDinamico(void);
int main(){
//arreglo estático
arregloEstatico();
//arreglo dinámico
arregloDinamico();
system("pause");
return 0;
}//fin main
08/10/201518 Mtl. Lourdes Cahuich
20. La corrupción de memoria ocurre en un programa
cuando los contenidos de una dirección de
memoria se modifican involuntariamente debido a
errores de programación.
08/10/201520 Mtl. Lourdes Cahuich
21. Cuando los contenidos corruptos de memoria se
usan más adelante en el programa, llevan a un
error o comportamiento extraño del mismo.
08/10/201521 Mtl. Lourdes Cahuich
22. La utilización de apuntadores que dan acceso
explícito a direcciones de memoria y aritmética
de apuntadores, que permiten desarrollar
aplicaciones eficientes, si no se usan de forma
adecuada pueden ocasionar errores de
corrupción de memoria.
08/10/201522 Mtl. Lourdes Cahuich
23. Estos errores son los más peligrosos y los más
difíciles de detectar debido a:
El origen de la corrupción de memoria y su
manifestación durante la ejecución del programa,
pueden estar muy separados, por lo que es difícil
relacionar la causa y el efecto.
Los “síntomas” aparecen en condiciones inusuales,
por lo que es difícil reproducir el error de manera
consistente o constante.
08/10/201523 Mtl. Lourdes Cahuich
24. Categorías de errores
1. Utilización de memoria no inicializada: se
considera que los contenidos de la memoria no
inicializada son valores basura (como poner
comida recién hecha en un plato sucio), y usar
estos valores puede llevar al comportamiento
imprevisible del programa.
08/10/201524 Mtl. Lourdes Cahuich
25. Categorías de errores (cont.)
2. Uso de memoria sin dueño: Cuando un
apuntador es nulo o apunta a una sección de
memoria ya liberada, o una ubicación de
memoria que esta fuera de la pila de memoria
del programa. Suelen causar excepciones de
“fallos de página”, lo que lleva a una falla del
programa.
08/10/201525 Mtl. Lourdes Cahuich
26. Categorías de errores (cont.)
3. Usar memoria más allá de la asignada (buffer
overflow): Si se tiene un arreglo que es usado
dentro de un bucle/ciclo que tiene sus contadores
de elementos incorrectos, la memoria más allá de
los límites del arreglo puede ser manipulada.
08/10/201526 Mtl. Lourdes Cahuich
27. Categorías de errores (cont.)
4. Gestión defectuosa de memoria heap: Fugas de
memoria y liberar memora que no es del “heap” o
está sin asignar.
08/10/201527 Mtl. Lourdes Cahuich
28. Cómo evitar fugas de memoria
Una fuga de memoria es un error de
programación que ocurre cuando un programa no
libera toda la memoria que se reservó, y debido a
esto la aplicación puede quedarse sin memoria y
causar que el sistema falle.
Para prevenir esto se debe saber cuándo ocurren
y hacer buen uso de los operadores “new” y
“delete”.
08/10/201528 Mtl. Lourdes Cahuich
29. Cómo evitar fugas de memoria
1. Por cada “new” se debe utilizar un “delete” para
liberar la misma cantidad de memoria reservada
con “new”.
2. Reserva memoria sólo si la has borrado.
char * str = new char[30]; //aparta dirección mem
//delete [] str; //esta linea corrige error
str = new char [60]; //da otra dirección de mem
//se pierde la primera memoria apartada
3. Vigila las asignaciones de apuntadores.
08/10/201529 Mtl. Lourdes Cahuich