Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
1
Punteros y Memoria Dinámica I
Curso INEM. Programación en C++ Santiago Muelas Pascual
Memoria
! Lugar donde almacenan los datos y las instrucciones
! Compuesta de un gran número de bytes
! Cada byte puede almacenar un valor representado por 8 cifras binarias (bits)
! A cada byte se le asigna un número de identificación
! Dirección de memoria
! Referencia para acceder a un byte
Dirección Contenido
0 00100000
1 00000001
2 10001000
…
54 00100100
Memoria
! ¿Qué necesita el compilador para generar el código para acceder a una variable?
• La dirección de memoria del byte inicial de la variable
• El número de bytes que componen la variable
Memoria
! ¿De dónde obtiene la dirección inicial? ! La dirección del byte inicial la obtiene a través del nombre de la
variable ! Sustituirá el nombre por la dirección inicial dentro del programa final
! ¿Y el número de bytes? ! El número de bytes viene definido por el tipo de la variable (char -
> 1, int -> 4, …) ! El compilador se encarga de reservar para dicha variable el número de
bytes que indique su tipo
2
Punteros
! Nuevo tipo básico de variables
! También almacenan información pero distinta
! El resto de los tipos almacenan datos relativos al cálculo del programa
! Los punteros almacenan direcciones de memoria
! El tamaño en bytes viene dado por el tamaño de la direcciones que utilice el computador
! Actualmente 4(32bits) o 8(64 bits)
Punteros
! Un puntero apunta a un dato
! Del cual tiene que conocer su tamaño (tipo)
! Para acceder a memoria hay que conocer lo que ocupa ! ¡Cuando se define una variable hay que especificar su tipo!
Definición
tipo *variable;
Ej int *a;
¡OJO!
Ej int *a,b; ! a es un puntero a un entero, b es un entero���
Operadores
! Operador de dirección: & ! Para poder obtener la dirección de una variable ! Para poder almacenar la direccion hará falta una
variable puntero con el mismo tipo ! No confundir con el paso por referencia (misma
sintáxis)
! Operador de indirección: * ! Para de acceder al dato almacenado en una dirección ! Realiza la función opuesta del operador & ! Sólo se debe utilizar con punteros
3
Ejemplo
Dirección
px-> 35: y -> 39:
Contenido Gráfica
? ? ? ? 0 0 0 3
? px
3 y
px-> 35: y -> 39:
0 0 0 39 0 0 0 3
39
3 y
px
px-> 35: y -> 39:
0 0 0 39 0 0 0 5
39
5 y
px
int main() {
}
int *px,y=3; px=&y;
*px=5;
/* px apunta a y */
/* y vale 5 */
Precendencia ( ) [ ] . -> ++ -- (post)
!sizeof, ++ -- (pre) &(dirección) *(indirección)
* / %
+ -
<< >>
< <= > >=
== !=
&
^
|
&&
||
= += -= *= /= %=
? :
Conversión de punteros
! Todos los punteros son direcciones de memoria exactamente iguales unas a otras
! Se puede transferir el contenido de un variable a otra con tipos base distintos
Conversión de punteros
! No hay conversión automática entre punteros
! Dos mecanismos ! Casting explícito ���
int* a;���char* b = (char *)a;
! reinterpret_cast (Sólo permite casting entre punteros)
! char* b = reinterpret_cast<char*>(a);
! ¿Qué sucede con esta conversión?���
4
Ejercicio
! Escriba un programa que:
! Obtenga la dirección de memoria de la variable a (int a=3;)
! La almacene en una variable ptr de tipo puntero
! Muestre por pantalla el valor de ptr
! Establezca en la dirección indicada en ptr el valor 5
! Imprima el valor de a
13
Punteros a void
! Punteros cuyo tipo base es void ! (void*)
! Pueden ser utilizados como punteros genéricos ! Será posible convertir cualquier puntero a void* sin mensaje de error por parte del compilador ! Para tener una colección de punteros heterogéneos
! Para poder convertir del tipo void * a cualquier otro será necesario utilizar los mecanismos anteriores.
! Declarar una variable (que no sea un puntero) de tipo void no tiene sentido
Puntero Nulo
! Uno de los mayores problemas en la programación: punteros definidos sin valor inicial ! ¿Qué contienen?
! Contedrán valores aleatorios
! Resultados impredecibles
! Es necesario asignar una dirección que ninguna variable pueda contener esa dirección
! Para que se detecte un error en el momento en el que se vaya a utilizar
! Se utiliza la dirección 0
Uso de const con punteros
! Dos formas: ! Puntero constante a una variable
! No se puede modificar la dirección pero sí el valor
! Se tiene que inicializar con un valor
! Puntero a una variable constante ! Se puede modificar la dirección pero no el valor
5
Uso de const con punteros int a = 3;
int * const p_a = &a; // Puntero cte a una variable
¿*p_a = 6; ?
¿p_a = NULL;?���
const int a = 3;
cont int *p_a = &a; // Puntero a una variable cte
¿*p_a = 6;?
¿p_a = NULL;?
Uso de const con punteros int a = 3;
int * const p_a = &a; // Puntero cte a una variable
*p_a = 6; // BIEN
p_a = NULL; // ERROR���
const int a = 3;
cont int *p_a = &a; // Puntero a una variable cte
¿*p_a = 6; ?
¿ p_a = NULL; ?
Uso de const con punteros int a = 3;
int * const p_a = &a; // Puntero cte a una variable
*p_a = 6; // BIEN
p_a = NULL; // ERROR���
const int a = 3;
cont int *p_a = &a; // Puntero a una variable cte
*p_a = 6; // ERROR
p_a = NULL; // BIEN
Referencias
! Concepto parecido al de puntero
! Una variable de tipo referencia contiene la dirección de otra variable
tipo& nombre_variable = variable_a_la_que_apunta;
! Como un puntero constante
! Hay que inicializar la variable con un valor ! No puede cambiar el valor de la variable a la que apunta
! No puede inicializarse con el valor 0
6
Referencias
! Facilita la escritura: ! Para acceder al contenido no hace falta
usar el operador * ! Para asignarle una dirección no hace falta
usar el operador &
Referencias
int a = 5;
int& b = a; // No hace falta poner &a
b = 3; // No hace falta utilizar *, a cambiaría a 3
Ejercicio
! Cree un programa que defina una variable constante entera y cree las siguientes variables que apunten a la variable entera e impriman su contenido por pantalla: ! Puntero
! Puntero constante
! Referencia
! ¿Referencia constante?
23
Arrays y punteros
! El identificador de una variable array tiene el valor de la dirección del primer elemento.
! Por lo tanto, es un puntero y puede usarse como tal
int a[5]={10,20,30,40,50};
int b=*a;
! El identificador de una variable array es además un puntero constante por lo que no puede ser modificado
10 20 30 40 50
a
b 10
7
Arrays y punteros
int a[5]={10,20,30,40,50}; 10 20 30 40 50 a
pb
pc
11 20 30 40 50 a
11 20 30 44 50 a
pb pc
int *pb,*pc;
pb=a;
*pb=11;
pc=&a[3];
*pc=44;
Aritmética de Punteros
! Tratar a los punteros como variables numéricas
! Se pueden realizar un número limitado de operaciones aritméticas con punteros ! Un puntero puede ser incrementado o decrementado
por un entero (operadores +,+=,++,-,-=,--) ! Para acceder a las posiciones contiguas de la
dirección original ! Un puntero puede ser restado de otro
! Normalmente suele ser un error si se aplica sobre variables que no sean arrays.
Aritmética de Punteros
! Si sumamos 3 a un puntero, el resultado será el valor original más 3*(tamaño del tipo en bytes)
! Si se restan dos punteros de tipo_a, el resultado será el número de elementos de tipo tipo_a que hay entre ambos int a[] = {1,2,3,4};
int a[] = {1,2,3,4};
int *b = a;
¿*(b+2) = 2; ?
¿ int pos = b – a;?
Aritmética de Punteros
! Si sumamos 3 a un puntero, el resultado será el valor original más 3*(tamaño del tipo en bytes)
! Si se restan dos punteros de tipo_a, el resultado será el número de elementos de tipo tipo_a que hay entre ambos int a[] = {1,2,3,4};
int a[] = {1,2,3,4};
int *b = a;
*(b+2) = 2; // Equivale a b[2] = 2
int pos = b – a; // pos valdrá 2
8
Ejercicios
! Escriba un programa que imprima los elementos del siguiente array
int valores[] = {7,6,5,4};
Utilizando la variable (int *ptr) y modificándola por medio del operador ++
29
Punteros y Clases/Structs
struct Fecha {
int anyo, mes, dia;
;
Fecha a, *ptr;
ptr = &a;
¿Cómo accedemos al atributo anyo por medio de ptr?
Programación en C 30
Punteros y Clases/Structs
struct Fecha {
int anyo, mes, dia;
;
Fecha a, *ptr;
ptr = &a;
(*ptr).anyo = 1970; //dereferenciamos e indexamos
Programación en C 31
Punteros y Clases/Structs
struct Fecha {
int anyo, mes, dia;
;
Fecha a, *ptr;
ptr = &a;
(*ptr).anyo = 1970; //dereferenciamos e indexamos
ptr->anyo = 1970; // o utilizamos el operador flecha (->)
Programación en C 32
9
Arrays de punteros
! Un array puede contener punteros
! El uso más común es para tener almacenados un conjunto de arrays de chars
! Cada elemento será un puntero al primer carácter de cada array de char
! Cada array del array puede tener distinto número de elementos ! Con arrays multidimensionales esto no era posible
Arrays de punteros
char* nombres[] = {“Juan”,”Pepe”, “Maria”};
Dirección
nombres[0] 10
nombres[1] 15
nombres[2] 21
Dirección
10 ‘J’ ‘u’ ‘a’ ‘n’ ‘\0’
15 ‘P’ ‘e’ ‘p’ ‘e’ ‘\0’
21 ‘M’ ‘a’ ‘r’ ‘i’ ‘a’ ‘\0’
Ejercicio
! ¿Qué habría que hacer para conseguir la salida indicada?
35
char* nombres[] = {“Juan”,”Pepe”, “Maria”};
// Que sentencias habria que poner para que
cout << nombres[0] << endl; // Imprima Pepe
cout << nombres[1] << endl; // Imprima Juan
Arrays de punteros
char* nombres[] = {“Juan”,”Pepe”, “Maria”};
char* tmp = nombres[0];
nombres[0] = nombres[1];
nombres[1] = tmp;���
Dirección
nombres[0] 15
nombres[1] 10
nombres[2] 21
Dirección
10 ‘J’ ‘u’ ‘a’ ‘n’ ‘\0’
15 ‘P’ ‘e’ ‘p’ ‘e’ ‘\0’
21 ‘M’ ‘a’ ‘r’ ‘i’ ‘a’ ‘\0’
10
Ejercicios
37