Upload
others
View
5
Download
0
Embed Size (px)
Citation preview
9
GradoenIngenieríaInformáticaGradoenIngenieríadelSoftware
GradoenIngenieríadeComputadores
LuisHernándezYáñez
FacultaddeInformáticaUniversidadComplutense
Fundamentos de la programaciónLuis Hernández Yáñez
Fundamentos de la programación: Punteros y memoria dinámica
Direcciones de memoria y punteros 849Operadores de punteros 854Punteros y direcciones válidas 864
Punteros no inicializados 866Un valor seguro: NULL 867
Copia y comparación de punteros 868Tipos puntero 873
Punteros a estructuras 875Punteros a constantes y punteros constantes 877
Punteros y paso de parámetros 879Punteros y arrays 883Memoria y datos del programa 886Memoria dinámica 891Punteros y datos dinámicos 895Gestión de la memoria 907Errores comunes 911Arrays de datos dinámicos 916Arrays dinámicos 928
Luis Hernández Yáñez
Página 849Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
LosdatosenlamemoriaTododatosealmacenaenmemoria:
Variosbytesapartirdeunadirección
int i = 5;
Eldato(i)seaccedeapartirdesudirecciónbase (0F03:1A38)
DireccióndelaprimeraceldadememoriautilizadaporeldatoEltipodeldato(int)indicacuántosbytes(4)requiereeldato:
00000000 00000000 00000000 00000101 5(Lacodificacióndelosdatospuedeserdiferente;yladelasdireccionestambién)
Página 850Fundamentos de la programación: Punteros y memoria dinámica
0F03:1A37 ...
i 0F03:1A38 00000000
0F03:1A39 00000000
0F03:1A3A 00000000
0F03:1A3B 00000101
0F03:1A3C ...
DirecciónbaseDirecciónbase
Luis Hernández Yáñez
LospunteroscontienendireccionesdememoriaUnpuntero sirveparaaccederatravésdeélaotrodato
Elvalordelpunteroesladireccióndememoriabasedeotrodato
Página 851Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
...
punt 0F07:0417 0F
0F07:0418 03
0F07:0419 1A
0F07:041A 38
...
Indirección:AccesoindirectoaundatoIndirección:Accesoindirectoaundato
puntpunt
5ii
punt apunta aipunt apunta ai
¿Dequétipoeseldatoapuntado?¿Cuántasceldasocupa?¿Cómoseinterpretanlos0/1?
¿Dequétipoeseldatoapuntado?¿Cuántasceldasocupa?¿Cómoseinterpretanlos0/1?
Luis Hernández Yáñez
Lospunteroscontienendireccionesdememoria¿Dequétipoeseldatoapuntado?
Lavariablealaqueapuntaunpunteroserádeuntipoconcreto
¿Cuántoocupa?¿Cómoseinterpreta?
Eltipodevariableapuntadoseestablecealdeclararelpuntero:tipo *nombre;
Elpunteronombre apuntaráaunavariabledeltipo indicado
Elasterisco(*)indicaqueesunpunteroadatosdeesetipoint *punt; // punt inicialmente contiene una dirección
// que no es válida (no apunta a nada)
Elpunteropunt apuntaráaunavariableentera(int)int i; // Dato entero vs. int *punt; // Puntero a entero
Página 852Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
LospunteroscontienendireccionesdememoriaLasvariablespunterotampocoseinicializanautomáticamente
Aldeclararlassininicializadorcontienendireccionesnoválidasint *punt; // punt inicialmente contiene una dirección
// que no es válida (no apunta a nada)
Unpunteropuedeapuntaracualquierdatodesutipobase
Unpunteronotieneporquéapuntarnecesariamenteaundato(puedenoapuntaranada:valorNULL)
¿Paraquésirvenlospunteros?
Paraimplementarelpasodeparámetrosporreferencia
Paramanejardatosdinámicos(Datosquesecreanydestruyendurantelaejecución)
Paraimplementarlosarrays
Página 853Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 854Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Obtenerladireccióndememoriade...Operadormonarioyprefijo& devuelveladireccióndememoriabasedeldatoalqueprecedeint i;
cout << &i; // Muestra la dirección de memoria de i
Unpunteropuederecibirladireccióndedatosdesutipobase
int i;
int *punt;
punt = &i; // punt contiene la dirección de i
Ahorapunt yacontieneunadireccióndememoriaválida
punt apunta a(contieneladirecciónde)lavariablei (int)
Página 855Fundamentos de la programación: Punteros y memoria dinámica
&&
puntpunt
ii
Luis Hernández Yáñez
Obtenerladireccióndememoriade...
int i, j;
...
int *punt;
Página 856Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38
0F03:1A39
0F03:1A3A
0F03:1A3B
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417
0F07:0418
0F07:0419
0F07:041A
...
&&
Luis Hernández Yáñez
Obtenerladireccióndememoriade...
int i, j;
...
int *punt;
...
i = 5;
Página 857Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417
0F07:0418
0F07:0419
0F07:041A
...
&&
5ii
Luis Hernández Yáñez
Obtenerladireccióndememoriade...
int i, j;
...
int *punt;
...
i = 5;
punt = &i;
Página 858Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417 0F
0F07:0418 03
0F07:0419 1A
0F07:041A 38
...
&&
puntpunt
5ii
Luis Hernández Yáñez
Obtenerloquehayenladirección...Operadormonarioyprefijo* accedealoquehayenladireccióndememoriaalaqueprecede
Permiteaccederaundatoatravésunpunteroqueloapunte:punt = &i;
cout << *punt; // Muestra lo que hay en la dirección punt
*punt:loquehayenladirecciónquecontieneelpunteropunt
punt contieneladireccióndememoriadelavariablei
*punt accedealcontenidodeesavariablei
Accesoindirectoalvalordei
Página 859Fundamentos de la programación: Punteros y memoria dinámica
**Luis Hernández Yáñez
Obtenerloquehayenladirección...
int i, j;
...
int *punt;
...
i = 5;
punt = &i;
j = *punt;
Página 860Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417 0F
0F07:0418 03
0F07:0419 1A
0F07:041A 38
...
0F0F
0303
1A1A
3838punt:punt:
**
Luis Hernández Yáñez
Obtenerloquehayenladirección...
int i, j;
...
int *punt;
...
i = 5;
punt = &i;
j = *punt;
Página 861Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417 0F
0F07:0418 03
0F07:0419 1A
0F07:041A 38
...
0000
0000
0000
0505
*punt:*punt:
**
Direccionamientoindirecto
(indirección)Se accede al dato ide forma indirecta
Direccionamientoindirecto
(indirección)Se accede al dato ide forma indirecta
Luis Hernández Yáñez
Obtenerloquehayenladirección...
int i, j;
...
int *punt;
...
i = 5;
punt = &i;
j = *punt;
Página 862Fundamentos de la programación: Punteros y memoria dinámica
...
i 0F03:1A38 00
0F03:1A39 00
0F03:1A3A 00
0F03:1A3B 05
j 0F03:1A3C
0F03:1A3D
0F03:1A3E
0F03:1A3F
...
punt 0F07:0417 0F
0F07:0418 03
0F07:0419 1A
0F07:041A 38
...
0000
0000
0000
0505
**
Luis Hernández Yáñez
Ejemplodeusodepunteros#include <iostream>using namespace std;
int main() {int i = 5;int j = 13;int *punt;punt = &i;cout << *punt << endl; // Muestra el valor de ipunt = &j;cout << *punt << endl; // Ahora muestra el valor de jint *otro = &i;cout << *otro + *punt << endl; // i + jint k = *punt;cout << k << endl; // Mismo valor que j
return 0;}
Página 863Fundamentos de la programación: Punteros y memoria dinámica
punteros.cpppunteros.cppLuis Hernández Yáñez
Página 864Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
TodopunterohadetenerunadirecciónválidaUnpunterosólodebeserutilizadositieneunadirecciónválida
UnpunteroNOcontieneunadirecciónválidatrasserdefinido
Unpunteroobtieneunadirecciónválida: Asignandoladireccióndeotrodato(operador&)
Asignandootropuntero(mismotipobase)queyaseaválido AsignandoelvalorNULL (punteronulo,noapuntaanada)
int i;
int *q; // q no tiene aún una dirección válida
int *p = &i; // p toma una dirección válida
q = p; // ahora q ya tiene una dirección válida
q = NULL; // otra dirección válida para q
Página 865Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Punterosqueapuntanasaberqué...Unpunteronoinicializadocontieneunadireccióndesconocidaint *punt; // No inicializado*punt = 12; // ¿A qué dato se está asignando el valor?
¿Direccióndelazonadedatosdelprograma?
¡Podemosmodificarinadvertidamenteundatodelprograma!
¿Direccióndelazonadecódigodelprograma?
¡Podemosmodificarelcódigodelpropioprograma!
¿Direccióndelazonadecódigodelsistemaoperativo?
¡PodemosmodificarelcódigodelpropioS.O.!
Consecuenciasimprevisibles(cuelgue)
(LosS.O.modernosprotegenbienlamemoria)
Página 866Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
PunterosquenoapuntananadaInicializandolospunterosaNULL podemosdetectarerrores:int *punt = NULL;...*punt = 13;
punt hasidoinicializadoaNULL:¡Noapuntaanada!
Sinoapuntaanada,¿¿¿quésignifica*punt???Notienesentido
ERROR:¡Accesoaundatoatravésdeunpunteronulo!
Errordeejecución,loqueciertamentenoesbueno
Perosabemoscuálhasidoelproblema,loqueesmucho
Sabemosdóndeyquébuscarparadepurar
Página 867Fundamentos de la programación: Punteros y memoria dinámica
Xpuntpunt
Luis Hernández Yáñez
Página 868Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
ApuntandoalmismodatoAlcopiarunpunteroenotro,ambosapuntaránalmismodato:
int x = 5;
int *punt1 = NULL; // punt1 no apunta a nada
int *punt2 = &x; // punt2 apunta a la variable x
Página 869Fundamentos de la programación: Punteros y memoria dinámica
Xpunt1punt1 punt2punt2
5xx
Luis Hernández Yáñez
ApuntandoalmismodatoAlcopiarunpunteroenotro,ambosapuntaránalmismodato:
int x = 5;
int *punt1 = NULL; // punt1 no apunta a nada
int *punt2 = &x; // punt2 apunta a la variable x
punt1 = punt2; // ambos apuntan a la variable x
Página 870Fundamentos de la programación: Punteros y memoria dinámica
punt1punt1 punt2punt2
5xx
Luis Hernández Yáñez
5xx
ApuntandoalmismodatoAlcopiarunpunteroenotro,ambosapuntaránalmismodato:
int x = 5;
int *punt1 = NULL; // punt1 no apunta a nada
int *punt2 = &x; // punt2 apunta a la variable x
punt1 = punt2; // ambos apuntan a la variable x
*punt1 = 8;
Página 871Fundamentos de la programación: Punteros y memoria dinámica
Aldatox ahorasepuedeaccederdetresformas:
x *punt1 *punt2
Aldatox ahorasepuedeaccederdetresformas:
x *punt1 *punt2
punt1punt1 punt2punt2
8
Luis Hernández Yáñez
¿Apuntanalmismodato?Operadoresrelacionales== y!=:int x = 5;int *punt1 = NULL;int *punt2 = &x;...if (punt1 == punt2) {
cout << "Apuntan al mismo dato" << endl;}else {
cout << "No apuntan al mismo dato" << endl;}
Página 872Fundamentos de la programación: Punteros y memoria dinámica
SólosepuedencompararpunterosconelmismotipobaseSólosepuedencompararpunterosconelmismotipobase
Luis Hernández Yáñez
Página 873Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
DeclaracióndetipospunteroDeclaramostiposparalospunteroscondistintostiposbase:typedef int *tIntPtr;typedef char *tCharPtr;typedef double *tDoublePtr;int entero = 5;tIntPtr puntI = &entero;char caracter = 'C';tCharPtr puntC = &caracter;double real = 5.23;tDoublePtr puntD = ℜcout << *puntI << " " << *puntC << " " << *puntD << endl;
Con*puntero podemoshacerloqueconotrosdatosdeltipobase
Página 874Fundamentos de la programación: Punteros y memoria dinámica
tipos.cpptipos.cpp
Luis Hernández Yáñez
AccesoaestructurasatravésdepunterosLospunterospuedenapuntartambiénaestructuras:typedef struct {
int codigo;string nombre;double sueldo;
} tRegistro;tRegistro registro;typedef tRegistro *tRegistroPtr;tRegistroPtr puntero = ®istro;
Operadorflecha(‐>):
Accesoaloscamposatravésdeunpunterosinusareloperador*puntero‐>codigo puntero‐>nombre puntero‐>sueldo
puntero‐>... (*puntero)....
Página 875Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Accesoaestructurasatravésdepunterostypedef struct {
int codigo;string nombre;double sueldo;
} tRegistro;tRegistro registro;typedef tRegistro *tRegistroPtr;tRegistroPtr puntero = ®istro;registro.codigo = 12345;registro.nombre = "Javier";registro.sueldo = 95000;cout << puntero‐>codigo << " " << puntero‐>nombre
<< " " << puntero‐>sueldo << endl;
puntero‐>codigo (*puntero).codigo *puntero.codigo
Página 876Fundamentos de la programación: Punteros y memoria dinámica
structPtr.cppstructPtr.cpp
puntero seríaunaestructuraconcampocodigo detipopunteropuntero seríaunaestructuraconcampocodigo detipopuntero
Luis Hernández Yáñez
PunterosaconstantesypunterosconstantesElefectodelmodificadordeaccesoconst dependedesusitio:
const tipo *puntero; Punteroaunaconstante
tipo *const puntero; Punteroconstante
Punterosaconstantes:typedef const int *tIntCtePtr; // Puntero a constante
int entero1 = 5, entero2 = 13;
tIntCtePtr punt_a_cte = &entero1;
(*punt_a_cte)++; // ERROR: ¡Dato no modificable!
punt_a_cte = &entero2; // OK: El puntero no es cte.
Página 877Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
PunterosaconstantesypunterosconstantesElefectodelmodificadordeaccesoconst dependedesusitio:
const tipo *puntero; Punteroaunaconstante
tipo *const puntero; Punteroconstante
Punterosconstantes:typedef int *const tIntPtrCte; // Puntero constante
int entero1 = 5, entero2 = 13;
tIntPtrCte punt_cte = &entero1;
(*punt_cte)++; // OK: El puntero no apunta a cte.
punt_cte = &entero2; // ERROR: ¡Puntero constante!
Página 878Fundamentos de la programación: Punteros y memoria dinámica
constPtr.cppconstPtr.cpp
Luis Hernández Yáñez
Página 879Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
PasodeparámetrosporreferenciaovariableEnellenguajeCnohaymecanismodepasoporreferencia(&)
Sólosepuedenpasarparámetrosporvalor
¿Cómosesimulaelpasoporreferencia?Pormediodepunteros:
void incrementa(int *punt);
void incrementa(int *punt) {(*punt)++;
}...int entero = 5;incrementa(&entero);cout << entero << endl;
Mostrará6 enlaconsola
Página 880Fundamentos de la programación: Punteros y memoria dinámica
Pasoporvalor:Elargumento(elpuntero)nocambia
Aquelloaloqueapunta(elentero)SÍpuedecambiar
Pasoporvalor:Elargumento(elpuntero)nocambia
Aquelloaloqueapunta(elentero)SÍpuedecambiar
param.cppparam.cpp
Luis Hernández Yáñez
Pasodeparámetrosporreferenciaovariableint entero = 5;incrementa(&entero);
Página 881Fundamentos de la programación: Punteros y memoria dinámica
5enteroentero
puntpunt
6enteroentero
punt recibeladireccióndeenteropunt recibeladireccióndeentero
6enteroentero
void incrementa(int *punt) {(*punt)++;
}
cout << entero << endl;
Luis Hernández Yáñez
Pasodeparámetrosporreferenciaovariable¿CuáleselequivalenteenCaesteprototipodeC++?void foo(int ¶m1, double ¶m2, char ¶m3);
Prototipoequivalente:
void foo(int *param1, double *param2, char *param3);
void foo(int *param1, double *param2, char *param3) {// Al primer argumento se accede con *param1// Al segundo argumento se accede con *param2// Al tercer argumento se accede con *param3
}
¿Cómosellamaría?int entero; double real; char caracter;//...foo(&entero, &real, &caracter);
Página 882Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 883Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
UnaíntimarelaciónVariablearray Punteroalprimerelementodelarray
Así,sitenemos:int dias[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Entonces:cout << *dias << endl;
Muestra31 enlaconsola,elprimerelementodelarray
Siempreapuntaalprimerelemento(nosepuedemodificar)
Accesoaloselementosdelarray:
Poríndiceoconaritméticadepunteros(Anexo)
Página 884Fundamentos de la programación: Punteros y memoria dinámica
¡Unnombredearrayesunpunteroconstante!¡Unnombredearrayesunpunteroconstante!
Luis Hernández Yáñez
Pasodearraysasubprogramas¡Estoexplicaporquénousamos&conlosparámetrosarray!
Elnombredelarrayesunpuntero:yaesunpasoporreferencia
Prototiposequivalentesparaparámetrosarray:const int N = ...;void cuadrado(int arr[N]);void cuadrado(int arr[], int size); // Array no delimitadovoid cuadrado(int *arr, int size); // Puntero
Arraysnodelimitadosypunteros:senecesitaladimensión
Elementos:seaccedenconíndice(arr[i])oconpuntero(*arr)
Unafunciónsólopuededevolverunarrayenformadepuntero:intPtr inicializar();
Página 885Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 886Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 887Fundamentos de la programación: Punteros y memoria dinámica
RegionesdelamemoriaElsistemaoperativodistinguevariasregionesenlamemoria:
Pila (Stack)
Montón (Heap)
Datos globales
Código del programa
S.O.
DatoslocalesDatoslocales
DatosdinámicosDatosdinámicos
MemoriaprincipalMemoriaprincipal
Luis Hernández Yáñez
Página 888Fundamentos de la programación: Punteros y memoria dinámica
MemoriaprincipalDatosglobalesdelprograma:Declaradosfueradelossubprogramas
typedef struct {...
} tRegistro;const int N = 1000;typedef tRegistro tArray[N];typedef struct {
tArray registros;int cont;
} tLista;
int main() {...
Pila
Montón
Datos globales
Código del programa
S.O.
DatoslocalesDatoslocales
DatosdinámicosDatosdinámicos
MemoriaprincipalMemoriaprincipal
Luis Hernández Yáñez
Página 889Fundamentos de la programación: Punteros y memoria dinámica
Lapila(stack)Datoslocalesdesubprogramas:Parámetrosporvaloryvariableslocales
void func(tLista lista, double &total){tLista aux;int i;...
Ylospunterostemporalesqueapuntanalosargumentosdelosparámetrosporreferencia
Pila
Montón
Datos globales
Código del programa
S.O.
DatoslocalesDatoslocales
DatosdinámicosDatosdinámicos
MemoriaprincipalMemoriaprincipal
func(lista, resultado)
&resultado
Luis Hernández Yáñez
Página 890Fundamentos de la programación: Punteros y memoria dinámica
Elmontón(heap)Datosdinámicos
Datosquesecreanysedestruyendurantelaejecucióndelprograma,amedidaquesenecesita
Sistemadegestióndememoriadinámica(SGMD)
Cuandosenecesitamemoriaparaunavariablesesolicita
ElSGMD reservaespacioydevuelveladirecciónbase
Cuandoyanosenecesitamáslavariable,sedestruye
SeliberalamemoriayelSGMD cuentadenuevoconella
Pila
Montón
Datos globales
Código del programa
S.O.
DatoslocalesDatoslocales
DatosdinámicosDatosdinámicos
MemoriaprincipalMemoriaprincipal
Luis Hernández Yáñez
Página 891Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 892Fundamentos de la programación: Punteros y memoria dinámica
DatosdinámicosSecreanysedestruyendurantelaejecucióndelprograma
Selesasignamemoriadelmontón
¿Porquéutilizarmemoriadinámica?
Almacéndememoriamuygrande:datosolistasdedatosquenocabenenmemoriaprincipalpuedencaberenelmontón
Elprogramaajustaelusodelamemoriaalasnecesidadesdecadamomento:nilefaltaniladesperdicia
CreaciónCreación
DestrucciónDestrucción
MontónDato dinámicoDato dinámico
Luis Hernández Yáñez
Página 893Fundamentos de la programación: Punteros y memoria dinámica
¿Cuándoseasignamemoriaalosdatos?
Datosglobales
Enmemoriaprincipalalcomenzarlaejecucióndelprograma
Existendurantetodalaejecucióndelprograma
Datoslocales deunsubprograma
Enlapilaalejecutarseelsubprograma
Existensólodurantelaejecucióndesusubprograma
Datosdinámicos
Enelmontóncuandoelprogramalosolicita
Existenavoluntad delprograma
Luis Hernández Yáñez
Página 894Fundamentos de la programación: Punteros y memoria dinámica
Datosestáticos Datosdeclaradoscomodeuntipoconcreto:
int i;
Seaccedendirectamenteatravésdelidentificador:cout << i;
Datosdinámicos Datosaccedidosatravésdesudireccióndememoria
Esadireccióndememoriadebeestarelalgúnpuntero
LospunterossonlabasedelSGMD
Losdatosestáticostambiénsepuedenaccederatravésdepunterosint *p = &i;
Luis Hernández Yáñez
Página 895Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 896Fundamentos de la programación: Punteros y memoria dinámica
Eloperadornewnew tipo Reservamemoriadelmontónparaunavariabledel
tipo ydevuelvelaprimeradireccióndememoriautilizada,quedebeserasignadaaunpuntero
int *p; // Todavía sin una dirección válidap = new int; // Ya tiene una dirección válida*p = 12;
Lavariabledinámicaseaccedeexclusivamenteporpunteros
Notieneidentificadorasociadoint i; // i es una variable estáticaint *p1, *p2;p1 = &i; // Puntero que da acceso a la variable
// estática i (accesible con i o con *p1)p2 = new int; // Puntero que da acceso a una variable
// dinámica (accesible sólo a través de p2)
DevuelveNULL sinoquedamemoriasuficienteDevuelveNULL sinoquedamemoriasuficiente
Luis Hernández Yáñez
Página 897Fundamentos de la programación: Punteros y memoria dinámica
InicializaciónconeloperadornewEloperadornew admiteunvalorinicialparaeldatocreado:int *p;p = new int(12);
Secrealavariable,detipoint,yseinicializaconelvalor12#include <iostream>using namespace std;#include "registro.h"
int main() {tRegistro reg;reg = nuevo();tRegistro *punt = new tRegistro(reg);mostrar(*punt);...
registros.cppregistros.cppLuis Hernández Yáñez
Página 898Fundamentos de la programación: Punteros y memoria dinámica
Eloperadordeletedelete puntero; Devuelvealmontónlamemoriausadapor
lavariabledinámicaapuntadaporpunteroint *p;p = new int;*p = 12;...delete p; // Ya no se necesita el entero apuntado por p
¡Elpunterodejadecontenerunadirecciónválida!¡Elpunterodejadecontenerunadirecciónválida!
Luis Hernández Yáñez
Montón(heap)Montón(heap)
Página 899Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;p3 = new double;*p3 = 123.45;cout << *p1 << endl;cout << *p2 << endl;cout << *p3 << endl;delete p2;delete p3;
return 0;}
dinamicas.cppdinamicas.cpp
1.5aa
p1p1
p2p2
p3p3
Identificadores:
4(a,p1,p2,p3)
Variables:
6(+*p2 y*p3)
Identificadores:
4(a,p1,p2,p3)
Variables:
6(+*p2 y*p3)
1.51.5
123.45123.45
Luis Hernández Yáñez
Página 900Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;
PILA
a 1.5
p1 ?
p2 ?
p3 ?
MONTÓN
Luis Hernández Yáñez
Página 901Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;
PILA
a 1.5
p1
p2 ?
p3 ?
MONTÓN
Luis Hernández Yáñez
Página 902Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;
PILA
a 1.5
p1
p2
p3 ?
MONTÓN
Luis Hernández Yáñez
Página 903Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;
PILA
a 1.5
p1
p2
p3 ?
1.5
MONTÓN
Luis Hernández Yáñez
Página 904Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;p3 = new double;
PILA
a 1.5
p1
p2
p3
1.5
MONTÓN
Luis Hernández Yáñez
Página 905Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;p3 = new double;*p3 = 123.45;
PILA
a 1.5
p1
p2
p3
123.45
1.5
MONTÓN
Luis Hernández Yáñez
Página 906Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;p3 = new double;*p3 = 123.45;cout << *p1 << endl;cout << *p2 << endl;cout << *p3 << endl;delete p2;
PILA
a 1.5
p1
p2 ?
p3
123.45
MONTÓN
Luis Hernández Yáñez
Página 907Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;
int main() {double a = 1.5;double *p1, *p2, *p3;p1 = &a;p2 = new double;*p2 = *p1;p3 = new double;*p3 = 123.45;cout << *p1 << endl;cout << *p2 << endl;cout << *p3 << endl;delete p2;delete p3;
PILA
a 1.5
p1
p2 ?
p3 ?
MONTÓN
Luis Hernández Yáñez
Página 908Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 909Fundamentos de la programación: Punteros y memoria dinámica
Lamemoriasereparteentrelapilayelmontón
Crecenendireccionesopuestas
Alllamarasubprogramaslapilacrece
Alcreardatosdinámicoselmontóncrece
Colisiónpila‐montón
Loslímitesdeambasregionesseencuentran
Seagotalamemoria
Desbordamientodelapila
Lapilasueleteneruntamañomáximoestablecido
Sisesobrepasaseagotalapila
Pila
Montón
Luis Hernández Yáñez
Página 910Fundamentos de la programación: Punteros y memoria dinámica
GestióndelmontónSistemadeGestióndeMemoriaDinámica(SGMD)
Gestionalaasignacióndememoriaalosdatosdinámicos
Localizaseccionesadecuadasysiguelapistadelodisponible
Nodisponedeunrecolectordebasura,comoellenguajeJava
¡Hayquedevolvertodalamemoriasolicitada!Debenejecutarsetantosdelete comonew sehayanejecutado
Lamemoriadisponibleenelmontóndebeserexactamentelamismaantesydespuésdelaejecucióndelprograma
Ytododatodinámicodebeteneralgúnacceso(puntero)
Esungraveerrorperder undatoenelmontón
Luis Hernández Yáñez
Página 911Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 912Fundamentos de la programación: Punteros y memoria dinámica
Olvidodedestruccióndeundatodinámico...int main() {
tRegistro *p;p = new tRegistro;*p = nuevo();mostrar(*p);
return 0;}
G++noindicaráningúnerroryelprogramapareceráterminarcorrectamente,perodejarámemoriadesperdiciada
VisualC++sícompruebaelusodelamemoriadinámicaynosavisasidejamosmemoriasinliberar
Faltadelete p;Faltadelete p;
Luis Hernández Yáñez
Página 913Fundamentos de la programación: Punteros y memoria dinámica
Intentodedestruccióndeundatoinexistente...int main() {
tRegistro *p1 = new tRegistro;*p1 = nuevo();mostrar(*p1);tRegistro *p2;p2 = p1;mostrar(*p2);delete p1;delete p2;
return 0;}
p1p1 tRegistro
p2p2
SólosehacreadounavariableSólosehacreadounavariable
Luis Hernández Yáñez
¡Perdido!
Página 914Fundamentos de la programación: Punteros y memoria dinámica
Pérdidadeundatodinámico...int main() {
tRegistro *p1, *p2;p1 = new tRegistro(nuevo());p2 = new tRegistro(nuevo());
mostrar(*p1);p1 = p2;mostrar(*p1);
delete p1;delete p2;
return 0;}
p2p2 tRegistro
p1p1 tRegistro
SepierdeundatoenelmontónSeintentaeliminarundatoyaeliminadoSepierdeundatoenelmontónSeintentaeliminarundatoyaeliminado
Luis Hernández Yáñez
Página 915Fundamentos de la programación: Punteros y memoria dinámica
Intentodeaccesoaundatotrassueliminación...int main() {
tRegistro *p;p = new tRegistro(nuevo());
mostrar(*p);delete p;...mostrar(*p);
return 0;}
p hadejadodeapuntaraldatodinámicodestruido Accesoamemoriainexistente
p hadejadodeapuntaraldatodinámicodestruido Accesoamemoriainexistente
Luis Hernández Yáñez
Página 916Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 917Fundamentos de la programación: Punteros y memoria dinámica
Arraysdepunterosadatosdinámicostypedef struct {
int codigo;string nombre;double valor;
} tRegistro;typedef tRegistro *tRegPtr;
const int N = 1000;// Array de punteros a registros:typedef tRegPtr tArray[N];typedef struct {
tArray registros;int cont;
} tLista;
Lospunterosocupanmuypocoenmemoria
Losdatosalosqueapuntenestaránenelmontón
Lospunterosocupanmuypocoenmemoria
Losdatosalosqueapuntenestaránenelmontón
Secreanamedidaqueseinsertan
Sedestruyenamedidaqueseeliminan
Secreanamedidaqueseinsertan
Sedestruyenamedidaqueseeliminan
Luis Hernández Yáñez
Página 918Fundamentos de la programación: Punteros y memoria dinámica
tLista lista;lista.cont = 0;
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
0lista.contlista.cont
Luis Hernández Yáñez
Página 919Fundamentos de la programación: Punteros y memoria dinámica
tLista lista;lista.cont = 0;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
1lista.contlista.cont
Luis Hernández Yáñez
Página 920Fundamentos de la programación: Punteros y memoria dinámica
tLista lista;lista.cont = 0;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
2lista.contlista.cont
Luis Hernández Yáñez
Página 921Fundamentos de la programación: Punteros y memoria dinámica
tLista lista;lista.cont = 0;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;lista.registros[lista.cont] = new tRegistro(nuevo());lista.cont++;
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
3lista.contlista.cont
Luis Hernández Yáñez
Página 922Fundamentos de la programación: Punteros y memoria dinámica
Losregistrosseaccedenatravésdelospunteros(operador‐>):cout << lista.registros[0]‐>nombre;
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
3lista.contlista.cont
Luis Hernández Yáñez
Página 923Fundamentos de la programación: Punteros y memoria dinámica
Nohayqueolvidarsededevolverlamemoriaalmontón:for (int i = 0; i < lista.cont; i++) {
delete lista.registros[i];}
0 1 2 3 4 5 6 998 999
lista.registroslista.registros
3lista.contlista.cont
Luis Hernández Yáñez
Página 924Fundamentos de la programación: Punteros y memoria dinámica
#ifndef lista_h#define lista_h#include "registro.h"
const int N = 1000;const string BD = "bd.dat";typedef tRegPtr tArray[N];typedef struct {
tArray registros;int cont;
} tLista;
void mostrar(const tLista &lista);void insertar(tLista &lista, tRegistro registro, bool &ok);void eliminar(tLista &lista, int code, bool &ok);int buscar(const tLista &lista, int code);void cargar(tLista &lista, bool &ok);void guardar(const tLista &lista);void destruir(tLista &lista);
#endif
lista.hlista.h
registro.h coneltipopuntero:
typedef tRegistro *tRegPtr;
Luis Hernández Yáñez
Página 925Fundamentos de la programación: Punteros y memoria dinámica
void insertar(tLista &lista, tRegistro registro, bool &ok) {ok = true;if (lista.cont == N) {
ok = false;}else {
lista.registros[lista.cont] = new tRegistro(registro);lista.cont++;
}}
void eliminar(tLista &lista, int code, bool &ok) {ok = true;int ind = buscar(lista, code);if (ind == ‐1) {
ok = false;}else {
delete lista.registros[ind];for (int i = ind + 1; i < lista.cont; i++) {
lista.registros[i ‐ 1] = lista.registros[i];}lista.cont‐‐;
}}
lista.cpplista.cppLuis Hernández Yáñez
Página 926Fundamentos de la programación: Punteros y memoria dinámica
int buscar(const tLista &lista, int code) {// Devuelve el índice o ‐1 si no se ha encontrado
int ind = 0;bool encontrado = false;while ((ind < lista.cont) && !encontrado) {
if (lista.registros[ind]‐>codigo == code) {encontrado = true;
}else {
ind++;}
if (!encontrado) {ind = ‐1;
}return ind;
}
void destruir(tLista &lista) {for (int i = 0; i < lista.cont; i++) {
delete lista.registros[i];}lista.cont = 0;
}...
Luis Hernández Yáñez
Página 927Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;#include "registro.h"#include "lista.h"
int main() {tLista lista;bool ok;cargar(lista, ok);if (ok) {
mostrar(lista);destruir(lista);
}
return 0;}
listadinamica.cpplistadinamica.cppLuis Hernández Yáñez
Página 928Fundamentos de la programación: Punteros y memoria dinámica
Luis Hernández Yáñez
Página 929Fundamentos de la programación: Punteros y memoria dinámica
CreaciónydestruccióndearraysdinámicosArraydinámico:arrayqueseubicaenlamemoriadinámica
Creacióndeunarraydinámico:tipo *puntero = new tipo[dimensión];
int *p = new int[10];
Creaunarrayde10int enmemoriadinámica
Loselementosseaccedenatravésdelpuntero:p[i]
Destruccióndelarray:delete [] p;
Luis Hernández Yáñez
Página 930Fundamentos de la programación: Punteros y memoria dinámica
#include <iostream>using namespace std;const int N = 10;
int main() {int *p = new int[N];for (int i = 0; i < N; i++) {
p[i] = i;}for (int i = 0; i < N; i++) {
cout << p[i] << endl;}delete [] p;
return 0;}
¡Noolvidesdestruirelarraydinámico!¡Noolvidesdestruirelarraydinámico!
Luis Hernández Yáñez
Página 931Fundamentos de la programación: Punteros y memoria dinámica
...#include "registro.h"
const int N = 1000;
// Lista: array dinámico (puntero) y contadortypedef struct {
tRegPtr registros;int cont;
} tLista;
...
listaAD.hlistaAD.hLuis Hernández Yáñez
Página 932Fundamentos de la programación: Punteros y memoria dinámica
void insertar(tLista &lista, tRegistro registro, bool &ok) {ok = true;if (lista.cont == N) {
ok = false;}else {
lista.registros[lista.cont] = registro;lista.cont++;
}}
void eliminar(tLista &lista, int code, bool &ok) {ok = true;int ind = buscar(lista, code);if (ind == ‐1) {
ok = false;}else {
for (int i = ind + 1; i < lista.cont; i++) {lista.registros[i ‐ 1] = lista.registros[i];
}lista.cont‐‐;
}} ...
listaAD.cpplistaAD.cpp
Nousamosnew
Sehancreadotodoelarrayalcargar
Nousamosnew
Sehancreadotodoelarrayalcargar
Nousamosdelete
Sedestruyetodoelarrayalfinal
Nousamosdelete
Sedestruyetodoelarrayalfinal
Luis Hernández Yáñez
Página 933Fundamentos de la programación: Punteros y memoria dinámica
int buscar(tLista lista, int code) {int ind = 0;bool encontrado = false;while ((ind < lista.cont) && !encontrado) {
if (lista.registros[ind].codigo == code) {encontrado = true;
}else {
ind++;}
}if (!encontrado) {
ind = ‐1;}return ind;
}
void destruir(tLista &lista) {delete [] lista.registros;lista.cont = 0;
}...
Luis Hernández Yáñez
Página 934Fundamentos de la programación: Punteros y memoria dinámica
void cargar(tLista &lista, bool &ok) {ifstream archivo;char aux;ok = true;archivo.open(BD.c_str());if (!archivo.is_open()) {
ok = false;}else {
tRegistro registro;lista.cont = 0;lista.registros = new tRegistro[N];archivo >> registro.codigo;while ((registro.codigo != ‐1) && (lista.cont < N)) {
archivo >> registro.valor;archivo.get(aux); // Saltamos el espaciogetline(archivo, registro.nombre);lista.registros[lista.cont] = registro;lista.cont++;archivo >> registro.codigo;
}archivo.close();
}}
SecreantodosalavezSecreantodosalavez
Luis Hernández Yáñez
Página 935Fundamentos de la programación: Punteros y memoria dinámica
MismoprogramaprincipalqueeldelarraydedatosdinámicosPeroincluyendolistaAD.h,enlugardelista.h
ejemploAD.cppejemploAD.cppLuis Hernández Yáñez
Página 936Fundamentos de la programación: Punteros y memoria dinámica
Arraydedatosdinámicos:Arraydepunterosadatosdinámicos
Arraydinámico:Punteroaarrayenmemoriadinámica
Montón
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7
Arraydedatosdinámicos:Arraydepunteros
Arraydedatosdinámicos:Arraydepunteros
Arraydinámico:PunteroaarrayArraydinámico:Punteroaarray
Luis Hernández Yáñez
LicenciaCC(Creative Commons)Estetipodelicenciasofrecenalgunosderechosaterceraspersonasbajociertascondiciones.
Estedocumentotieneestablecidaslassiguientes:
Pulsaenlaimagendearribaaladerechaparasabermás.
Fundamentos de la programación: Punteros y memoria dinámica Página 937
Reconocimiento(Attribution):Encualquierexplotacióndelaobraautorizadaporlalicenciaharáfaltareconocerlaautoría.
Nocomercial(Noncommercial):Laexplotacióndelaobraquedalimitadaausosnocomerciales.
Compartirigual(Sharealike):Laexplotaciónautorizadaincluyelacreacióndeobrasderivadassiemprequemantenganlamismalicenciaalserdivulgadas.