La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Uso de punteros Unidad III – Conceptos Avanzados de Programación Programación I - 0416202.

Presentaciones similares


Presentación del tema: "Uso de punteros Unidad III – Conceptos Avanzados de Programación Programación I - 0416202."— Transcripción de la presentación:

1 Uso de punteros Unidad III – Conceptos Avanzados de Programación Programación I - 0416202

2 Uso de punteros Contenido Esta lección abarca los siguientes temas: Punteros, operadores e inicialización. Relación entre punteros y arreglos. Relación entre punteros y funciones. Utilización de memoria dinámica para manejar arreglos mediante el uso de punteros. Punteros a objetos. Vectores dinámicos de objetos. Uso de objetos dinámicos. Atributos dinámicos. Creación de objetos con atributos dinámicos. Destrucción de objetos con atributos dinámicos. Operador de asignación para objetos con atributos dinámicos.

3 Uso de punteros Punteros Todas las variables tienen una ubicación en la memoria y en esa ubicación se almacena su valor. Por ejemplo si se tiene la instrucción: int x = 200; La dirección de x es AF13 y su valor 200 es guardado en esa dirección. Las direcciones de memoria son notadas con el sistema hexadecimal x 200 Memoria AF13

4 Uso de punteros Punteros Ventajas de usar punteros Proporciona medios por los cuales se pueden modificar los argumentos de llamada de las funciones. Esto es, simular llamadas por referencia. Se usan para soportar rutinas de asignación dinámica de C/C++. Crear y manipular estructura de datos que puedan crecer o encogerse, caso de éstas: listas enlazadas, colas, pilas y árboles. Pueden mejorar la eficiencia de ciertas rutinas.

5 Uso de punteros Punteros Desventajas de usar punteros Puede provocar fallo del sistema por no estar inicializados o mal uso (forma incorrecta) de los mismos. Formato: Pueden ser de cualquier tipo de datos. Hay punteros que contienen la dirección de variables de cualquier tipo. tipo_dato * Nombre_Variable; Indicador de puntero

6 Uso de punteros Punteros Operadores & Se refiere a su dirección. * Indica el valor de la variable puntero. Ejemplo: int i, *ap, variable; i ap variable Memoria ABF0 ABF4 ABF8 150 variable=150; ap = &variable; i = *ap; ABF8150

7 Uso de punteros Punteros Inicialización de punteros Si se usa un puntero antes de darle valor probablemente falle el programa y el sistema operativo, por eso es tan importante la inicialización de ellos. Se puede hacer de dos formas: la primera es asignando la dirección de una variable y la segunda es inicializarlo en el valor nulo. Ejemplo: void main () { int variable, *Ap1, *Ap2, *Ap3; Ap1=&variable; //Su contenido depende de la //dirección de variable Ap2=NULL; Ap3=0; }

8 Uso de punteros Punteros Errores comunes 1. void main ( ) 2. { char k, *p; 3. k=’m’; 4. *p=k; 5. } 6. p=&k; 1. void main ( ) 2. { int n, *p; 3. n=10; 4. p=n; 5. printf(“%d”,*p); 6. } 7. p=&n; Puntero no inicializado Error en el uso del Puntero

9 Uso de punteros Punteros Notas importantes Aunque & y * representa AND a nivel de bits y multiplicación cuando se usan como operadores punteros tienen mayor prioridad que todos los operadores aritméticos. Las variables punteros deben apuntar al tipo de dato correcto porque pueden dar resultados no deseados. El operador & y * son complementos, cuando se operan ambos de manera consecutiva en el apuntador, en cualquier orden, se imprimirá el mismo resultado. El especificador de conversión %p extrae la localización de memoria de un apuntador en formato hexadecimal.

10 Uso de punteros Punteros Ejemplo: void main() {int n, *p; n=5; p=&n printf(“\n%d”, n); printf(“\n%p”, p); printf(“\n%d”, *p); printf(“\n%p”, *&p); printf(“\n%p”, &*p); } n p Memoria AC01 AD12 AC015 Pantalla d p d p p 5 AC01 5

11 Uso de punteros Punteros Manipulación de punteros Ejemplo: void main ( ) { int n = 5; int *np = &n; printf(“n = %d y *np = %d”, n, *np); *np++; printf(“n = %d y *np = %d”, n, *np); *np = *np + 20; printf(“n = %d y *np = %d”, n, *np); } Memoria AC015 n np AC01 AD12 AC016 26

12 Uso de punteros Punteros Aritmética de punteros Las operaciones se realizan a nivel de tipo de elementos y los operadores usando son +, -, ++,--. Ejemplo: void main ( ) { char var1 = ‘a’; char *caracter = &var1; int var2 = 5; int *entero = &var2;... } 0600 Z 0601 var2 0602 5 a 10 0603 0604 0605 0606 0607 0608 var1 0100 0601 caracter 0200 0603 entero 0600 0607 caracter --; entero++;

13 Uso de punteros Punteros y Arreglos Relación entre punteros y arreglos Un arreglo es un puntero a la dirección de su primer elemento. Un nombre de arreglo sin índice, devuelve la dirección de comienzo del arreglo que es el primer elemento. Se puede entonces intercambiar información entre punteros y arreglos, siempre y cuando sean del mismo tipo.

14 Uso de punteros Punteros y Arreglos Relación entre punteros y arreglos Para acceder al tercer elemento de cadena se puede hacer de 2 formas: char cadena[ ]=“Unet”; char *Ap; Ap= cadena; //Ap tiene la dirección del //primer elemento de la cadena cadena[2] //Tradicional: Ordenación de arreglos ó *(Ap+2) //Usando aritmética de punteros. AC01 AC02 AC03 AC04 AC05 cadena Un e t \0 DF78 Ap AC01

15 Uso de punteros Punteros y Funciones Relación entre punteros y funciones En C++ existen dos tipos de parámetros al invocar funciones, estos son: por valor y por referencia. Cuando los argumentos se pasan en llamada por valor, se efectúa una copia del valor del argumento y ésta se pasa a la función invocada. Las modificaciones a la copia no afectan el valor original de la variable. La llamada de funciones donde intervienen parámetros por punteros se le llama pase por referencia y debe ser utilizada sólo en llamadas confiables, porque las modificaciones de estas variables se mantienen y afectan la variable original.

16 Uso de punteros Punteros y Funciones Relación entre punteros y funciones Cuando un argumento se pasa por referencia, la dirección del dato es pasada a la función. El contenido de esta dirección puede ser accedido libremente. Además, cualquier cambio que se realiza al dato (al contenido de la dirección) será reconocido en ambas, la función y rutina de llamada. Así, el uso de punteros como argumentos de funciones permite que el dato sea alterado globalmente desde dentro de la función. Los argumentos formales que sean punteros deben ir precedidos por un asterisco ( * ).

17 Uso de punteros Punteros y Funciones Paso de argumentos a una función Paso por valor y por referencia: #include void pase_por_valor_y_referencia (int, int *); void main( ) { } void pase_por_valor_y_referencia (int aux_ x, int *aux_y) { aux_x = aux_x + 2; *aux_y = *aux_y + 2; } int X=5, Y=10; printf(“\nEl valor inicial de X es: %d y el de Y es: %d“, X, Y); printf(“\nEl valor final de X es: %d y el de Y es: %d“, X, Y); getch( ); pase_por_valor_y_referencia (X, &Y);

18 Uso de punteros Punteros y Funciones Paso de arreglos a una función Para pasar todo un arreglo a una función, el nombre del arreglo debe aparecer solo, sin corchetes, ni índices, como un argumento real en la llamada a la función. El correspondiente argumento formal debe ser declarado como un arreglo, si se trata de un vector se escribe con un par de corchetes vacíos. Los arreglos multidimensionales se definen prácticamente de la misma manera que los unidimensionales, excepto que se requiere un par separado de corchetes para cada índice. Pudiéndose dejar el primer par de corchetes vacíos. Si un elemento del arreglo es alterado dentro de una función, esta alteración será reconocida en la parte del programa desde la que se hizo la llamada.

19 Uso de punteros Punteros y Funciones Paso de arreglos a una función: Método tradicional #include void cargar(int nx, int vec[]); void promedio(int nx, int vec[]); void main( ) { int i; int vector [5]; cargar(5,vector); promedio(5,vector); getch(); } void cargar (int nx, int vec[] ) { for (int i=0; i<nx; i++){ printf(“\nIngrese un numero: ”); scanf(“%d”,&vec[i]); } } void promedio(int nx, int vec[]) { int acum=0; for (int i=0; i<nx; i++) acum=acum+vec[i]; printf(“\nProm:%.2f”,(float)acum/nx ); }

20 Uso de punteros Punteros y Funciones Paso de arreglos a una función: Usando punteros #include void cargar(int nx, int *vec); void promedio(int nx, int *vec); void main( ) { int i; int vector[5]; cargar(5,vector); promedio(5,vector); getch(); } void cargar(int nx, int *vec ) { for (int i=0; i<nx; i++){ printf(“\nIngrese un numero: ”); scanf(“%d”,vec+i); } } void promedio(int nx, int *vec) { int acum=0; for (int i=0; i<nx; i++) acum=acum+ *(vec+i); printf(“\nProm2:%.2f”,(float)acum/nx ); }

21 Uso de punteros Punteros y Funciones Paso de cadenas a una función #include void pase_cadenas (char *r, char est[], char * cap, char v_mun[][20]); void main( ) { } void pase_cadenas (char *r, char est[], char *cap, char v_mun[][20]) { *r = ‘S’; strcpy(est,”Tachira”); strcpy(cap,”San Cristobal”); strcpy(v_mun[0],”Lobatera”); } char resp, estado[20], capital[20], v_municip[5][20]; pase_cadenas (&resp, estado, capital, v_municip); printf(“%c %s %s %s”, resp, estado, capital, v_municip[0]); getch(); printf(“%c %s %s %s”, resp, estado, capital, v_municip[0]);

22 Uso de punteros Punteros y Memoria Dinámica Instrucción new: Trabajando con un vector Se utiliza para abrir memoria a variables dinámicas. Ejemplo: Después de utilizarse este operador, la memoria debe liberarse con el operador delete. int * x = new int [MAX]; delete [] vector; x 0 1 2 3 4 0100 0104 0108 0112 0116 0050 0100

23 Uso de punteros Punteros y Memoria Dinámica void recibeVector1(int *v, int t){ for(int i=0; i<t;i++) *(v+i)=i; } void recibeVector2(int v[], int t){ for(int i=0; i<t;i++) v[i]+=i; } void main (int argc, char * argv[]){ int *vec, tam; printf("Tamanho:"); scanf("%d",&tam); vec = new int [tam]; recibeVector1(vec, tam); recibeVector2(vec,tam); } Ejemplo:

24 Uso de punteros Punteros y Memoria Dinámica Instrucción new: Trabajando con una matriz void recibeMatriz(int **, int, int); void main (int argc, char * argv[]){ int **mat, nfil, ncol; printf("Filas:"); scanf("%d",&nfil); printf("Columnas:"); scanf("%d",&ncol); mat = new int * [nfil]; for(int i=0; i<nfil;i++) mat[i] = new int [ncol]; recibeMatriz(mat, nfil, ncol); } void recibeMatriz(int **m, int f, int c){ for(int i=0; i<f;i++) for(int j=0; j<c; j++) scanf(“%d”, (*(m+i)+j) ); } 0 120 12 0100 0104 0108 mat 0050 0100 2000 2004 2008 2012 2016 2000 2020 2024 2028 2032 2036 2020 0 1 2 3 4 2040 2044 2048 2052 2056 2040

25 Uso de punteros Punteros y Memoria Dinámica Instrucción malloc: Solicita un bloque de (size) bytes de memoria. Si no hay espacio disponible malloc devuelve null. La solicitud de bloque de memoria es hasta 64K. Se deben incluir las librerías stdlib.h y alloc.h Formato: Ejemplo: void * malloc (size_t size); x = (int *) malloc(MAX * sizeof(int) ); Esta función reserva un bloque de memoria cuyo tamaño (en bytes) es equivalente a MAX=5 cantidades enteras. El puntero x apunta al comienzo del bloque de memoria.

26 Uso de punteros Punteros y Memoria Dinámica #include void main() { int *Apunt, n, i; ´ clrscr(); printf(“Cantidad de datos a ingresar: ”); scanf(“%d”,&n); //Para reservar memoria Apunt = ( int * ) malloc ( n * sizeof (int) );//malloc devuelve un void * printf(“Bytes reservados para cada dato: %d\n”, sizeof(Apunt) ); //Para leer la lista de números en el vector for(i=0; i<n; i++){ printf(“Ingrese Apunt[%d]: ”, i); scanf(“%d”, Apunt + i ); } //En vez de &Apunt[i] //Para mostrar la lista de números del vector for(i=0; i<n; i++) printf(“Apunt[%d]= %d\n”, i, *(Apunt +i) );// En vez de Apunt[i] //Para liberar la memoria utilizada free(Apunt); getch(); } Ejemplo:

27 Uso de punteros Punteros y Memoria Dinámica Ahora, supongamos que Matriz es un arreglo bidimensional de enteros con 10 filas y 5 columnas. Usando una variable puntero para representar la Matriz, ésta se puede declarar: int * Matriz [10]; ó int *Matriz [5]; Ejemplo: for (i=0; i<10; i++) Matriz[i] = (int *) malloc (5*sizeof(int) ); ó for (i=0; i<5; i++) Matriz[i] = (int *) malloc (10*sizeof(int) ); En vez de Matriz [10][5]; Luego, se pide memoria para la dimensión que falta por representar:

28 Uso de punteros Punteros y Memoria Dinámica Ejemplo: #include void leer(int * [5], int, int); void mostrar(int * [5], int, int); void main() { int * Matriz [5], n, i; printf(“Cantidad de datos a ingresar: ”); scanf(“%d”,&n); //Para reservar memoria for (i=0; i<5; i++) Matriz[i]=(int *)malloc(n*sizeof(int)); //malloc devuelve un void * leer(Matriz, 5, n); mostrar(Matriz, 5, n); free(Matriz); getch(); } void leer(int * m[5], int nfil, int ncol){ int x, y; for (x=0; x<nfil; x++) for (y=0; y<ncol; y++) { printf(“Ingrese Matriz[%d][%d]: ”, x, y); scanf(“%d”, (*(m+x) + y) ); //ó (m[x] + y) En vez de &m[x][y] } void mostrar(int * m [5], int nfil, int ncol){ int x, y; printf(“\nDatos de la Matriz\n”); for (x=0; x<nfil; x++) { for (y=0; y<ncol; y++) printf(“ %d”, *(*(m+x) + y)); //ó *(m[x] + y) En vez de m[x][y] printf(“\n”); } }

29 Uso de punteros Punteros y Memoria Dinámica Ajusta el tamaño de memoria previamente solicitada al nuevo tamaño, trasladando el contenido a una nueva localización de memoria si es necesario. Instrucción realloc: Formato: void * realloc (void * block, size_t size); block: Puntero a un bloque de memoria previamente solicitado con instrucción malloc, calloc o realloc. size: El nuevo tamaño en bytes que tendrá el bloque de memoria

30 Uso de punteros Punteros y Memoria Dinámica Ejemplo:

31 Uso de punteros Punteros y Objetos En C++ se pueden definir punteros a objetos, ya que las clases son tipos, y se pueden declarar punteros de cualquier tipo. Por tanto, si se tiene una clase Punto, se puede crear: class Punto { private: int coorx; int coory; public: …… }; int *p1; char *c; Punto * p1; Esta declaración no llama al constructor, ya que se trata de una variable puntero y no de un Punto Ejemplo:

32 Uso de punteros Punteros y Objetos Para trabajar con el puntero, se le puede asignar la dirección de memoria de un objeto de tipo Punto. class Punto { private: int coorx; int coory; public: Punto(int a, int b); int get_x(); int get_y(); void set_x(int a); void set_y(int a); void visualizar(); }; Punto c(2,5); Punto *p1; p1 = & c; p1->visualizar(); (*p1).visualizar(); p1->set_x(8);

33 Uso de punteros Punteros y Objetos También se pueden usar los operadores de las variables dinámicas: new y delete. El operador new sigue los siguientes pasos: 1.Crea espacio para el objeto. 2.Llama al constructor especificado. El operador delete realiza los pasos inversos: 1.Llama al destructor. 2.Libera la memoria ocupada por el objeto. Ejemplo: Punto *p1, *p2; p1 = new Punto(); P2 = new Punto(3,4);..... delete p2; Constructor que queremos que se ejecute

34 Uso de punteros Punteros y Objetos También se pueden crear vectores dinámicos de objetos Vectores dinámicos de objetos El operador new sigue los siguientes pasos: 1.Crea espacio para los 100 objetos. 2.Llama al constructor por defecto para cada objeto (0 a 99). El operador delete realiza los pasos inversos: 1.Llama al destructor para cada punto (99 a 0). 2.Libera la memoria. Punto **p; p = new Punto[100]; delete [] p;

35 Uso de punteros Punteros y Objetos Antes de usar el objeto, pasándole mensajes a través del puntero que lo apunta, se ha de crear el objeto con new. Cuando ya no se necesita el objeto se destruye con delete. Uso de objetos dinámicos void main () { Punto *p; //Crear ----- p = new Punto(); //Creado el objeto dinámico //Usar ----- p->visualizar(); //Uso del objeto mediante envío de mensaje //Destruir ----- delete p; //Liberar memoria del objeto }

36 Uso de punteros Punteros y Objetos Se está en presencia de ellos, cuando dentro de una clase se declaran atributos en forma de punteros: Atributos dinámicos Ambas declaraciones son equivalentes pero con implementación distinta. Punto p1; class Punto { private: int x; int y; public:.... }; Punto p2; class Punto { private: int * x; int * y; public:.... };

37 Uso de punteros Punteros y Objetos Creación de objetos con atributos dinámicos class Punto { private: int * x; int * y; public: Punto(int a=0, int b=0);.... }; Punto p2; Punto::Punto(int a, int b) { x = a; y = b; } Punto::Punto(int a, int b) { x= new int; y = new int; *x = a; *y = b; } Cuando se crea un objeto con atributos dinámicos, se crean al mismo tiempo esos atributos. ¿Dónde? En el constructor. X

38 Uso de punteros Punteros y Objetos Para cada objeto que se crea de la clase Punto, se crean a su vez sus atributos dinámicos. Atributos dinámicos void main () { Punto p1(7,3); Punto p2();.... } class Punto { private: int * x; int * y; public: Punto(int a=0, int b=0);.... }; Punto::Punto(int a, int b) { x= new int; y = new int; *x = a; *y = b; }

39 Uso de punteros Punteros y Objetos Creación de objetos con atributos dinámicos ¿Cuál es el efecto de la siguiente declaración? class Punto { private: int * x; int * y; public: Punto(int a=0, int b=0);.... }; Punto::Punto(int a, int b) { x= new int; y = new int; *x = a; *y = b; } void main () { Punto *p1; p1=new Punto(2,5);.... }

40 Uso de punteros Punteros y Objetos Destrucción de objetos con atributos dinámicos De la misma forma, cuando se destruye un objeto con atributos dinámicos, se destruyen al mismo tiempo esos atributos. ¿Dónde? En el constructor. class Punto { private: int * x; int * y; public: Punto(int a=0, int b=0); ~Punto(); }; Punto::Punto(int a, int b) { x= new int; y = new int; *x = a; *y = b; } Punto::~Punto() { delete x; delete y; } El destructor destruye los atributos dinámicos

41 Uso de punteros Punteros y Objetos Operador de asignación para atributos dinámicos Cuando se copian objetos, se ejecuta el operador de asignación de la clase. Si en la clase no está definido ningún operador de asignación, el compilador realiza una copia bit a bit. void main () { Punto p1(2,5), p2; p2 = p1; } El problema está en que ambos objetos comparten memoria Ocurre una pérdida de memoria, porque se copian los atributos igualando los punteros

42 Uso de punteros Punteros y Objetos En esta situación, 1.¿Qué ocurre cuando se modifica el objeto p1? 2.¿y cuando se destruye el objeto p1? Operador de asignación para atributos dinámicos X

43 Uso de punteros Punteros y Objetos Operador de asignación para atributos dinámicos Esto se resuelve sobrecargando el operador de asignación “=”. Cuando las clases definen atributos dinámicos, el operador de asignación se hace imprescindible. El operador de asignación debe copiar los contenidos de los punteros, no los punteros como tal. Punto& Punto::operator = (Punto p) { *x = *p.x; *y = *p.y; return *this; } Devuelve una referencia de ese objeto Como el objeto sobre el que se copia, ya tiene creados los atributos dinámicos, simplemente se copia lo apuntado.

44 Uso de punteros Punteros y Objetos La clase Punto completa: class Punto { private: int * x; int * y; public: Punto(int a=0, int b=0); ~Punto(); Punto& operator = (Punto p); int get_x(); int get_y(); void set_x(int a); void set_y(int a); void visualizar(); }; archivo Punto.h

45 Uso de punteros Punteros y Objetos La clase Punto completa: archivo Punto.cpp Punto::Punto(int a, int b) { x= new int; y = new int; *x = a; *y = b; } Punto::~Punto() { delete x; delete y; } Punto& Punto::operator = (Punto p) { *x = *p.x; *y = *p.y; return *this; } void Punto::set_x(int a) { *x = a; } void Punto::set_y(int a) { *y = a; } int Punto::get_x() { return *x; } int Punto::get_y() { return *y; }

46


Descargar ppt "Uso de punteros Unidad III – Conceptos Avanzados de Programación Programación I - 0416202."

Presentaciones similares


Anuncios Google