UNIVERSIDAD CENTROAMERICANA INTEGRANTES: LUIS CARLOS CAJINA BUSTOS SHARON RADARANI MEJIA GUERRERO CESAR NUÑEZ CARRERA: INGENIENIERA EN SISTEMAS Y TECNOLOGIAS DE LA INFORMACION ASIGNATURA: ABSTRACCION Y ESTRUCTURA DE DATOS FECHA: 02 DE OCTUBRE DEL 2009 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información INDICE Introducción…………………………………………………………………………...3 Punteros………………………………………………………………………………..4 Operadores Dirección (&) e Indirección (*)……………………………....6 Estructura en C++……………………………………………………………………...6 Manejo de Memoria………………………………………………………………….8 Conclusiones…………………………………………………………………………….12 Bibliografía……………………………………………………………………………12 Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 2 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información INTRODUCCION Este documento se realizó con el objetivo de brindar mayor conocimientos sobre lo que se refiere al lenguaje en C++ con respecto algunas características en su utilización y su importancia. En cual abordaremos los temas como la definición, la utilización o fin y cómo podemos trabajar con los punteros, estructuras y manejo de memoria en C++ Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 3 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información Punteros El valor de cada variable está almacenado en un lugar de la memoria, caracterizado por una dirección (que se suele expresar con un número hexadecimal). El ordenador mantiene una tabla de direcciones que relaciona el nombre de cada variable con su dirección en la memoria. Gracias a los nombres de las variables (identificadores) no hace falta que el programador se preocupe de la dirección de memoria donde están almacenados sus datos. Sin embargo, en ciertas ocasiones es más útil trabajar con las direcciones que con los propios nombres de las variables. El lenguaje C/C++ dispone del operador dirección (&) que permite determinar la dirección de una variable, y de un tipo especial de variables destinadas a contener direcciones de variables, estas variables se llaman punteros o apuntadores. Así pues, un puntero es una variable que puede contener la dirección de otra variable. Por supuesto, los punteros están almacenados en algún lugar de la memoria y tienen su propia dirección. Se dice que un puntero apunta a una variable si su contenido es la dirección de esa variable. Un puntero ocupa 4 bytes de memoria, y se debe declarar o definir de acuerdo con el tipo de dato al que apunta. Por ejemplo, un puntero a una variable de tipo int se declara del siguiente modo: int *direc; Lo cual quiere decir que a partir de este momento, la variable direc podrá contener la dirección de cualquier variable entera. La regla nemotécnica es que el valor al que apunta direc (es decir *direc), es de tipo int. Los punteros a long, char, float, 4irecc, etc. Se definen de igual manera que el puntero a int del ejemplo anterior. Int *countPtr, count; count=7; countPtr=&count; count 7 count se refiere directamente a la variable cuyo valor es 7. Punteros, Estructura y Manejo de Memoria countPtr count 7 countPtr se refiere en forma indirecta a la variable cuyo valor es 7. Abstracción y Estructura de Datos 4 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información Operadores Dirección (&) e Indirección (*) Como se ha dicho, el lenguaje C/C++ dispone del operador dirección (&) que permite hallar la dirección de la variable a la que se aplica. Un puntero es una verdadera variable, y por tanto puede cambiar de valor, es decir, puede cambiar la variable a la que apunta. Para acceder al valor depositado en la zona de memoria a la que apunta un puntero se debe utilizar el operador indirección (*). Por ejemplo, supóngase las siguientes declaraciones y sentencias: int i, j, *p; // p es un puntero a int p = &i; // p contiene la dirección de i *p = 10; // i toma el valor de 10 P = &j; // p contiene ahora la dirección de j *p = -2 // j toma el valor -2 Las constantes y las expresiones no tienen dirección, por lo que no se les puede aplicar el operador (&). Tampoco puede cambiarse la dirección de una variable. Los valores posibles para un puntero son las direcciones posibles de memoria. Un puntero puede tener valor 0 (equivalente a la constante simbólica predefinida NULL). No se puede asignar una dirección absoluta directamente. Las siguientes sentencias son ilegales: P = &34; // las constantes no tiene dirección p = &(i+1); // las expresiones no tiene dirección &i = p; // las direcciones no se pueden cambiar p = 17654 // habría que escribir p = (int *) 17654; Para imprimir punteros con la función printf() se deben utilizar los formatos %u y %p. No se permiten asignaciones directas entre punteros que apuntan a distintos tipos de variables. Sin embargo, existe un tipo indefinido de punteros (void*, o punteros a void), que pueden asignarse y al que puede asignarse cualquier tipo de puntero. Por ejemplo: int *p; 5irecc *q; void *r; p = q; // ilegal p = (int *)q; // legal r = q; // legal Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 5 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información Los punteros son unas variables un poco especiales, ya que guardan información –no sólo de la dirección a la que apuntan-, sino también del tipo de variable almacenado en esa dirección. Esto implica que no van a estar permitidas las operaciones que no tiene sentido con direcciones de variables, como multiplicar o dividir, pero si otras como sumar o restar. Además estas operaciones se realizan de un modo correcto. Así, la sentencia: p= p+1; hace que p apunte a la dirección siguiente de la que apuntaba, teniendo en cuenta el tipo de dato. También tiene sentido la diferencia de punteros al mismo tipo de variable. El resultado es la distancia entre las direcciones de las variables apuntadas por ellos, no en bytes sino en datos de ese mismo tipo. Con apuntadores se pueden ejecutar un conjunto limitado de operaciones aritméticas. Un apuntador puede ser incrementado (++) o decrementado (--), se puede añadir un entero a un puntero (+ o +=), un entero puede ser restado de un apuntador (- o -=), o un apuntador puede ser sustraído o restado de otro. Relación entre Punteros y Arreglos Existe una relación muy estrecha entre los vectores y los punteros. De hecho, el nombre de un vector es un puntero (un puntero constante, en el sentido de que no puede apuntar a otra variable distinta de aquella a la que apunta) a la dirección de memoria que contiene el primer elemento del vector. Estructura en C++ Las estructuras de control de un programa se ven complementadas con las estructuras de datos que un lenguaje de programación proporciona y las que el mismo programador puede llegar a definir. El lenguaje c permite manipular los tipos simples de datos para crear estructuras más complejas basadas en dichos tipos primigenios. El lenguaje C, así como la mayoría de los lenguajes de programación, proporciona un conjunto finito de tipos de datos sobre los cuales se pueden realizar programas de cierta complejidad. El modelado de los problemas de la “vida real” nos lleva a requerir tipos de datos distintos. En cualquier aplicación nos encontraremos que un dato particular estará compuesto por campos individuales que por sí solos no poseen significados. Es particularmente útil al programador la posibilidad en los lenguajes de armar nuevos tipos de datos que son conjuntos de datos más simples. Sin esa característica en los lenguajes el programador se ve obligado a controlar la agrupación d sus datos por sus propios medios. Una estructura es un grupo de variables las cuales pueden ser de diferentes tipos sostenidas o mantenidas juntas en una sola unidad. La unidad es la estructura. Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 6 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información Sintaxis y reglas para estructuras en C/C++ En C++ se forma una estructura utilizando la palabra reservada struct, seguida por un campo etiqueta opcional, y luego una lista de miembros dentro de la estructura. La etiqueta opcional se utiliza para crear otras variables del tipo particular de la estructura: struct nombre_estructura { tipo identificador; tipo identificador; tipo identificador; … tipo identificador; }lista de variable_de_estructura; Donde: nombre_estructura: Representa el nombre que recibirá la estructura. Dicho nombre será único para la estructura. Identificador: Es el nombre de un componente de la estructura, cada componente puede ser de tipo elemental o compuesto. Variable_de_estructura: Es el nombre de una variable que está conformada por los tipos declarados en la estructura. Se puede omitir el nombre_estructura o bien la lista de variables de estructura pro no ambas. Cada componente de la estructura recibe el nombre de miembro de la estructura. Un punto y coma finaliza la definición de una estructura puesto que esta es realmente una sentencia C/C++. Supongamos que queremos hacer una agenda con los números de teléfono de nuestros amigos. Necesitaríamos un array de cadenas para almacenar sus nombres, otro para sus apellidos y otro para sus números de teléfono. Esto puede hacer que el programa quede desordenado y difícil de seguir. Aquí es donde radica la importancia de las estructuras. Para nuestro ejemplo podemos crear una estructura en la que almacenaremos los datos de cada persona. Vamos a crear una declaración de estructura llamada amigo: Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 7 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información struct estructura_amigo { char nombre [30]; char apellido [40]; char teléfono [10]; int edad; }; Ahora ya tenemos definida la estructura, pero aun no podemos usarla. Necesitamos declarar una variable con esa estructura. Struct estructura_amigo amigo; Ahora la variable amigo es de tipo estructura_amigo. Para acceder al nombre de amigo usamos: amigo.nombre. Inicializar una estructura A las estructuras se les puede dar valores iniciales de manera análoga. Primero tenemos que definir la estructura y luego cuando declaramos una variable como estructura le damos el valor inicial que queramos. Manejo de Memoria en C++ Cada una de las variables que se utilizan en un programa para almacenar datos, así como el mismo código del programa, necesitan ser representados en la memoria para llevar a cabo el procesamiento, independientemente de la representación interna de los tipos de datos, que puede variar de un compilador a otro, de un procesador a otro. Estructura de la Memoria La memoria se divide en zonas para lograr la coordinación entre los datos necesarios para el procesamiento (datos del sistema) y los datos y elementos de los programas del usuario. Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 8 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información LA PILA Es una zona de memoria que gestiona las llamadas a funciones durante la ejecución de un programa. Cada vez que se realiza una llamada a una función en el programa, se crea un entorno de programa, que se libera cuando acaba su ejecución. El entorno de programa almacena, entre otros: La siguiente instrucción que se ejecutará cuando se resuelva la llamada a la función (dirección de retorno). Los argumentos y variables locales definidos en la función. La reserva y liberación de la memoria la realiza el Sistema Operativo de forma automática durante la ejecución del programa. Las variables locales no son variables estáticas. Son un tipo especial de variables dinámicas, conocidas como variables automáticas. EL HEAP (MONTÓN) Es una zona de memoria donde se reservan y se liberan “bytes” durante la ejecución de los programas según sus propias necesidades. Esta memoria surge de la necesidad de los programas de “crear nuevas variables” en tiempo de ejecución con el fin de optimizar el almacenamiento de datos. Supongamos que se desea realizar un programa que permita trabajar con una lista de datos relativos a una persona. Struct Persona { char nombre [30]; int identificación; char dirección[50]; }; Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 9 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información A prioridad, es necesario definir un tamaño apropiado para almacenar un vector de Persona. Supongamos que realizamos la siguiente definición: Persona VectorPersona[100]; ¿Qué inconvenientes tiene esta definición? En cada ejecución se puede requerir un número diferente de posiciones del vector: Si el número de posiciones usadas es mucho menor que 100, tenemos reservada memoria que no vamos a utilizar (desperdicio de memoria). Si el número de posiciones usadas es mayor que 100, el programa no funcionará correctamente, ya que se usan posiciones de memorias que pueden estar usando otras variables del programa. La utilización de variables estáticas o automáticas para almacenar información cuyo tamaño no es conocido a prioridad (sólo se conoce exactamente en tiempo de ejecución) resta generalidad al programa. La alternativa válida para solucionar estos problemas consiste en la posibilidad de, en tiempo de ejecución, pedir la memoria necesaria para almacenar la información y de liberarla cuando ya no sea necesaria. Esta memoria se reserva en el Heap y, habitualmente, se habla de variables dinámicas para referirse a los bloques de memoria del Heap que se reservan y liberan en tiempo de ejecución. MEMORIA ESTÁTICA, MEMORIA DINÁMICA Y MEMORIA AUTOMÁTICA Todas las variables, arrays, punteros y objetos en general tienen una duración determinada en el transcurso del programa. Tales objetos son creados y destruidos, o en otros términos: se asocian sus nombres (identificadores) a una zona de memoria en la cual no puede asentarse otro objeto, y tales zonas de memoria son liberadas para el uso de otros objetos. La existencia de tales objetos está determinada según tres formas básicas de usar la memoria en C/C++. MEMORIA ESTÁTICA Los objetos son creados al comenzar el programa y destruidos sólo al finalizar el mismo. Mantienen la misma localización en memoria durante todo el transcurso del programa. Estos objetos son almacenados al principio del segmento de datos. Los objetos administrados de este modo son: variables globales, variables estáticas de funciones, miembros static de clases, y literales de cualquier tipo. Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 10 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información MEMORIA AUTOMÁTICA Los objetos son creados al entrar en el bloque en que están declarados, y se destruyen al salir del bloque. Se trata de un proceso dinámico pero manejado de modo automático por el compilador (no confundir con memoria dinámica). Tales objetos se almacenan en la parte alta de la pila al entrar en la función o bloque que los contiene. Este procedimiento se aplica a: variables locales y argumentos de función. MEMORIA DINÁMICA En este caso tanto la creación y destrucción de los objetos está en manos del programador. El sitio donde se almacenan tales objetos se suele denominar en ingles “heap”’ o “free store”, traducido como “montículo” o “memoria libre”. Pero el sitio preciso donde se encuentre tal montículo depende del compilador y el tipo de puntero utilizado en la reserva de memoria dinámica. Cualquier tipo de objeto puede ser creado y destruido a través de este procedimiento. En C y C++ la administración explícita de memoria por parte del programador juega un rol muy importante, no es así en otros lenguajes (Basic, Smalltalk, Perl) donde la gestión principal es automática. La administración manual permite un mayor grado de flexibilidad, pero también multiplica la posibilidad de errores. Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 11 Universidad Centroamericana Ingeniería en Sistemas y Tecnologías de la Información CONCLUSIONES Con el desarrollo de los temas abordados en este contenido hemos adquirido más conocimientos con respecto al lenguaje en C++, tanto en su importancia y en su utilización de los punteros, estructura y manejo de memorias, ya que esto es muy importante conocerlo como programadores que somos, porque nos facilitaran nuestro trabajo estaremos seguros que después de haber adquirido estos conocimientos tendremos mayor destreza en lenguajes de C++ y sabremos su complejidad y podremos resolver problemas que se nos presenten en la vida cotidianamente. Bibliografía http://www.itq.edu.mx/vidatec/maestros/sis/mlopez/Tutorial/est.htm http://laurel.datsi.fi.upm.es/~rpons/personal/trabajos/curso_c/node25.html http://sopa.dis.ulpgc.es/so/cpp/intro_c/introcfc.htm Punteros, Estructura y Manejo de Memoria Abstracción y Estructura de Datos 12