Unidad 9. Punteros

Anuncio
Unidad 9
PUNTEROS EN C++
Objetivos




Entender el concepto de
puntero.
Saber definir el tipo de datos
puntero.
Saber crear y acceder
variables puntero y
destruirlas.
crear dinámicamente y
acceder variables
referenciadas por puntero, y
destruirlas.




usar punteros para la
creación de arrays
dinámicos.
Usar punteros como
alternativa al paso de
parámetros por referencia.
Usar punteros a funciones
como parámetros de otras
funciones.
Saber utilizar punteros para
mejorar la eficiencia de un
programa
2
Contenidos
1. INTRODUCCIÓN
2. ¿QUÉ ES UN PUNTERO?
DECLARACIÓN E
INICIALIZACIÓN
2.1. Punteros a objetos
3. OPERADORES PUNTEROS
4. PASO POR DIRECCIÓN
5. EXPRESIONES CON PUNTEROS
5.1. Asignaciones de punteros
5.2. Aritmética de punteros
5.3. Comparación de punteros
6. PUNTEROS Y ARRAYS
6.1. Indexar un puntero
6.2. Punteros a arrays de caracteres
6.3. Arrays de punteros
7. GESTIÓN DINÁMICA DE
MEMORIA
8. ARRAYS Y ASIGNACIÓN
DINÁMICA
9. PUNTEROS Y ARRAYS
BIDIMENSIONALES
9.1. Representación a partir de un puntero a
arrays de una dimensión
9.2. Representación a partir de un array de
punteros a arrays de una dimensión
10. PUNTEROS A PUNTEROS
11. PUNTEROS A FUNCIONES
11.1. Formato de declaración
11.2. Asignación del nombre de función a
un puntero a función
11.3. Llamada a una función a través de su
puntero
11.4. Paso de funciones a otras funciones
12. LA ORDENACIÓN RÁPIDA EN C++:
qsort
13. UNA NOTA SOBRE
DECLARACIONES DE OBJETOS EN
C/C++
14. ARGUMENTOS DE main
3
Concepto de puntero


Un puntero es un tipo de variable que contiene la
dirección en memoria de otra variable, que se conoce
como objeto al que apunta.
No hay que confundir una dirección de memoria con el
contenido de esa dirección de memoria.
int x=25;
Dirección mm
...
...
1502
25
1504
1506
1508
...
...
...
...
La dirección de la variable x (&x) es 1502
El contenido de la variable x es 25
4
Tipos de punteros


A objetos.
- Cuando el puntero tiene como valor la localización de otro objeto.
A funciones.
- Cuando el puntero tiene como valor la localización de llamada a
una función.
Importancia del uso de punteros en C:



Simula el paso por referencia (Paso por dirección).
Mejoran la eficiencia de algunos algoritmos (más rápidos).
Se usan para soportar las funciones de asignación
dinámica de memoria (malloc, free, new, delete) y las
estructuras de datos dinámicas.
5
PUNTEROS A OBJETOS
•Una variable puntero se declara como todas las variables.
•Debe ser del mismo tipo que la variable apuntada. Su
identificador va precedido de un asterisco (*):
<tipo> * Nombre_Puntero;
int *punt; //Es una variable puntero que apunta a variable que contiene un dato de
tipo entero llamada punt.
char *car; //Es un puntero a variable de tipo carácter.
long float *num;
float *mat[5]; // . . .
Un puntero
tiene su
propia
dirección de
memoria:
&punt
&car
6
Operadores punteros

De dirección &: Aplicado al nombre de un objeto,
devuelve la dirección de memoria de su operando.

De indirección *: Aplicado al nombre de un objeto
puntero, devuelve el valor del objeto localizado en la
dirección que le sigue.
A un puntero se le puede asignar:
- la dirección de una variable no puntero. P1 = &var
- el valor de otro puntero. P2 = P1
- un valor nulo. P1 = NULL

7
EXPRESIONES CON PUNTEROS
• Hay tantos tipos de punteros como tipos de datos.
• También pueden declararse punteros a estructuras más
complejas (funciones, struct, ficheros...) e incluso punteros
vacíos (void ) y punteros nulos (NULL).
Ejemplo1
char dato;
//variable que almacenará un carácter.
char *punt; //declaración de puntero a carácter.
punt = &dato; //en la variable punt guardamos la dirección
// de memoria de la variable dato; punt apunta
// a dato. Ambas son del mismo tipo, char.
8
EXPRESIONES CON PUNTEROS

Aritmética de punteros : suma, incremento, decremento y
resta de enteros a punteros.
Ejemplos: Hay que tener cuidado con las direcciones apuntadas:
int *punt = NULL, var = 14;
punt = &var;
printf(“%#X, %p”, punt, &var);
printf(“\n%d, %d”, *punt, var);
printf(“%d, %d”, *(punt+1), var+1);
//la misma salida: dirección (FFF2)
//salida: 14, 14
Numcualquiera,
*(punt + 1) repesenta el valor contenida//salida:
en la dirección
de memoria15
aumentada
en una posición (int=2bytes), que será un valor no deseado. Sin embargo
var+1 representa el valor 15.
punt + 1 representa lo mismo que &var + 1 (avance en la dirección de memoria
de var).

Comparación de punteros .
Los punteros pueden usarse en una expresión relacional.
Ejemplo:
if(punt <punt2) printf (“punt apunta a una memoria menor que punt2”);
Ver sumpun.cpp
9
Ejercicio: haz la traza de
#include <stdio.h>
void main(void)
{
int a, b, c, *p1, *p2;
void *p;
p1 = &a;
*p1 = 1;
p2 = &b;
*p2 = 2;
p1 = p2;
*p1 = 0;
p2 = &c;
*p2 = 3;
printf("%d %d %d\n", a, b, c);
// Paso 9. ¿Qué se imprime?
p = &p1; //no tiene sentido, aunque el compilador lo permita
p1 = p2;
*p1 = 11;
printf("%d %d %d\n", a, b, c);
// Paso 13. ¿Qué se imprime?
}
10
Ver dirmen.cpp
Punteros y Arrays

En C se puede indexar un puntero.
int mat[ ] = {2, 16, -4, 29, 234, 12, 0, 3};
Dirección
del elemento
0
Dirección del
octavo elemento
&mat[0] &mat[1] &mat[2] &mat[3] &mat[4] &mat[5] & mat[6] &mat[7]
2
mat
16
-4
mat+1 mat+2
Puntero a la
dirección del
elemento 0
29
mat+3
234
12
mat+4 mat+5
Incremento en una
unidad int (dos bytes)
0
3
mat+6
mat+7
mat++
11
Punteros y Arrays II

Punteros a arrays de caracteres.
Las operaciones con cadenas se realizan con punteros.
La forma de definir un puntero a una cadena de caracteres:
char *cadena;
El identificador del array es la dirección de comienzo del array. Para saber
dónde termina la cadena, el compilador añade el carácter ‘\0’ (ASCII 0,
NULL): char *nombre = “PEPE PEREZ”;
nombre
dirección de memoria
P E P E
*(nombre+2)
P E R E Z \0
contenido
12
Punteros y Arrays III
Arrays de puntero a cadenas de caracteres.
En un array de punteros a cadenas de caracteres cada elemento apunta a un
carácter.
La declaración será:
char *cad[10]; //array de 10 filas y cada fila una dirección a una cadena de
caracteres
cad[0]
...
cad
FFB1
H
O L
cad+1
A
...
\0
cad[4]
A
D
I
O S
\0
...
...
13
Punteros y Arrays IV (arrays de punteros

Arrays de punteros.
Los punteros se pueden agregar en arrays. El
acceso será:
Como un array de punteros a arrays de una
dimensión: utilizado con las cadenas de caracteres.
*array [filas];
NORMALMENTE –por facilidad de uso-:
typedef char cadena[columnas];
cadena array[filas];

Ver u9_e6.cpp
14
Punteros y arrays bidimensionales I
Col 0
Col 1
Col 2
Col 3
Fila 0
1.45
-23.5
-14,08
17.3
Fila 1
20
2.95
0.082
6.023
Utilizando punteros, la declaración será:
float *mat [4]; //array bidimensional
En donde mat es un puntero a un grupo contiguo de arrays
monodimensionales (vectores) de 4 elementos cada uno.
Con subíndices
Con punteros
Valor
mat[0][0]
*(*(mat+0)+0)
1.45
mat[0][1]
*(*(mat+0)+1)
-23.5
mat[0][2]
*(*(mat+0)+2)
-14.08
mat[0][3]
*(*(mat+0)+3)
17.3
mat[1][0]
*(*(mat+1)+0)
20
mat[1][1]
*(*(mat+1)+1)
2.95
mat[1][2]
*(*(mat+1)+2)
0.082
mat[1][3]
*(*(mat+1)+3)
6.023
15
Punteros y arrays bidimensionales II
int x[10][20];
Ver: ardepunt.cpp.
pmatcon.cpp
Consideramos que es un array formado por 10 arrays
unidimensionales (vectores) de 20 elementos cada uno
* ( * ( x + 2 ) +5) equivale a x[2][5]
ya que x + 2 es un puntero a la fila 3. Por tanto. El contenido
de dicho puntero, *(x+2), es la fila 3. Si me desplazo 5
posiciones en esa fila llego a la posición *(x+2)+5, cuyo
contenido es *(*(x+2)+5).
Las siguientes expresiones con punteros son válidas:
**x
x[0][0]
*(*(x+1))
x[1][0]
**(x+1)
x[1][0]
*(*x+1)
x[0][1]
*(*(x+1)+1)
x[1][1]
16
Punteros y arrays bidimensionales III
int array[filas][columnas]; int array[F][C];
array[y][z] = 129; //es equivalente a:
*(*array + columnas F y + z)) = 129; //asignación
Con int array[2][5], ¿qué pondría si quisiera asignar 129 al
elemento de la fila 1 y columna 2?
*(*array + 5x1 + 1)) = 129;
es decir, desde el origen del array avanza 6 posiciones
de memoria:
fila 0     
fila 1
 129   
array[1][1]
*(*(array+5+1))
*(*array + 6)
17
arrays dinámicos I

Pasos para usar un array dinámico:


Se declara un puntero en vez de un array.
tipo * Variable_puntero;
Se pide la memoria adecuada para el array a partir del
puntero declarado anteriormente.
Variable_puntero = (tipo*) malloc (tamaño*sizeof (tipo));
Variable_puntero = new TipoOjeto[(Expresion)];


Se debe liberar la memoria una vez que hemos
terminado con ella.
free (Variable_puntero);
delete [ ] Variable_puntero;
Diferencias entre una forma y otra:

new y delete estan diseñados para POO

new y delete son operadores por lo tanto no necesitan
prototipo.

new no necesita casting.
18
arrays dinámicos II

Nos aseguramos de tener memoria.
if (array == NULL)
{
<Código de error y/o exit (0) >
}

Procesamos en caso afirmativo.
else
{
<Procesamos>
free (array); // liberamos
memoria
}
Ver: proyecto con AsigDin.cpp, arrays.h
19
Gestión dinámica de memoria


MALLOC
void * malloc (size_t TAM);
REALLOC (cambia tamaño, no añade)
void * realloc (void* viejo_bloque, size_t TAM-NUEVO);



FREE
void free (void * punt);
NEW
new TipoObjeto [(Expresion)];
DELETE
delete [[ ]] PunteroObjeto;
20
/* asignación-reasignación de
memoria dinámica REASIGMM.CPP*/
#include <stdio.h>
#include <alloc.h>
#include <string.h>
int main(void)
{
char *str;
/* reservamos 9 caracteres para la cadena*/
//str = (char *) malloc(10);
str = new char [10];
/* colocamos la cadena Hello*/
strcpy(str, "Hello");
printf("Cadena %s\t en la dirección %p\n", str, str);
str = (char *) realloc(str, 20);
/* colocamos la cadena Hello, cruel world!*/
strcpy(str, "Hello, cruel wordl!");
printf("la cadena ahora %s\t su nueva dirección %p\n", str, str);
/* liberamos la memoria*/
//free(str);
delete [ ]str;
return 0;
}
21
ARGUMENTOS DE MAIN

argc: número de argumentos pasados desde la línea de
comandos.


al menos vale 1, el nombre del programa
argv: array de punteros (de longitud argc) a los argumentos
enviados.



env: array de punteros a las variables de entorno.



argv[0] apunta al nombre del programa
argv[argc-1] apunta al último de los argumentos
la ultima apunta a NULL.
si se usa, deben usarse tambien argc y argv.
PASO DE PARÁMETROS DESDE:


LA LINEA DE COMANDOS: a continuación del nombre del programa
EL IDE: en la opción arguments de Run
página: 367 y apellido.cpp
22
PUNTEROS A FUNCIONES




Formato de declaración
float (*Ppot) (float, float);
Asignación del nombre de función a un
puntero a función
Ppot = potencia;
Llamada a una función a través de su
puntero
res = (*Ppot) (num1,num2); // res = potencia (num1,num2);
Paso de funciones como parámetros de funciones:
ver página 361 y 362
ver puntfunc.cpp y pág. 360
23
Ordenación rápida : Quick –sort
Búsqueda binaria. <stdlib.h>

qsort
void qsort (void *base, size_t NUMELEM, size_t NUM_BYTES, int
(*comp) (const void *elem1, const void *elem2));





void *base: puntero a un array de cualquier tipo
size_t NUMELEM: número de elementos del array
size_t NUM_BYTES: número de bytes de cada elemento del array
(*comp): puntero a la función que ordena y que debemos implementar en
cada caso.
bsearch: búsqueda binaria en un array ordenado
void *bsearch (const void *key, const void *base, size_t NUMELEM,
size_t NUM_BYTES, int (*fcmp)(const void* elem1, const void*
elem2));


devuelve un puntero al primer elemento que coincida con Key. Si no
existe devuelve NULL.
(*fcmp): puntero a la función que compara un elemento del array con la
clave.
ver orden.cpp y ejercicios 6 y7
24
El ignorante afirma, el sabio duda y reflexiona.
--Aristóteles--
25
Descargar