Programación en C++/Punteros
De Wikilibros, la colección de libros de texto de contenido libre.
Editores:
| ← Funciones virtuales | ← Estructuras II |
Contenido |
[editar] Punteros
Los punteros permiten simular el paso por referencia, crear y manipular estructuras dinamicas de datos, tales como listas encadenadas, pilas, colas y árboles. Generalmente las variables contienen valores especificos. Los punteros son variables pero en vez de contener un valor especifico, contienen las direcciones de las variables a las que apuntan. Para obtener o modificar el valor de la variable a la que apuntan se utiliza el operador de indirección. Los punteros, al ser variables deben ser declaradas como punteros antes de ser utilizadas.
[editar] Sintaxis
int *ptrID, ID; ID = 8; ptrID = &ID;
ptrID es un puntero a int, mientras que la variable ID es solo una variable del tipo int. Todo puntero debe ser precedido por un asterisco (*).
Esto se representa graficamente de la siguiente manera:
Se puede declarar mas de un puntero en la misma sentencia. En el ejemplo que sigue se ve la declaración de dos punterons a int.
int *ptrY, *ptrX;
[editar] Operadores
Existen dos operadores a tener en cuenta cuando trabajamos con punteros. El operador de dirección (&) que devuelve la dirección de memoria de su operando y el operador de indirección (*) que devuelve un alias para el objeto al cual apunta el operando del puntero.
En el siguiente ejemplo vemos como se inicializa una variable X con el valor 15. Luego se crea un puntero a int y por último el puntero pasa a apuntar a la variable X. Esto es, ptrX es un puntero a X.
int X = 15; int *ptrX; ptrX = &X;
[editar] Punteros y matrices
Las matrices son punteros constantes. Una matriz sin subindice es un puntero al primer elemento de la matriz.
int X[15]; int *ptrX; ptrX = X; // ptrX recibe la dirección del primer elemento ( 0 ) de X
Asi como tambien podria escribirse
int X[15]; int *ptrX; ptrX = &X[0]; // ptrX es igual a la dirección del primer elemento de X
Se pueden utilizar distintos elementos de la matriz teniendo en cuenta la sintaxis de punteros.
int X[15], Y, *ptrX; ptrX = X; Y = *( ptrX + 7 );
En este caso puede verse que Y toma el valor del elemento 7 de la matriz X, siendo 7 el desplazamiento dentro de la matriz. El operador de indirección queda fuera del parentesis porque tiene una prioridad superior a la del operador +. De no existir los parentesis, se sumaria 7 al elemento X[0]. Teniendo en cuenta que las matrices son punteros constantes, el nombre de la matriz puede tratarse como un puntero:
Y = *( X + 7 );
[editar] Aritmética de Punteros
Al usar punteros a matrices, hay que tener en cuenta que la aritmética cambia sensiblemente.
#include <iostream> using std::cout; using std::endl; void main() { int X[6] = { 1, 2, 3, 4, 5, 6 }; int *prtX; prtX = X; // incializo el valor del puntero. cout << endl << *prtX; prtX += 2; cout << endl << *prtX; prtX -= 2; cout << endl << *prtX; prtX++; cout << endl << *prtX; }
En el siguiente código, primero se crea un puntero a un arreglo de 6 elementos y si inicializa el puntero prtX al primer elemento del arreglo X[0]. Si tenemos en cuenta que el siguiente ejemplo se ejecuta en una computadora con enteros de 4 bytes, el segundo elemento de la matriz tendrá en memoria un desplazamiento de 4 bytes, el 2 de ocho y asi sucesivamente. La operación prtX += 2; produce un desplazamiento llevándolo al 3 elemento dentro del arreglo. Debe entenderse que prtX ahora apunta a una dirección de memoria y la instrucción cambia esta dirección de memoria sumándole 2 multiplicado por el tamaño del tipo de dato del arreglo que en este supuesto sería de 4. (dir = ( dir + 2 * 4 )), dando por resultado un desplazamiento de 8 bytes. Sería igual que ejecutar la operación prtX = &X[2];. La operación prtX -= 2 obedece a la misma lógica estableciendo el puntero al primer elemento del array X[0] y el operador ++ modifica el puntero desplazándolo 4 bytes y asignándole el segundo elemento de la matriz.
[editar] Matrices de punteros
Para realizar una estructura de datos dinámica, se puede utilizar una matriz donde sus elementos sean punteros. Suponiendo que queramos hacer un calendario y lo dividamos por semanas. Podríamos utilizar una matriz con los días de la semana.
const char *dias[7] = { "Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado" }
Cada día de la semana, no es un elemento de la matriz, sino que la expresión dias[7] crea una matriz de siete elementos como punteros a char.
[editar] Formas de pasar un valor por referencia
Un puntero no constante a un dato no constante
#include <iostream> void sumoeldoble( int * ); // prototipo void main () { int X = 15; sumoeldoble( &X ); // Pasa la dirección de memoria de X . std::cout << X; } void sumoeldoble( int *ptrX ) { // Toma el valor de X mediante el operador de indirección // La funcion no devuelve nada porque modifica el valor por referencia. *ptrX = *ptrX + ( *ptrX * 2 ); }
Un puntero no constante a un dato constante
#include <iostream> void imprimeChars( const char * ); // prototipo void main () { char cFrase[] = "Hola Mundo"; imprimeChars( cFrase ); } void imprimeChars( const char *ptrStr ) { for ( ; *ptrStr != '\0'; ptrStr++ ) //Sin inicialización std::cout << *ptrStr; }
Un puntero constante a un dato no constante
Un puntero es constante cuando apunta siempre a la misma dirección de memoria y si el dato no es constante entonces el valor puede ser modificado.
void main () { int foo, bar; int * const ptrFoo = &foo; // Apuntador constante a un entero en la dirección de memoria de foo *ptrFoo = 53; // Esto devuelve un error porque es un puntero constante. // No se puede alterar la dirección de memoria a la que apunta. ptrFoo = &bar; }
Un puntero constante a un dato constante
El puntero constante apunta siempre a la misma dirección de memoria y el valor al que apunta dicho puntero no puede ser modificado mediante el puntero. Este es el metodo en que se debe pasar matrices a funciones que solo leen lamatriz y no la modifican.
#include <iostream> using namespace std; int main () { int foo = 3, bar; const int * const ptrFoo = &foo; cout << foo; *ptrFoo = 53; //Error porque no puede alterarse el valor ptrFoo = &bar; // Error foo = 23; cout << foo; }
[editar] Punteros a funciones
Teniendo en cuenta que el nombre de una función es en verdad la dirección de memoria donde comienza el código, los punteros a funciones contienen la dirección de memoria de la función a la que apunta, y se pueden pasar y retornar entre funciones.
#include <iostream> using namespace std; bool functionA( int, int, bool (*)( int ) ); //Prototipo bool functionB( int ); //Prototipo void main() { int x = 113, y = 226; if ( functionA( x, y, functionB ) ) cout << "\nEl resultado es verdadero"; else cout << "\nEl resultado es falso"; } bool functionA( int param1, int param2, bool (*verificar)( int ) ) { if ( ( (*verificar)( param1 ) ) && ( (*verificar)( param2 ) ) ) return true; } bool functionB( int param ) { if ( param > 100 ) return true; else return false; }
En el ejemplo anterior podrá ver que en la definición de los prototipos, la función functionA recibe tres parámetros, siendo el tercer parámetro un puntero a la funcion functionB, practicamente copiando el prototipo sin el nombre. Cuando se ejecuta functionA, se le pasa como parametro el nombre de la función
[editar] Ordenamiento burbuja
Ordenamiento burbuja utilizando punteros
#include <iostream> #include <iomanip> using namespace std; void orden( int *, const int ); // prototipo void swap( int * const, int * const ); // prototipo int main() { const int nSize = 10; int a[ nSize ] = { 3, 9, 14, 27, 18, 154, 8, 6, 74, 33 }; cout << "\nElementos a ordenar\n"; for ( int j = 0; j < nSize; j++ ) cout << setw( 5 ) << a[ j ]; orden( a, nSize ); // ordena el arreglo cout << "\nElementos ordenados\n"; for ( int j = 0; j < nSize; j++ ) cout << setw( 5 ) << a[ j ]; cout << endl; return 0; // indica terminación exitosa } void orden( int *matriz, const int nSize ) { for ( int pasada = 0; pasada < nSize - 1; pasada++ ) { for ( int k = 0; k < nSize - 1; k++ ) { if ( matriz[ k ] > matriz[ k + 1 ] ) { swap( &matriz[ k ], &matriz[ k + 1 ] ); } } } } void swap( int * const ptrElemento1, int * const ptrElemento2 ) { int mantiene = *ptrElemento1; *ptrElemento1 = *ptrElemento2; *ptrElemento2 = mantiene; }
[editar] Proyecto de colas para un banco
Por cada 2 clientes normales pasa uno VIP al Cajero
El codigo es muy simple pero muy trabajado y depurado, esta relizado con if/while.... lo mas complicado son los apuntadores, pero nada del otro mundo, muestra el perfecto uso de funciones, tiene una clave: jahvi, de todas lo puedes leer en el codigo. Compila perfecto en DEV C++. Tiene una interfaces muy creativa, ideal estudian tes que se estan inciando en el desarrollo de software con programacion estructurada. recuerda copiarlo en un pagina en blanco en dev c++ desde aqui: (copialo completo y compilalo)
#include <stdio.h> #include <iostream.h> #include <conio.h> #include <stdlib.h> #include <string.h> using namespace std; typedef struct nodo { int cedula; struct nodo*siguiente; }tiponodo; typedef tiponodo *pnodo; typedef tiponodo *cola; cola cola_n=NULL; cola cola_vip=NULL; int solic; void insertar (cola *cola_n) { cola aux, creado; creado=(pnodo)malloc(sizeof(tiponodo)); cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl; cout<<" ||||||||||||||||||||METROPOLI banco universal||||||||||||||||||||"<<endl; cout<<" |||||||||||||||||||||||Le da la bienvenida|||||||||||||||||||||||"<<endl; cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl; cout<<" Estimado cliente: Introduzca su numero de cedula"<<endl; cin>> creado->cedula; cout<<" Pronto sera atendido"<<endl; if ((*cola_n)==NULL) { creado->siguiente=*cola_n; *cola_n=creado; } else { aux=*cola_n; while(aux!=NULL) { if(aux->siguiente==NULL) { creado->siguiente=aux->siguiente; aux->siguiente=creado; aux=aux->siguiente; } aux=aux->siguiente; } } } void mostrar_cola (cola cola_n) { cola aux; aux=cola_n; if(aux==NULL) { cout<<"No hay clientes en cola"<<endl; } else { while(aux!=NULL) { cout<<"Cedula: "<<aux->cedula<<endl; cout<<""<<endl; aux=aux->siguiente; cout<<"* Clientes ordenados por orden de llegada((((((SIMCOLAS))))))"<<endl; } } } //modificado hasta acá... falta de orden por parte del creador void insertar_vip (cola *cola_vip){ cola aux_2, creado_vip; creado_vip=(pnodo)malloc(sizeof(tiponodo)); cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl;//62 cout<<" ||||||||||||||||||||METROPOLI banco universal||||||||||||||||||||"<<endl; cout<<" |||||||||||||||||||||||Le da la bienvenida|||||||||||||||||||||||"<<endl; cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl; cout<<" Estimado cliente: Introduzca su numero de cedula"<<endl; cin>> creado_vip->cedula; cout<<" Pronto sera atendido"<<endl; if ((*cola_vip)==NULL){ creado_vip->siguiente=*cola_vip; *cola_vip=creado_vip; }else{ aux_2=*cola_vip; while(aux_2!=NULL){ if(aux_2->siguiente==NULL){ creado_vip->siguiente=aux_2->siguiente; aux_2->siguiente=creado_vip; aux_2=aux_2->siguiente; } aux_2=aux_2->siguiente; } } } void mostrar_cola_vip (cola cola_vip){ cola aux_2; aux_2=cola_vip; if(aux_2==NULL){ cout<<"No hay clientes V.I.P en cola"<<endl; }else{ while(aux_2!=NULL){ cout<<"Cedula: "<<aux_2->cedula<<endl; cout<<""<<endl; cout<<"* Clientes ordenados por orden de llegada((((((SIMCOLAS))))))"<<endl; aux_2=aux_2->siguiente; } } } void pop (cola *cola_n){ if((*cola_n)==NULL){ cout<<"No hay clientes en cola ((((((SIMCOLAS))))))"<<endl; cout<<""<<endl; } if((*cola_n)!=NULL){ cout<<"Cliente: "<<(*cola_n)->cedula; cout<<" es su turno"<<endl; *cola_n=(*cola_n)->siguiente; free(cola_n); system("PAUSE"); cout<<""<<endl; } if((*cola_n)==NULL){ cout<<"No hay clientes en cola ((((((SIMCOLAS))))))"<<endl; cout<<""<<endl; }else{ cout<<"Cliente: "<<(*cola_n)->cedula; cout<<" es su turno"<<endl; *cola_n=(*cola_n)->siguiente; free(cola_n); system("PAUSE"); cout<<""<<endl; } } void pop_vip(cola *cola_vip){ if(cola_vip!=NULL){ cout<<"Cliente: "<<(*cola_vip)->cedula; cout<<" es su turno"<<endl; *cola_vip=(*cola_vip)->siguiente; free(cola_vip); }else{ cout<<"No hay usuarios V.I.P en cola ((((((SIMCOLAS))))))"<<endl; } } void menu(); void Insertar(); void insertar_vip(); void mostrar_cola(); void mostrar_colavip(); void solicitar_numero(); void salir(); struct perly{ char uxer[]; }data; struct perly *p = &data; int main(int argc, char *argv[]) { system("color 0a"); cout<<" * * * "<<endl; cout<<" * * "<<endl; cout<<" * | * * * * "<<endl; cout<<" * -+- * "<<endl; cout<<" __ | * * * * "<<endl; cout<<" ___| | * _|_ * ____ ____ "<<endl; cout<<" [_]|°°|__ _| |_ * | |....| |....| * * "<<endl; cout<<" | | _|[] []|_ ___ | |....| | ___|__ "<<endl; cout<<" [_]| °° |__|_ ______| | | |_| |....| || -- - | * * "<<endl; cout<<" |________ |__ | |# #| |_| |....| || - -- | _____ "<<endl; cout<<" [_]| _____ | |__[]| | | |_| |....|__|| -- - | |* * *| "<<endl; cout<<" | [___] | |__ |# #| |_| |....|__|| -- -_|_|* * *| "<<endl; cout<<" [_]| | °° | | |__| |__|....| || ___|* *|* * *| "<<endl; cout<<" | _____ | |__ #|_______|....| | |* *|* *|* * *| "<<endl; cout<<" [_]| [___] | °° |__|_______|__ | | |* *|* *|* * *| "<<endl; cout<<" | | __|_____________|__ |* *|* *|* * *| "<<endl; cout<<" [_]| _____ | °° _|___________________|_ |* *|* *|* * *| "<<endl; cout<<" | [___] | |_______________________| ______________ "<<endl; cout<<" __|_______|_________|_______________________| _________________ "<<endl; cout<<" |_______________________________________________________________|"<<endl; cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl;//62 cout<<" ||||||||||||||||||||METROPOLI banco universal||||||||||||||||||||"<<endl; cout<<" ||||||||||||Sistema Integral para el Manejo de COLAS|||||||||||||"<<endl; cout<<" |||||||||||||||||||||||||||||SIMCOLAS||||||||||||||||||||||||||||"<<endl; cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl; cout<<" |||||||||Creado por: Javier Rodriguez Caracas-Venezuela||||||||||"<<endl; cout<<" |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"<<endl; cout<<" Login: "; char usuario[6] = "jahvi"; cin.getline(p->uxer,6); if (strcmp(p->uxer,usuario) == 0) { cout<<"Bienvenid@ al sistema "<<endl; menu(); cout<<""<<endl; }else{ cout<<"Acceso Denegado. Consulte al Admisnistrador "<<endl; } system("PAUSE"); return EXIT_SUCCESS; } void menu() { short a; do { cout<<""<<endl; cout<< "0 - Agregar Cliente"<<endl; cout<< "1 - Agregar Cliente V.I.P"<<endl; cout<< "2 - Solicitar Numero"<<endl; cout<< "3 - Mostrar Cola"<<endl; cout<< "4 - Mostrar Cola V.I.P"<<endl; cout<< "5 - Salir del Sistema"<<endl; cout<<""<<endl; fflush(stdout); cout<<"Opcion #:"; cin>>a; cout<<""<<endl; if (a == 5) exit(1); switch(a){ case 0 : Insertar(); break; case 1 : insertar_vip(); break; case 2 : solicitar_numero(); break; case 3 : mostrar_cola(); break; case 4 : mostrar_colavip(); break; case 5 : salir(); break; default : puts("Usted no ha seleccionado nada, porfavor seleccione algo\n"); break; }; } while (1); } void Insertar(){ insertar(&cola_n); } void insertar_vip(){ insertar(&cola_vip); } void mostrar_cola(){ mostrar_cola(cola_n); } void mostrar_colavip(){ mostrar_cola_vip(cola_vip); } void solicitar_numero(){ pop(&cola_n); if(cola_vip!=NULL){ pop_vip(&cola_vip); }else{ cout<<"No hay cliente V.I.P en cola ((((((SIMCOLAS))))))"<<endl; } } void salir(){ }
| ← Funciones virtuales | Arriba | ← Estructuras II |