Você está na página 1de 12

Universidad Nacional de Trujillo Ingeniera de Sistemas

Computacin Apuntadores

APUNTADORES
1. Introduccin. Un apuntador es la direccin en memoria de una variable. La memoria de una computadora se divide en posiciones de memoria numeradas (llamadas bytes), y las variables se implementan como una sucesin de posiciones de memoria adyacentes. En ocasiones el sistema C++ utiliza estas direcciones de memoria como nombres de las variables. Si una variable se implementa como tres posiciones de memoria, la direccin de la primera de esas posiciones a veces se usa como nombre para esa variable. Por ejemplo, cuando la variable se usa como argumento de llamada por referencia, es esta direccin, no el nombre del identificador de la variable, lo que se pasa a la funcin invocadora. Una direccin que se utiliza para nombrar una variable de este modo (dando la direccin de memoria donde la variable inicia) se llama apuntador porque podemos pensar que la direccin apunta a la variable. La direccin apunta a la variable porque la identifica diciendo dnde est, en lugar de decir qu nombre tiene. Digamos que una variable est en la posicin nmero 1007, podemos referirnos a ella diciendo es la variable que est all, en la posicin 1007. En varias ocasiones hemos empleado apuntadores: cuando una variable es un argumento de llamada por referencia en una llamada de funcin, la funcin recibe esta variable argumento en forma de un apuntador a la variable. stos son dos usos importantes de los apuntadores, pero el sistema C++ se encarga de ello automticamente, aunque tambin proporciona la posibilidad de escribir programas que manipulen apuntadores de cualquier forma que queramos. 2. Definicin y declaracin. Un apuntador, llamado tambin puntero, es aquella variable que contiene una direccin de memoria, normalmente la direccin de otra variable. Se pueden tener apuntadores a cualquier tipo de variable. Un apuntador se puede guardar en una variable. Sin embargo, aunque un apuntador es una direccin de memoria y una direccin de memoria es un nmero, no podemos guardar un apuntador en una variable de tipo int o double. Una variable que va a contener un apuntador se debe declarar como de tipo apuntador. Por ejemplo, lo que sigue declara p como una variable de apuntador que puede contener un apuntador que apunta a una variable de tipo double.
double *p;

La variable p puede contener apuntadores a variables de tipo double, pero normalmente no puede contener un apuntador a una variable de algn otro tipo, como int o char. Cada tipo de variable requiere un tipo de apuntador distinto. En general, si queremos declarar una variable que pueda contener apuntadores a otras variables de un tipo especfico, declaramos variables de apuntador igual que declaramos una variable ordinaria de ese tipo, pero colocamos un asterisco antes del nombre de la variable. Por ejemplo, lo siguiente declara las variables ptr1 y ptr2 de modo que puedan contener apuntadores a variables de tipo int; tambin se declaran dos variables ordinarias var1 y var2 de tipo int:
int *ptr1, *ptr2, var1, var2;

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-1-

Universidad Nacional de Trujillo Ingeniera de Sistemas

Computacin Apuntadores

Es necesario que haya un asterisco antes de cada una de las variables de apuntador. Si omitimos el segundo asterisco en la declaracin anterior, ptr2 no ser una variable de apuntador; ser una variable ordinaria de tipo int. Cuando tratamos apuntadores y variables de apuntador, normalmente hablamos de apuntar en lugar de hablar de direcciones. Cuando una variable de apuntador, como ptr1, contiene la direccin de una variable, como var1, decimos que dicha variable apunta a la variable var1 o es un apuntador a la variable var1. 3. Operadores de apuntadores. 3.1. Operador de direccin (&). Permite determinar la direccin de una variable cualquiera (puede ser incluso la direccin de una variable apuntador). Este operador unario se puede anteponer a cualquier variable. 3.2. Operador de indireccin (*). Tambin llamado operador de desreferenciacin. Permite determinar el valor o contenido de lo que se encuentra en la direccin apuntada por la variable direccin (apuntador). Este operador unario se puede anteponer a una variable apuntador o puntero. 4. Inicializacin. Cuando un apuntador es declarado apunta a algn lado. Se debe inicializar el apuntador antes de usarlo.
int *ptr1; int var1; ptr1 = &var1; *ptr1 = 100; // Se // Se // El // Se
declara un apuntador a un entero. declara una variable entera. apuntador recibe la direccin de var1. asigna valor a var1 a travs de su apuntador.

Podemos representar grficamente que ptr1 apunta a la variable var1:

ptr1

var1 100

int

int

Figura 1. Representacin grfica de: ptr1 apunta a la variable var1. Ahora tenemos dos formas de referirnos a var1: podemos llamarla var1 o la variable a la que ptr1 apunta. En C++ la forma de decir la variable a la que ptr1 apunta es *ptr1. ste es el mismo asterisco que usamos al declarar ptr1, pero ahora tiene otro significado. Cuando el asterisco se usa de esta manera se le conoce como operador de desreferenciacin, y decimos que la variable de apuntador est desreferenciada.

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-2-

Universidad Nacional de Trujillo Ingeniera de Sistemas

Computacin Apuntadores

Si ahora ejecutamos las siguientes sentencias, desplegarn el mismo valor en la pantalla:


cout << var1 << endl; cout << *ptr1 << endl; // Imprimir el nmero 100. // Imprimir el nmero 100.

En tanto ptr1 contenga un apuntador que apunte a var1, entonces var1 y *ptr1 se referirn a la misma variable. As pues, si asignamos 100 a *ptr1, tambin estamos asignando 100 a var1. El smbolo & que usamos para obtener la direccin de una variable es el mismo smbolo que usamos en una declaracin de funcin para especificar un parmetro de llamada por referencia. Esto no es una coincidencia. Recuerde que un argumento de llamada por referencia se implementa dando la direccin del argumento a la funcin invocadora. As pues, estos dos usos del smbolo & son bsicamente el mismo. 5. Apuntadores en instrucciones de asignacin. Podemos asignar el valor de una variable de apuntador a otra variable de apuntador. Esto copia una direccin de una variable de apuntador a otra. Por ejemplo, si ptr1 todava est apuntando a var1, lo siguiente establecer el valor de ptr2 de modo que tambin apunte a var1:
ptr2 = ptr1;

Siempre que no hayamos modificado el valor de var1, lo siguiente tambin desplegar 100 en la pantalla:
cout << *ptr2 << endl; // Imprimir el nmero 100.

Asegrese de no confundir:
ptr1 = ptr2;

con
*ptr1 = *ptr2;

Cuando aadimos el asterisco, no estamos tratando con los de apuntadores prt1 y ptr2, sino con las variables a las que estos apuntan. Esto se ilustra en las figuras siguientes.

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-3-

Universidad Nacional de Trujillo Ingeniera de Sistemas

Computacin Apuntadores

Antes: ptr1 var1 84 ptr2 var2 99 ptr1 = ptr2 ptr2 ptr1

Despus: var1 84 var2 99

Figura 2. Representacin grfica de: ptr1 = ptr2.

Antes: ptr1 var1 84 ptr2 var2 99 *ptr1 = *ptr2 ptr2 ptr1

Despus: var1 99 var2 99

Figura 3. Representacin grfica de: *ptr1 = *ptr2. 6. Apuntadores y funciones. Cuando se pasan argumentos a funciones, estos son pasados por valor, si el parmetro es modificado dentro de la funcin, una vez que termina la funcin el valor pasado de la variable permanece inalterado. Hay muchos casos que se requiere alterar el argumento pasado a la funcin y recibir el nuevo valor una vez que la funcin ha terminado. Para hacer lo anterior se debe usar una llamada por referencia, lo cual se puede simular pasando un puntero al argumento. Con esto se provoca que la computadora pase la direccin del argumento a la funcin. Ejemplo 1. Escriba un programa que intercambie el valor de dos variables. El intercambio debe realizarse dentro de una funcin a la cual se hace una llamada por referencia.
#include #include #include #include #include "stdafx.h" "iostream" "iomanip" <conio.h> <windows.h>

using namespace std; void leeValor(int &, char *); void intercambio(int *, int *); void imprime(int *, int *);

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-4-

Universidad Nacional de Trujillo Ingeniera de Sistemas


int _tmain(int argc, _TCHAR* argv[]) { int x, y; cout<<endl<<setw(30)<<"Intercambio de valores"<<endl; leeValor(x, "Valor de X: "); leeValor(y, "Valor de Y: "); cout<<endl<<endl<<"Presione una tecla para continuar..."; _getch(); system("cls"); cout<<endl<<endl<<setw(30)<<" Antes del intercambio "<<endl; imprime(&x, &y); intercambio(&x, &y); cout<<endl<<endl<<setw(30)<<"Despues del intercambio"<<endl; imprime(&x, &y); _getch(); return 0; } void leeValor(int &n, char *cad) { cout<<endl<<setw(15)<<cad; cin>>n; } void intercambio(int *pX, int *pY) { int temp; temp = *pX; *pX = *pY; *pY = temp; } void imprime(int *pX, int *pY) { cout<<endl<<setw(10)<<"X: "<<setw(5)<<*pX<<endl; cout<<endl<<setw(10)<<"Y: "<<setw(5)<<*pY<<endl; }

Computacin Apuntadores

7.

Apuntadores y arreglos. El nombre de un arreglo sin ndice representa la direccin del primer elemento del arreglo: Si se tiene: Entonces:
char p[10]; p representa &p[0];

Una variable arreglo puede ser utilizada como si fuera un apuntador, y cualquier apuntador inicializado con la direccin de un elemento de un arreglo (generalmente el primero) puede utilizarse como si estuviera declarado como arreglo:
int *ptr1, a[10]; ptr1 = a;

Entonces:
a[5] = 100;

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-5-

Universidad Nacional de Trujillo Ingeniera de Sistemas Es lo mismo que:


*(a + 5) = 100;

Computacin Apuntadores

Ejemplo 2. Escriba un programa que permita ingresar nmeros enteros en un arreglo, los ordene ascendentemente y luego los reporte.
#include #include #include #include #include "stdafx.h" "iostream" "iomanip" <conio.h> <windows.h>

using namespace std; void ingreso(int [], int); void ordena(int [], int); void reporte(int [], int); const int TAM=20; int _tmain(int argc, _TCHAR* argv[]) { int a[TAM], n; cout<<endl<<setw(40)<<"Puntero a arreglo de enteros"<<endl; do { cout<<endl<<"Numero de elementos (1-"<<TAM<<"): "; cin>>n; }while(n<1 || n>TAM); system("cls"); cout<<endl<<setw(40)<<"Ingreso de datos al arreglo"<<endl; ingreso(a, n); cout<<endl<<"Termino el ingreso de datos."<<endl <<"Presione una tecla para continuar..."; _getch(); system("cls"); ordena(a, n); cout<<endl<<setw(40)<<"Listado ordenado ascendentemente"<<endl; reporte(a, n); _getch(); return 0; } void ingreso(int *pA, int n) { cout<<endl; for(int i=0; i<n; i++) { cout<<"Elemento "<<(i+1)<<": "; cin>>*pA; ++pA; } } void ordena(int *pA, int n) { int *pB, temp; pB = pA; for(int i=0; i<n-1; i++) { for(int j=i; j<n; j++) { if(*pA > *pB) { temp = *pA;

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-6-

Universidad Nacional de Trujillo Ingeniera de Sistemas


*pA = *pB; *pB = temp; } ++pB; } ++pA; pB = pA; } } void reporte(int *pA, int n) { cout<<endl<<endl; for(int i=0; i<n; i++) cout<<setw(10)<<"A["<<i<<"]: "<<setw(5)<<pA[i]<<endl; }

Computacin Apuntadores

En este ejemplo la funcin ordenAscendente(int *ptrA, int n) tambin pudo haberse escrito de la siguiente manera:
void ordenAscendente(int *ptrA, int n) { int *ptrAux, aux; ptrAux = ptrA; for(int i=0; i<n-1; i++) { for(int j=i+1; j<n; j++) { if(ptrA[i] > ptrAux[j]) { aux = ptrA[i]; ptrA[i] = ptrAux[j]; ptrAux[j] = aux; } } } }

8.

Apuntadores y matrices. Si declaramos una matriz int M[10][10], M[i] representa &M[i][0], siendo i un entero de 0 a 9. Cuando se pasa un arreglo bidimensional a una funcin se debe especificar el nmero de columnas el nmero de filas es irrelevante. La razn de lo anterior, es nuevamente los apuntadores. El compilador requiere conocer cuntas son las columnas para que pueda saltar de fila en fila en la memoria. Considerando que una funcin deba recibir int M[5][10], se puede declarar el argumento de la funcin como:
funcionX(int M[][10]) { }

o an:
funcionX(int (*M)[10]) { }

En la ltima sentencia se requieren los parntesis (*M) ya que los corchetes tienen una precedencia ms alta que el asterisco. Ejemplo 3. Escriba un programa que lea lneas de texto hasta encontrar una lnea en blanco, entonces vuelve a mostrar cada lnea de dos maneras: caracter a caracter e indexando slo la primera dimensin y utilizando el formato cadena.
#include "stdafx.h" #include "iostream" #include "iomanip"

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-7-

Universidad Nacional de Trujillo Ingeniera de Sistemas


#include <conio.h> #include <windows.h> using namespace std; const int MAX = 100; const int longitud = 80; void ingreso(char (*)[longitud], int &); void mostrarCaracteres(char (*)[longitud], int); void mostrarLineas(char (*)[longitud], int);

Computacin Apuntadores

int _tmain(int argc, _TCHAR* argv[]) { char texto[MAX][longitud]; int i; cout<<endl<<setw(40)<<"Ingreso de lineas de texto"<<endl; cout<<endl<<"Ingrese una linea en blanco para terminar..." <<endl<<endl; ingreso(texto,i); system("cls"); cout<<endl<<setw(40)<<"Texto mostrado caracter a caracter" <<endl<<endl; mostrarCaracteres(texto, i); cout<<endl<<endl<<setw(48)<<"Texto mostrado con el formato de cadena" <<endl<<endl; mostrarLineas(texto, i); _getch(); return 0; } void ingreso(char (*ptrT)[longitud], int &i) { cout.setf(ios::left); for(i=0; i<MAX; i++) { cout<<setw(6)<<"Linea"<<setw(2)<<(i+1)<<setw(3)<<":"; cin.getline(ptrT[i], 80); if(!*ptrT[i]) // Equivale a *&texto[t][0] break; } cout<<resetiosflags(ios::left); } void mostrarCaracteres(char (*ptrT)[longitud], int i) { cout.setf(ios::left); for(int t=0; t<i; t++) { cout<<setw(6)<<"Linea"<<setw(2)<<(t+1)<<setw(3)<<":"; for(int j=0; ptrT[t][j]; j++) cout<<setw(2)<<ptrT[t][j]; cout<<endl; } cout<<resetiosflags(ios::left); } void mostrarLineas(char (*ptrT)[longitud], int i) { cout.setf(ios::left); for(int t=0; t<i; t++) cout<<setw(6)<<"Linea"<<setw(2)<<(t+1)<<setw(3)<<": "<<ptrT[t] <<endl; cout<<resetiosflags(ios::left); }

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-8-

Universidad Nacional de Trujillo Ingeniera de Sistemas

Computacin Apuntadores

Ejemplo 4. Escriba un programa que permita, haciendo uso de apuntadores, ingresar nmeros en una matriz y luego reporte los datos ingresados.
#include #include #include #include "stdafx.h" "iostream" "iomanip" <conio.h>

using namespace std; const int TAM = 10; void dimension(int &, char *); void ingreso(int (*)[TAM], int, int); void reporte(int (*)[TAM], int, int); int _tmain(int argc, _TCHAR* argv[]) { int a[TAM][TAM], fil, col; cout<<endl<<setw(40)<<"Puntero a Matriz de numeros"<<endl<<endl; cout.setf(ios::left); dimension(fil, "Numero de filas: "); dimension(col, "Numero de columnas: "); cout<<resetiosflags(ios::left); system("cls"); cout<<endl<<setw(30)<<"Ingreso de datos a la matriz"<<endl<<endl; ingreso(a, fil, col); cout<<endl<<endl<<"Termino ingreso de datos" <<endl<<"Presione una tecla para continuar..."<<endl; _getch(); system("cls"); cout<<endl<<setw(30)<<"Reporte de datos de la matriz"<<endl<<endl; reporte(a, fil, col); _getch(); return 0; } void dimension(int &dim, char *cad) { do { cout<<setw(20)<<cad; cin >> dim; }while(dim <= 0 || dim >= TAM); } void ingreso(int (*ptrA)[TAM], int fil, int col) { for(int i=0; i<fil; i++) { for(int j=0; j<col; j++) { cout<<setw(7)<<"M[" << i << "][" << j << "]: "; cin>>(*ptrA)[j]; } ++ptrA; } } void reporte(int (*ptrA)[TAM], int fil, int col) { for(int i=0; i<fil; i++) { for(int j=0; j<col; j++) cout<<setw(7)<<ptrA[i][j]; cout<<endl; } }

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

-9-

Universidad Nacional de Trujillo Ingeniera de Sistemas 9. Apuntadores y arreglos de estructuras.

Computacin Apuntadores

Para trabajar sobre un arreglo de estructuras se aplican los mismos mecanismos que para trabajar con un arreglo de nmeros enteros por ejemplo, haciendo la salvedad que en la estructura no se asigna un nico valor sino tantos valores como miembros se hayan definido en ella. Ejemplo 5. Escriba un programa que permita, haciendo uso de estructuras y apuntadores, ingresar el nombre y la edad de N personas, y que luego reporte dichos datos ordenados ascendentemente por el nombre.
#include #include #include #include #include #include "stdafx.h" "iostream" "iomanip" <string.h> <conio.h> <windows.h>

using namespace std; struct datos { char nombre[30]; int edad; }; const int TAM = 20; void void void void numeroPersonas(int &); ingreso(datos [], int); ordenaPorNombre(datos [], int); reporte(datos [], int);

int _tmain(int argc, _TCHAR* argv[]) { datos d[TAM]; int n; cout<<endl<<setw(50)<<"Arreglo de estructuras"<<endl<<endl; numeroPersonas(n); system("cls"); cout<<endl<<endl<<setw(30)<<"Ingreso de datos"<<endl<<endl; ingreso(d, n); cout<<endl<<endl<<"Termino el ingreso de datos." <<endl<<"Presione una tecla para continuar..."; _getch(); system("cls"); cout<<endl<<endl<<setw(30)<<"Listado original"<<endl<<endl; reporte(d, n); cout<<endl<<endl<<setw(35)<<"Listado ordenado por nombre" <<endl<<endl; ordenaPorNombre(d,n); reporte(d,n); _getch(); return 0; } void numeroPersonas(int &n) { do { cout<<"Numero de personas (1-"<<TAM<<"): "; cin>>n; }while(n<1 || n>TAM); cin.get(); }

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

- 10 -

Universidad Nacional de Trujillo Ingeniera de Sistemas


void ingreso(datos *pD, int n) { for(int i=0; i<n; i++) { cout<<endl<<"Datos de persona "<<(i+1)<<endl; cout<<"Nombre: "; cin.getline(pD[i].nombre, 30); cout<<"Edad: "; cin>>pD[i].edad; cin.get(); } } void ordenaPorNombre(datos *pD, int n) { datos *pAux, temp; pAux = pD; for(int i=0; i<n-1; i++) { for(int j=i; j<n; j++) { if(strcmp(pD->nombre, pAux->nombre)>0) { temp = *pD; *pD = *pAux; *pAux = temp; } ++pAux; } ++pD; pAux = pD; } }

Computacin Apuntadores

void reporte(datos *pD, int n) { cout.setf(ios::left); cout<<setw(5)<<""<<setw(30)<<"Nombre"<<setw(5)<<"Edad"<<endl; for(int i=0; i<n; i++) cout<<setw(5)<<""<<setw(30)<<pD[i].nombre<<setw(5)<<pD[i].edad <<endl; cout<<resetiosflags(ios::left); }

10. Arreglos de apuntadores. Los apuntadores pueden estructurarse en arreglos como cualquier otro tipo de dato. La declaracin para un arreglo de punteros a enteros de tamao 10 es:
int *a[10];

Para asignar la direccin de una variable entera llamada num al tercer elemento del arreglo de punteros, se debe indicar:
a[2] = &num;

Para referirse al valor de num:


*a[2]

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

- 11 -

Universidad Nacional de Trujillo Ingeniera de Sistemas 11. Aritmtica de apuntadores.

Computacin Apuntadores

Slo se puede realizar suma y resta de apuntadores. Cada vez que la variable apuntador se incrementa, apunta a la direccin de memoria del siguiente elemento de su tipo base. Cada vez que la variable apuntador disminuye, apunta a la posicin del elemento anterior. Tambin se les puede sumar y restar enteros a los apuntadores, considerando siempre que lo que se suma y se resta son posiciones de tipo base:
int *ptr1; ptr1 = ptr1 + 9;

Dado que la variable ptr1 es de tipo apuntador a entero de 4 bytes, luego de la suma, apuntar 36 (9 x 4) bytes mas all del valor inicial. La razn por la cual se asocia un apuntador a un tipo de dato, es por que se debe conocer en cuantos bytes est guardado el dato. De tal forma, que cuando se incrementa un apuntador, se incrementa el apuntador por un bloque de memoria, en donde el bloque est en funcin del tamao del dato. Por lo tanto para un apuntador a un char, se agrega un byte a la direccin y para un apuntador a int o a float se agregan 4 bytes. De esta forma si a un apuntador a float se le suma 2, el apuntador entonces se mueve dos posiciones float que equivalen a 8 bytes. 12. Apuntadores a apuntadores. Denominado tambin indireccin mltiple o encadenamiento de punteros.
int *ptr1; int **ptr2; // Se declara un apuntador a un entero. // Se declara apuntador a otro apuntador.

La forma de asignarles valores sera:


int var1, *ptr1, **ptr2; var1 = 10; // Se asigna valor a var1. ptr1 = &var1; // El apuntador ptr1 recibe la direccin de var1. ptr2 = &ptr1; // El apuntador ptr2 recibe la direccin de ptr1.

Ing. Zoraida Yanet Vidal Melgarejo, Mg.

- 12 -

Você também pode gostar