UNIDAD 3
PUNTEROS, REFERNCIAS Y ARREGLOS
3.1 CREACION
En C++ se puede crear un puntero genérico que puede recibir la dirección de cualquier tipo de dato.
La declaración de punteros utiliza un asterisco *, que en este caso actúa como calificador de tipo, en una sintaxis muy parecida a la utilizada en la declaración de objetos normales. En este capítulo nos referimos exclusivamente a declaración de punteros a objetos; la declaración de punteros a función será comentada en otro apartado. Cuando los punteros que señalan a miembros de clase (propiedades o métodos) presentan ciertas características especiales por lo que también serán tratados aparte.
La declaración de punteros utiliza un asterisco *, que en este caso actúa como calificador de tipo, en una sintaxis muy parecida a la utilizada en la declaración de objetos normales. En este capítulo nos referimos exclusivamente a declaración de punteros a objetos; la declaración de punteros a función será comentada en otro apartado. Cuando los punteros que señalan a miembros de clase (propiedades o métodos) presentan ciertas características especiales por lo que también serán tratados aparte.
En C++ se puede crear un puntero genérico que puede recibir la dirección de cualquier tipo de dato.
La declaración de punteros utiliza un asterisco *, que en este caso actúa como calificador de tipo, en una sintaxis muy parecida a la utilizada en la declaración de objetos normales. En este capítulo nos referimos exclusivamente a declaración de punteros a objetos; la declaración de punteros a función será comentada en otro apartado. Cuando los punteros que señalan a miembros de clase (propiedades o métodos) presentan ciertas características especiales por lo que también serán tratados aparte.
La declaración de punteros utiliza un asterisco *, que en este caso actúa como calificador de tipo, en una sintaxis muy parecida a la utilizada en la declaración de objetos normales. En este capítulo nos referimos exclusivamente a declaración de punteros a objetos; la declaración de punteros a función será comentada en otro apartado. Cuando los punteros que señalan a miembros de clase (propiedades o métodos) presentan ciertas características especiales por lo que también serán tratados aparte.
La sintaxis general de la declaración de puntero a objeto es: * [= ]
void main(){void *p;int a=1;double x=2.4;p=&a;p=&x; }
No se puede desreferenciar un puntero void.void main (){void *p;double x=2.5;p=&x;*p=3.6; // error: se desreferencia a un puntero void}
void main(){void *p;int a=1;double x=2.4;p=&a;p=&x; }
No se puede desreferenciar un puntero void.void main (){void *p;double x=2.5;p=&x;*p=3.6; // error: se desreferencia a un puntero void}
Los punteros siguen las reglas de creación y destrucción del resto de las variables, sin embargo hay que recordar que los objetos tienen duración independiente de los posibles que los señalan, de forma que cuando un puntero-a-objeto sale de ámbito, no se invoca implícitamente ningún destructor para el objeto señalado. A la inversa, la destrucción del objeto señalado no supone necesariamente la destrucción de los punteros que los referencian.
En la práctica pueden presentarse ambas circunstancias, ocasionando situaciones potencialmente peligrosas o erróneas. Por ejemplo, el primer caso puede ocurrir con objetos persistentes creados con los operadores new o new.
Este tipo de objetos son accesibles a través de un puntero, generalmente un objeto automático que es destruido automáticamente al salir de ámbito. Pero el objeto señalado permanece ocupando memoria, por lo que se hace necesaria una invocación explícita al operador delete para destruirlo antes que sea destruido el puntero, pues de lo contrario se produciría una perdida irrecuperable de memoria.
El segundo caso, la destrucción de un objeto sin que sean destruidos los punteros que lo señalan, también es bastante frecuente, dando lugar a los denominados punteros descolgados (“Dangling pointers”), cuyo uso inadvertido es especialmente .
3.2 OPERACIONES CON PUNTEROS
Un puntero es un tipo de dato similar a un entero, y hay un conjunto de operaciones definidas para punteros:
La suma o resta de un entero produce una nueva localización de memoria.
Se pueden comparar punteros, utilizando expresiones lógicas, para ver si están apuntando o no a la misma dirección de memoria.
La resta de dos punteros da como resultado el número de variables entre las dos direcciones.
Veamos cómo trabaja este programa:
princPunt es la dirección del primer elemento de vector, y finPunt la dirección del último elemento. int princPunt = vector; es una combinación de declaración y definición.
La expresión *(princPunt+2) incrementa el valor del puntero princPunt en dos y devuelve el número guardado en esa localización, es decir, apunta a la tercera localización de memoria y su valor es 15.
Se pueden utilizar también enteros en formato hexadecimal. Así,
cout << *(princPunt + 17 ) y cout << *(princPunt + 0x11 ) producen la misma salida.
Se pueden utilizar también enteros en formato hexadecimal. Así,
cout << *(princPunt + 17 ) y cout << *(princPunt + 0x11 ) producen la misma salida.
La expresión princPunt == finPunt comprueba si los dos punteros son iguales. Esto sólo puede ser verdad si los dos punteros apuntan a la misma variable.
Siempre que se realiza una operación aritmética sobre un puntero, sumando o restando un entero, el puntero se incrementa o decrementa un número apropiado de sitios tal que el nuevo valor apunta a la variable que está n elementos (no n bytes) antes o después que el dado.
Siempre que se realiza una operación aritmética sobre un puntero, sumando o restando un entero, el puntero se incrementa o decrementa un número apropiado de sitios tal que el nuevo valor apunta a la variable que está n elementos (no n bytes) antes o después que el dado.
De la misma forma, al restar dos punteros se obtiene el número de objetos entre las dos localizaciones. Finalmente, dos punteros son iguales si y sólo si apuntan a la misma variable (el valor de las direcciones es el mismo). No son necesariamente iguales si sus valores indirectos son los mismos, ya que estas variables podrían estar en diferentes localizaciones de memoria.
3.3 REFERENCIAS
Las referencias son un tipo de dato C++ estrechamente relacionado con los punteros. Una referencia de un objeto no es un objeto, en el sentido que no tiene su propio espacio de almacenamiento como ocurre con los punteros, y en consecuencia no pueden realizarse con ellas muchas de las operaciones que se relacionan con objetos. Por ejemplo obtener su dirección, crearlas con el operador new, o crear matrices de referencias.
Una referencia es una especie de alias o "alter ego" del objeto. Como se verá a continuación, este concepto, que también existe en otros lenguajes, es un recurso de C++ para pasar argumentos a funciones permitiendo que los argumentos no sean simples variables locales de la función, sino objetos del ámbito que realiza la invocación, lo que permite que la función pueda modificar objetos externos a ella.
Sintaxis:
La declaración de una variable de este tipo se realiza mediante
el declarador de referencia &. La sintaxis general es:
& [ = ]
Ejemplo:
int x;
int & z = x; // decimos que x es el 'iniciador' y que z es la 'referencia'
Estas sentencias declaran e inicia la variable z como referencia-a-entero,
y la asocia con la variable x (que es un entero). En adelante z actúa como un alias de x,
de forma que cualquier operación sobre z equivale a hacerla sobre x. En realidad puede considerarse que z es "casi" un sinónimo de x (como si fuesen la misma variable). , si hacemos:
int x = 4;
Declaración: Las referencias no pueden ser declaradas aisladas, de forma que tienen que estar indefectiblemente unidas a un objeto en su propia definición (deben ser inicializadas en la declaración). Además, una vez declaradas no pueden ser reasignadas a otro objeto (como los punteros), por lo que resultan unidas de por vida al objeto inicial. Por ejemplo:Por la razón anterior, puesto que tienen que estar unidas a un objeto, no pueden referenciar a void:
int& z = void; // Error.
Sí pueden ser inicializadas a otra referencia del mismo tipo, en cuyo caso señalan al objeto inicial. Ejemplo:int& max
(int& a, int& b) {
3.4 ARREGLOS UNIDIMENSIONALES, BIDIMENSIONALES Y MULTIDIMENSIONALES
Arreglos Unidimensionales
Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior.
Representación en Memoria
Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior.
Representación en Memoria
Los arreglos se representan en memoria de la forma siguiente:
x : array[1..5] of integer
Arreglos Bidimensionales
Este tipo de arreglos al igual que los anteriores es un tipo de dato estructurado, finito ordenado y homogéneo. El acceso a ellos también es en forma directa por medio de un par de índices.Los arreglos bidimensionales se usan para representar datos que pueden verse como una tabla con filas y columnas. La primera dimensión del arreglo representa las columnas, cada elemento contiene un valor y cada dimensión representa una relación La representación en memoria se realiza de dos formas: almacenamiento por columnas o por renglones.
Arreglos Multidimensionales
Los arreglos multidimensionales tienen más de una dimensión. En C#, las dimensiones se manejan por medio de un par de corchetes, dentro de los que se escriben los valores de cada dimensión, separados por comas.Este también es un tipo de dato estructurado, que está compuesto por n dimensiones. Para hacer referencia a cada componente del arreglo es necesario utilizar n índices, uno para cada dimensión.
3.5 CADENAS DE CARACTERES
En programación, una cadena de caracteres, palabra, ristra de caracteres o frase (string en inglés) es una secuencia ordenada de longitud arbitraria (aunque finita) de elementos que pertenecen a un cierto alfabeto. En general, una cadena de caracteres es una sucesión de caracteres (letras, números u otros signos o símbolos).
Siguiendo en el ámbito de la informática, al considerar las cadenas como un tipo de datos, hay que definir (o conocer) cuales son las operaciones que podemos hacer con ellas, en principio éstas podrían ser muchas y llegar a ser muy sofisticadas.
Aquí se exponen algunas de ellas:
Siguiendo en el ámbito de la informática, al considerar las cadenas como un tipo de datos, hay que definir (o conocer) cuales son las operaciones que podemos hacer con ellas, en principio éstas podrían ser muchas y llegar a ser muy sofisticadas.
Aquí se exponen algunas de ellas:
• Asignación: Consiste en asignarle una cadena a otra.
• Concatenación: Consiste en unir dos cadenas o más (o una cadena con un carácter) para formar una cadena de mayor tamaño.
• Búsqueda: Consiste en localizar dentro de una cadena una subcadena más pequeña o un carácter.
• Extracción: Se trata de sacar fuera de una cadena una porción de la misma según su posición dentro de ella.
• Comparación
3.6 ASIGNACION DINAMICA DE MEMORIA
Es la asignación de almacenamiento de memoria para utilización por parte de un programa de computador durante el tiempo de ejecución de ese programa. Es una manera de distribuir la propiedad de recursos de memoria limitada entre muchas piezas de código y datos. Un objeto asignado dinámicamente permanece asignado hasta que es desasignado explícitamente, o por el programador o por un recolector de basura; esto es notablemente diferente de la asignación automática de memoria y de la asignación estática de memoria (la de las variables estáticas). Se dice que tal objeto tiene tiempo de vida dinámico.
La asignación dinámica de memoria es una característica de C. Le permite al usuario crear tipos de datos y estructuras de cualquier tamaño de acuerdo a las necesidades que se tengan en el programa.
La asignación dinámica de memoria es una característica de C. Le permite al usuario crear tipos de datos y estructuras de cualquier tamaño de acuerdo a las necesidades que se tengan en el programa.
Se revisarán dos de las aplicaciones más comunes:
• Arreglos dinámicos
• Estructuras dinámicas de datos.
En C la asignación dinámica de memoria se manipula con las funciones malloc() y free(). En C++ se define un método de hacer asignación dinámica utilizando los operadores new y delete.
En C la asignación dinámica de memoria se manipula con las funciones malloc() y free(). En C++ se define un método de hacer asignación dinámica utilizando los operadores new y delete.
El operador new está disponible directamente en C++, de modo que no se necesita utilizar ningún archivo de cabecera; new se puede utilizar con dos formatos:new tipo // asigna un único elemento new tipo[num_eltos] // signa un arraySi la cantidad de memoria solicitada no está disponible, el operador new proporciona el valor 0. El operador delete libera la memoria signada con new.delete variabledelete [n] variable.
new es superior a malloc por tres razones:
1.- new conoce cuánta memoria se asigna a cada tipo de variable.
2.- malloc() debe indicar cuánta memoria asignar.
3.- new hace que se llame a un constructor para el objeto asignado y malloc no puede.
delete produce una llamada al destructor en este orden:
1. Se llama al destructor
3.7 USO DE CLASES DEFINIDAS PARA ARREGLOS
En el lenguaje de programación C una estructura(struct) es lo mismo que una clase, en este caso se explica referente a un struct.
Se puede crear un array de estructuras tal como se crea un array de otros tipos. Los arrays de estructuras son idóneos para almacenar un archivo completo de empleados, un archivo de inventario, o cualquier otro conjunto de datos que se adapte a un formato de estructura.
Mientras que los arrays proporcionan un medio práctico de almacenar diversos valores del mismo tipo, los arrays de estructuras le permiten almacenar juntos diversos valores de diferentes tipos, agrupados como estructuras.
Muchos programadores de C utilizan arrays de estructuras como un método para almacenar datos en un archivo de disco. Se pueden introducir y calcular sus datos de disco en arrays de estructuras y a continuación almacenar esas estructuras en memoria. Los arrays de estructura proporcionan también un medio de guardar datos que se leen del disco.La declaración de un array de estructuras info_libro se puede hacer de un modo similar a cualquier array es decir
struc info_libro libros [100];
asigna un array de 100 elementos denominado libros. Para acceder a los miembros de cada uno de los elementos estructura se utiliza una notación de array. Para inicializar el primer elemento de libros, por ejemplo, su código debe hacer referencia a los miembros de libros [0] de la forma siguiente:
strcpy (libros [0].titulo, "C++ a su alcance");
strcpy (libros [0].autor, "Luis Joyanes");
strcpy (libros [0].editorial, "McGraw-Hill");
libros [0].anyo=1999;
strcpy (libros [0].autor, "Luis Joyanes");
strcpy (libros [0].editorial, "McGraw-Hill");
libros [0].anyo=1999;
Tambien puede inicializarse un array de estructuras en el punto de la declaración encerrando la lista de inicializadores entrellaves, {}.
Por ejemplo:
struct info_libro libros [3] = { "C++ a su alcance", "Luis Joyanes", "McGraw-
Hill", 1999, "Estructura de datos", "Luis Joyanes", "McGraw-Hill", 1999,
"Problemas en pascal", "Angel Hermoso", "McGraw-Hill", 1997};
No hay comentarios:
Publicar un comentario