Documentos de Académico
Documentos de Profesional
Documentos de Cultura
PUNTEROS
PUNTEROS
Los punteros en C++ sirven para señalar objetos, y también para manipularlos.
Para entender qué es un puntero veremos primero cómo se almacenan los datos en un
ordenador.
Memoria de un bit de ferrita.
Recordemos q la memoria de un ordenador está compuesta por unidades básicas llamadas bits.
Cada bit sólo puede tomar dos valores, normalmente denominados alto y bajo, ó 1 y 0. Pero
trabajar con bits no es práctico, y por eso se agrupan.
Cada grupo de 8 bits forma un byte u octeto. En realidad el microprocesador, y por lo tanto
nuestro programa, sólo puede manejar directamente bytes o grupos de dos o cuatro bytes. Para
acceder a los bits hay que acceder antes a los bytes.
Cada byte de la memoria de un ordenador tiene una dirección, llamada dirección de memoria.
Por otra parte, la mayor parte de los objetos que usamos en nuestros programas no caben en
una dirección de memoria. La solución utilizada para manejar objetos que ocupen más de un
byte es usar posiciones de memoria correlativas. De este modo, la dirección de un objeto es la
dirección de memoria de la primera posición que contiene ese objeto.
Dicho de otro modo, si para almacenar un objeto se precisan cuatro bytes, y la dirección de
memoria de la primera posición es n, el objeto ocupará las posiciones desde n a n+3, y la
dirección del objeto será, también, n.
PUNTERO
S
Intentemos ver con mayor claridad el funcionamiento de los punteros. Podemos
considerar la memoria del ordenador como un gran array, de modo que podemos
acceder a cada celda de memoria a través de un índice. Podemos considerar que la
primera posición del array es la 0 celda[0].
tipo *nombre_variable[tamaño];
xyz xyz
Qwertyuiopasdfg Qwertyuiopasdfg
Abcdefghi Abcdefghi
1
OBTENER PUNTEROS A OBJETOS
Ejemplos:
int *pEntero;
char *pCaracter;
struct stPunto *pPunto;
Los punteros sólo pueden apuntar a objetos de un tipo determinado, en el ejemplo, pEntero sólo puede
apuntar a un objeto de tipo int.
La forma:
<tipo>* <identificador>;
con el (*) junto al tipo, en lugar de junto al identificador del objeto, también está permitida. De hecho,
también es legal la forma:
<tipo> * <identificador>;
Los punteros apuntan a objetos, por lo tanto, lo primero que tenemos que saber hacer con nuestros
punteros es asignarles direcciones de memoria válidas de objetos.
Para averiguar la dirección de memoria de cualquier objeto usaremos el operador de dirección (&),
que leeremos como "dirección de".
Por supuesto, los tipos tienen que ser "compatibles", no podemos almacenar la dirección de un objeto
de tipo char en un puntero de tipo int.
Por ejemplo:
int A;
int *pA;
pA = &A;
Según este ejemplo, pA es un puntero a int que apunta a la dirección donde se almacena el valor del
EJEMPLO
1 #include <iostream>
#include <conio.h>
using namespace std;
int main(){
cout << "El numero es:"<< *dir_numero<< endl; //mostrar el valor guardado en la
posición
cout << "El numero es:"<< &numero<< endl;
cout << "La direccion de la memoria:"<< dir_numero<< endl;
getch();
return 0;
}
EJEMPLO
#include <iostream>
2 #include <conio.h>
using namespace std;
int main(){
if (*dir_numero%2==0){
cout << "El numero "<< *dir_numero<<" es par"<< endl; //mostrar el valor guardado
en la posicion
cout << "La posicion en memoria: "<< dir_numero<< endl;
}
else{
cout << "El numero "<< *dir_numero<<" es impar"<< endl; //mostrar el valor
guardado en la posicion
cout << "La posicion en memoria: "<< dir_numero<< endl;
}getch();
return 0;
}
PUNTEROS CON ARREGLOS O ARRAY
Hemos visto que los arrays pueden ser una potente herramienta para el
almacenamiento y tratamiento de información, pero tienen un inconveniente: hay que
definir su tamaño durante el diseño del programa, y después no puede ser modificado.
La gran similitud de comportamiento de los punteros y los arrays nos permiten crear
arrays durante la ejecución, y en este caso además el tamaño puede ser variable.
Usaremos un puntero normal para crear vectores dinámicos, uno doble para tablas, etc.
Por ejemplo, crearemos una tabla dinámicamente. Para ello se usan los punteros a
punteros. Veamos la declaración de un puntero a puntero:
int **tabla;
"tabla" es un puntero que apunta a un objeto de tipo puntero a int.
Sabemos que un puntero se comporta casi igual que un array, por lo tanto nada nos
impide que "tabla" apunte al primer elemento de un array de punteros:
int n = 134;
tabla = new int*[n];
EJEMPLO
1 #include <iostream>
#include <conio.h>
using namespace std;
int main(){
int numero[]={1,2,3,4,5};
int *dir_numero; //creo puntero tipo entero
int main( )
{
cout<<"\t\t\tBIENVENIDOS AL SISTEMA DE NOTAS"<< endl;
solicitar_notas();
mostrar_notas();
delete[] pnotas;
getch();
system("pause");
return 0;
void solicitar_notas(){
cout<<"Introduzca las cantidad de notas a registrar\n";
cin >> cantidad_notas;
pnotas = new int[cantidad_notas]; // creo arreglo y reservo la primera posicion
for (int i = 0; i <cantidad_notas; i++){
cout<<"Ingrese la notas \n";
cin >> pnotas[i];
}
}
void mostrar_notas(){
cout<<"Las notas son: \n";
for (int i = 0; i <cantidad_notas; i++){
cout<< pnotas[i]<< endl;
}
}
ARGUMENTOS EN LA FUNCIÓN MAIN
ertyuiopasdfg\0
cdefghi\0
0
1
ARGUMENTO DE MAIN()
Línea de órdenes
23
EJEMPLO
1
#include <iostream>
using namespace std;
23
ESTRUCTURAS
ESTRUCTURAS
Las estructuras son el segundo tipo de datos estructurados. Al contrario que los arrays,
las estructuras nos permiten agrupar varios datos, que mantengan algún tipo de
relación, aunque sean de distinto tipo, permitiendo manipularlos todos juntos, usando
un mismo identificador, o cada uno por separado.
Las estructuras son llamadas también muy a menudo registros, o en inglés records.
Tienen muchos aspectos en común con los registros usados en bases de datos. Y
siguiendo la misma analogía, cada objeto de una estructura se denomina a menudo
campo, o field. struct [<identificador>] { [<tipo>
Sintaxis: <nombre_objeto>[,<nombre_objeto>,...]]; }
[<objeto_estructura>[,<objeto_estructura>,.
..];
struct Persona {
char Nombre[65];
char Direccion[65];
int AnoyNacimiento;
} Fulanito;
void GuardaB(int n) {
B = n;} // Asigna un nuevo valor a B
} Par;
int main() {
Par.GuardaA(15);
Par.GuardaB(63);
cout << Par.LeeA() << endl;
cout << Par.LeeB() << endl;
return 0; }
INICIALIZACION DE ESTRUCTURAS
De un modo parecido al que se inicializan los arrays, se pueden inicializar estructuras,
tan sólo hay que tener cuidado con las estructuras anidadas. Por ejemplo:
struct A {
int i;
int j;
int k;
};
struct B {
int x;
struct C {
char c;
char d;
} y;
int z;
};
int main() {
Punto1.x = 10;
Punto1.y = 12;
Punto2 = Punto1;
}
La línea Punto2 = Punto1; equivale a Punto2.x = Punto1.x; Punto2.y =
Punto1.y;.
ASIGNACION DE ESTRUCTURAS
Mediante este constructor podemos asignar valores iniciales en la declaración:
complejo c1(10.23, 213.22);
Los números reales se consideran un subconjunto de los imaginarios, en los que la parte
imaginaria vale cero. Esto nos permite crear otro constructor que sólo admita un valor real:
struct complejo {
complejo() { real=0; imaginario = 0; }
complejo(double r, double i) { real=r; imaginario = i; }
complejo(double r) { real=r; imaginario = 0; }
double real;
double imaginario;
};
Este constructor nos permite, como en el caso anterior, inicializar un valor de un complejo en la
declaración, pero también nos permite asignar un valor double a un complejo, y por el sistema
de promoción automático, también podemos asignar valores enteros o en coma flotante:
complejo c1(19.232);
complejo c2 = 1299.212;
int x = 10;
complejo c3 = x;
Este tipo de constructores se comportan como conversores de tipo, nada nos impide crear
constructores con cualquier tipo de parámetro, y tales constructores se podrán usar para
convertir cualquier tipo al de nuestra estructura.
ARRAY DE ESTRUCTURAS
La combinación de las estructuras con los arrays proporciona una potente
herramienta para el almacenamiento y manipulación de datos.
Ejemplo:
struct Persona {
char Nombre[65];
char Direccion[65];
int AnoyNacimiento;
} Plantilla[200];
Vemos en este ejemplo, declarar el array Plantilla que contiene los datos relativos a
doscientas personas.
Podemos acceder a los datos de cada uno de ellos:
cout << Plantilla[43].Direccion;
O asignar los datos de un elemento de la plantilla a otro:
Plantilla[0] = Plantilla[99];
ESTRUCTURAS ANIDADAS
También está permitido anidar estructuras. Ejemplo:
struct stDireccion {
char Calle[64];
int Portal;
int Piso;
char Puerta[3];
char CodigoPostal[6];
char Poblacion[32];
};
struct stPersona {
struct stNombre {
char Nombre[32];
char Apellidos[64];
} NombreCompleto;
stDireccion Direccion;
char Telefono[10];
};
...
Por ejemplo para declarar un objeto del tipo stNombre hay que utilizar el operador de acceso (::):
stPersona::stNombre NombreAuxiliar;
Sin embargo para declarar un objeto de tipo stDireccion basta con declararla:
stDireccion DireccionAuxiliar;
PROBLEMA PROPUESTO