Anda di halaman 1dari 243

PROGRAMACION EN EL LENGUAJE C/C++

CAPITULO 1
Proceso de creacin del software.

Se define como proceso al conjunto ordenado de pasos a seguir para llegar a la solucin de un problema u obtencin de un producto, en este caso particular, para lograr un producto software que resuelva un problema especfico. El proceso de creacin de software puede llegar a ser muy complejo, dependiendo de su porte, caractersticas y criticidad del mismo. Por ejemplo la creacin de un sistema operativo es una tarea que requiere proyecto, gestin, numerosos recursos y todo un equipo disciplinado de trabajo. En el otro extremo, si se trata de un sencillo programa, ste puede ser realizado por un solo programador fcilmente. Es as que normalmente se dividen en tres categoras segn su tamao (lneas de cdigo) o costo. Considerando los de gran porte, es necesario realizar complejas tareas, tanto tcnicas como de gerencia, una fuerte gestin y anlisis diversos, la complejidad de ello ha llevado a que desarrolle una ingeniera especfica para tratar su estudio y realizacin: es conocida como Ingeniera de Software. En tanto que en los de mediano porte, pequeos equipos de trabajo (incluso un avezado analista-programador solitario) pueden realizar la tarea. Aunque, siempre en casos de mediano y gran porte (y a veces tambin en algunos de pequeo porte, segn su complejidad), se deben seguir ciertas etapas que son necesarias para la construccin del software. Tales etapas, si bien deben existir, son flexibles en su forma de aplicacin, de acuerdo a la metodologa o proceso de desarrollo escogido y utilizado por el equipo de desarrollo o por el analista-programador solitario (si fuere el caso). Los procesos de desarrollo de software poseen reglas preestablecidas, y deben ser aplicados en la creacin del software de mediano y gran porte, ya que en caso

contrario lo ms seguro es que el proyecto o no logre concluir o termine sin cumplir los objetivos previstos, y con variedad de fallos inaceptables. Entre tales procesos los hay giles o livianos (ejemplo XP), pesados y lentos (ejemplo RUP), y variantes intermedias. Normalmente se aplican de acuerdo al tipo y porte del software a desarrollar, a criterio del lder (si lo hay) del equipo de desarrollo. Algunos de esos procesos son Programacin Extrema (en ingls eXtreme Programming o XP), Proceso Unificado de Rational (en ingls Rational Unified Process o RUP), Feature Driven Development (FDD), etc. Cualquiera sea el proceso utilizado y aplicado al desarrollo del software, y casi independientemente de l, siempre se debe aplicar un modelo de ciclo de vida. Cuando un proyecto fracasa, rara vez es debido a fallas tcnicas, la principal causa de fallos y fracasos es la falta de aplicacin de una buena metodologa o proceso de desarrollo. Entre otras, una fuerte tendencia, desde hace pocas dcadas, es mejorar las metodologas o procesos de desarrollo, o crear nuevas y concientizar a los profesionales de la informtica a su utilizacin adecuada. Normalmente los especialistas en el estudio y desarrollo de estas reas y afines son los ingenieros en software, es su orientacin. Los especialistas en cualquier otra rea de desarrollo informtico normalmente aplican sus conocimientos especializados pero utilizando modelos, paradigmas y procesos ya elaborados. Es comn para el desarrollo de software de mediano porte que los equipos humanos involucrados apliquen metodologas propias, normalmente un hbrido de los procesos anteriores y a veces con criterios propios. El proceso de desarrollo puede involucrar numerosas y variadas tareas , desde lo administrativo, pasando por lo tcnico y hasta la gestin y el gerenciamiento. Pero, casi rigurosamente, siempre se cumplen ciertas etapas mnimas; las que se pueden resumir como sigue: Captura, elicitacin, especificacin y anlisis de requisitos (ERS) Diseo

Codificacin Pruebas (unitarias y de integracin) Instalacin y paso a produccin Mantenimiento

En las anteriores etapas pueden variar ligeramente sus nombres, o ser ms globales, o contrariamente, ser ms refinadas; por ejemplo indicar como una nica fase (a los fines documentales e interpretativos) de anlisis y diseo; o indicar como implementacin lo que est dicho como codificacin; pero en rigor, todas existen e incluyen, bsicamente, las mismas tareas especficas.

Lenguajes de programacin. Definicin.

Un lenguaje de programacin es un conjunto de smbolos y reglas sintcticas y semnticas que definen su estructura y el significado de sus elementos y expresiones. Es utilizado para controlar el comportamiento fsico y lgico de una mquina. Un lenguaje de programacin es un lenguaje diseado para describir el conjunto de acciones que un equipo debe ejecutar. Por lo tanto, un lenguaje de programacin es un modo prctico para que los seres humanos puedan dar instrucciones a un equipo. Los primeros lenguajes de programacin surgieron de la idea de Charles Babagge, la cual se le ocurri a este hombre a mediados del siglo XIX, predijo muchas de las teoras en que se basan los actuales ordenadores. Consista en lo que l denominaba la maquina analtica, pero que por motivos tcnicos no pudo construirse hasta mediados del siglo XX. Con l colaboro Ada Lovedby, la cual es considerada como la primera programadora de la historia, pues realizo programas para aqulla supuesta maquina de Babagge, en tarjetas perforadas.

Los lenguajes de programacin son los medios de comunicacin entre los programadores o usuarios y la computadora. Con ellos se construyen los programas que despus sern ejecutados por la computadora.

Clasificacion de los lenguajes de programacin.

Un lenguaje de programacin es un conjunto limitado de palabras y de smbolos que representan procedimientos, clculos, decisiones y otras operaciones que pueden ejecutar una computadora.

Lenguajes de Programacion segn su nivel.

Calsificamos los lenguajes segn su nivel de programacin en: Lenguajes de mquina El lenguaje mquina de una computadora consta de cadenas de nmeros binarios (ceros y unos) y es el nico que "entienden" directamente los procesadores. Todas las instrucciones preparadas en cualquier lenguaje de mquina tienen por lo menos dos partes. La primera es el comando u operacin, que dice a la computadora cul es la funcin que va a realizar. Todas las computadoras tienen un cdigo de operacin para cada una de sus funciones. La segunda parte de la instruccin es el operando, que indica a la computadora dnde hallar o almacenar los datos y otras instrucciones que se van a manipular; el nmero de operandos de una instruccin vara en las distintas computadoras. Segn los estndares actuales, las primeras computadoras eran poco tolerantes. Los programadores tenan que traducir las instrucciones de manera directa a la forma de lenguaje de mquina que comprendan las

computadoras. Por ejemplo, un programador que escribiera la instruccin "SUMAR 0814" para una de las primeras mquinas IBM hubiera escrito: 000100000000000000000000000010111000 Adems de recordar las docenas de cdigos numricos para los comandos del conjunto de instrucciones de la mquina, el programador tena que conocer las posiciones donde se almacenan los datos y las instrucciones. La codificacin inicial muchas veces requera meses, por lo que era costosa y era frecuente que originara errores. Lenguajes ensambladores A principios de la dcada de 1950, y con el fin de facilitar la labor de los programadores, se desarrollaron cdigos nemotcnicos para las

operaciones y direcciones simblicas. La palabra nemotcnico se refiere a una ayuda para la memorizacin. Uno de los primeros pasos para mejorar el proceso de preparacin de programas fue sustituir los cdigos de operaciones numricos del lenguaje de mquina por smbolos alfabticos, que son los cdigos nemotcnicos. Todas las computadoras actuales tienen cdigos nemotcnicos aunque, naturalmente, los smbolos que se usan varan en las diferentes marcas y modelos. La computadora sigue utilizando el lenguaje de mquina para procesar los datos, pero los programas ensambladores traducen antes los smbolos de cdigo de operacin especificados a sus equivalentes en lenguaje de mquina. Este procedimiento prepar avances posteriores. La tcnica de

direccionamiento simblico permite expresar una direccin no en trminos de su localizacin numrica absoluta, sino en trminos de smbolos convenientes para el programador. Durante las primeras etapas del direccionamiento simblico, el programador asigna un nombre simblico y una direccin real a un dato. As, durante el resto del programa, el programador se referir a los

nombres simblicos, ms que a las direcciones, cuando fuera preciso procesar estos datos. Ms adelante se hizo otra mejora. Se dej a la computadora la tarea de asignar y recordar las direcciones de las instrucciones. Lo nico que tena que hacer el programador era indicar a la computadora la direccin de la primera instruccin, y el programa ensamblador se encargaba de almacenar, de manera automtica, todas las dems en forma secuencial a partir de ese punto. As, si se agregaba ms tarde otra instruccin al programa, no era necesario modificar las direcciones de todas las instrucciones que seguan al punto de insercin. En vez de ello, el procesador ajustaba automticamente las localidades de memoria la prxima vez que se ejecutaba el programa.En la actualidad, los programadores no asignan nmeros de direccin reales a los datos simblicos, simplemente especifican dnde quieren que se coloque la primera localidad del programa, y el programa ensamblador se encarga de lo dems: asigna localidades tanto para las instrucciones como para los datos.Estos programas de ensamble, o ensamblador, tambin permite a la computadora convertir las instrucciones en lenguaje ensamblador del programador en su propio cdigo de mquina. Un programa de instrucciones escrito en lenguaje ensamblador por un programador se llama programa fuente. Despus de que el ensamblador convierte el programa fuente en cdigo de mquina a ste se le denomina programa objeto. Para los programadores es ms fcil escribir instrucciones en un lenguaje ensamblador que en cdigos de lenguajes de mquina, pero es posible que se requieran dos corridas de computadora antes de que se puedan utilizar las instrucciones del programa fuente para producir las salidas deseadas. Los lenguajes ensambladores tienen ventajas sobre los lenguajes de mquina. Ahorran tiempo y requieren menos atencin a detalles. Se

incurren en menos errores y los que se cometen son ms fciles de localizar. Lenguajes de alto nivel Los primeros programas ensambladores producan slo una instruccin en lenguaje de mquina por cada instruccin del programa fuente. Para agilizar la codificacin, se desarrollaron programas ensambladores que podan producir una cantidad variable de instrucciones en lenguaje de mquina por cada instruccin del programa fuente. Dicho de otra manera, un sola macroinstruccin poda producir varias lneas de cdigo en lenguaje de mquina. Por ejemplo, el programador podra escribir "LEER ARCHIVO", y el programa traductor producira una serie detallada de instrucciones al lenguaje de mquina previamente preparada, con lo que se copiara un registro del archivo que estuviera leyendo el dispositivo de entrada a la memoria principal. As, el programador no se tena que ocupar de escribir una instruccin por cada operacin de mquina realizada. El desarrollo de las tcnicas nemotcnicas y las macroinstrucciones condujo, a su vez, al desarrollo de lenguajes de alto nivel que a menudo estn orientados hacia una clase determinada de problemas de proceso. A diferencia de los programas de ensamble, los programas en lenguaje de alto nivel se pueden utilizar con diferentes marcas de computadores sin tener que hacer modificaciones considerables. Esto permite reducir sustancialmente el costo de la reprogramacin cuando se adquiere equipo nuevo. Otras ventajas de los lenguajes de alto nivel son: o Son ms fciles de aprender que los lenguajes ensambladores. o Se pueden escribir ms rpidamente. o Permiten tener mejor documentacin. o Son ms fciles de mantener.

o Un programador que sepa escribir programas en uno de estos lenguajes no est limitado a utilizar un solo tipo de mquina.

Lenguajes compilados.

Naturalmente, un programa que se escribe en un lenguaje de alto nivel tambin tiene que traducirse a un cdigo que pueda utilizar la mquina. Los programas traductores que pueden realizar esta operacin se llaman compiladores. stos, como los programas ensambladores avanzados, pueden generar muchas lneas de cdigo de mquina por cada proposicin del programa fuente. Se requiere una corrida de compilacin antes de procesar los datos de un problema. Los compiladores son aquellos cuya funcin es traducir un programa escrito en un determinado lenguaje a un idioma que la computadora entienda (lenguaje mquina con cdigo binario). Al usar un lenguaje compilado, el programa desarrollado nunca se ejecuta mientras haya errores, sino hasta que luego de haber compilado el programa, ya no aparecen errores en el cdigo.

Lenguajes interpretados.

Se puede tambin utilizar una alternativa diferente de los compiladores para traducir lenguajes de alto nivel. En vez de traducir el programa fuente y grabar en forma permanente el cdigo objeto que se produce durante la corrida de compilacin para utilizarlo en una corrida de produccin futura, el programador slo carga el programa fuente en la computadora junto con los datos que se van a procesar. A continuacin, un programa intrprete, almacenado en el sistema operativo del disco, o incluido de manera permanente dentro de la mquina, convierte cada proposicin del programa fuente en lenguaje de mquina conforme vaya siendo necesario durante el proceso de los datos. No se graba el cdigo objeto para utilizarlo posteriormente.

La siguiente vez que se utilice una instruccin, se le debe interpretar otra vez y traducir a lenguaje mquina. Por ejemplo, durante el procesamiento repetitivo de los pasos de un ciclo, cada instruccin del ciclo tendr que volver a ser interpretado cada vez que se ejecute el ciclo, lo cual hace que el programa sea ms lento en tiempo de ejecucin (porque se va revisando el cdigo en tiempo de ejecucin) pero ms rpido en tiempo de diseo (porque no se tiene que estar compilando a cada momento el cdigo completo). El intrprete elimina la necesidad de realizar una corrida de compilacin despus de cada modificacin del programa cuando se quiere agregar funciones o corregir errores; pero es obvio que un programa objeto compilado con antelacin deber ejecutarse con mucha mayor rapidez que uno que se debe interpretar a cada paso durante una corrida de produccin.

Lenguajes de programacin declarativos.

Se les conoce como lenguajes declarativos en ciencias computacionales a aquellos lenguajes de programacin en los cuales se le indica a la computadora qu es lo que se desea obtener o qu es lo que se esta buscando. La programacin declarativa es una forma de programacin que implica la descripcin de un problema dado en lugar de proveer una solucin para dicho problema, dejando la interpretacin de los pasos especficos para llegar a dicha solucin a un intrprete no especificado. La programacin declarativa adopta, por lo tanto, un enfoque diferente al de la programacin imperativa tradicional. En otras palabras, la programacin declarativa provee el "qu", pero deja el "cmo" liberado a la implementacin particular del intrprete. Por lo tanto se puede ver que la programacin declarativa tiene dos fases bien diferenciadas, la declaracin y la interpretacin. Los lenguajes declarativos estn orientados a buscar la solucin del problema, sin preocuparse por la forma de llegar a ello; es decir, el programador debe concentrarse en la lgica del algoritmo, ms que en el control de la secuencia. Los

programas estn formados por un conjunto de definiciones o ecuaciones, las cuales describen lo que debe ser calculado, no en s la forma de hacerlo. Las variables slo pueden tener asignado un solo valor a lo largo de la ejecucin del programa, lo cual implica que no puede existir asignacin destructiva. Debido a esto, cobra especial importancia el uso del anidamiento y la recursividad. Las listas representan la estructura fundamental de datos. El orden de la ejecucin no resulta importante debido a que no existen efectos colaterales; es decir, que al calcular un valor, resulta imposible afectar el clculo de otros y con esto se puede afirmar que cualquier secuencia de ejecucin deber conducir al mismo resultado. Las expresiones o definiciones pueden ser usadas como valores y por lo tanto se pueden tratar como argumentos de otras definiciones.El control de la ejecucin no es responsabilidad del programador. Entre los lenguajes declarativos podemos clasificar: Programacin lgica La idea fundamental de la programacin lgica consiste en emplear la lgica como lenguaje de programacin. La lgica no es imperativa porque no sirve para indicar cmo resolver un problema. La lgica es declarativa porque sirve para especificar qu problema resolver. En la programacin lgica, se especifican las condiciones que satisfacen las soluciones, se deducen las soluciones a partir de las condiciones y el nfasis de todo est en qu problema resolver. El problema se describe especificando qu caracteriza a sus posibles soluciones. La programacin lgica, junto con la funcional, forma parte de lo que se conoce como programacin declarativa. En los lenguajes tradicionales, la programacin consiste en indicar cmo resolver un problema mediante sentencias; en la programacin lgica, se trabaja de forma descriptiva, estableciendo relaciones entre entidades, indicando no cmo, sino qu hacer.

Se establece entonces que la idea esencial de la programacin lgica es: algoritmos = lgica + control. Es decir, un algoritmo se construye especificando conocimiento en un lenguaje formal y el problema se resuelve mediante un mecanismo de inferencia que acta sobre aqul. Al hacer un recorrido por la programacin lgica, aparece como uno de sus lenguajes ms representativos, Prolog, que es un clsico de la inteligencia artificial y que se aplica de mltiples formas en el desarrollo de software comercial. Programacin funcional La programacin funcional es un paradigma de programacin declarativa basado en la utilizacin de funciones matemticas. El objetivo de la programacin funcional es conseguir lenguajes expresivos y matemticamente elegantes, en los que no sea necesario bajar al nivel de la mquina para describir el proceso llevado a cabo por el programa. Los programas escritos en un lenguaje funcional estn constituidos nicamente por definiciones de funciones, entendiendo stas no como subprogramas clsicos de un lenguaje imperativo, sino como funciones puramente matemticas, en las que se verifican ciertas propiedades como la transparencia referencial, y por tanto, la carencia total de efectos laterales. Otras caractersticas propias de estos lenguajes son la no existencia de asignaciones de variables y la falta de construcciones estructuradas como la secuencia o la iteracin. Existen dos grandes categoras de lenguajes funcionales: los funcionales puros y los hbridos. La diferencia entre ambos estriba en que los lenguajes funcionales hbridos son menos dogmticos que los puros, al permitir conceptos tomados de los lenguajes imperativos, como las secuencias de instrucciones o la asignacin de variables. En contraste, los lenguajes funcionales puros tienen una mayor potencia expresiva,

conservando a la vez su transparencia referencial, algo que no se cumple siempre con un lenguaje hbrido. Programacin orientada a bases de datos Las bases de datos son programas que administran informacin y hacen ms ordenada la informacin, aparte de hacer la fcil de buscar y por supuesto de encontrar. Las caractersticas de las bases de datos pueden ser ventajosas o desventajosas: pueden ayudar a almacenar, organizar, recuperar, comunicar y manejar informacin en formas que seran imposibles sin las computadoras, pero tambin afecta de alguna manera ya que existen enormes cantidades de informacin en bases de datos de las que no se tiene control del acceso. Las bases de datos tienen muchos usos: facilitan el almacenamiento de grandes cantidades de informacin; permiten la recuperacin rpida y flexible de informacin, con ellas se puede organizar y reorganizar la informacin, as como imprimirla o distribuirla en formas diversas. Es claro que los lenguajes orientados a bases de datos son declarativos y no imperativos, pues el problema es "qu" se quiere hacer o "qu" se necesita buscar y encontrar en la base de datos, y no se enfatiza el "cmo". Una base de datos tambin se puede definir como un banco de datos o conjunto de datos que pertenecen al mismo contexto, almacenados sistemticamente para su posterior uso. Los sistemas gestores de bases de datos (SGBD) permiten almacenar y posteriormente acceder a los datos de forma rpida y estructurada.

Lenguajes de programacin imperativos.

Se llama lenguajes imperativos a aquellos en los cuales se le ordena a la computadora cmo realizar una tarea siguiendo una serie de pasos o instrucciones. El

proceso anterior se puede realizar con un lenguaje imperativo como por ejemplo BASIC, C, C++, Java, Clipper, Dbase, C#, PHP, Perl, etc. Dentro de la programacin imperativa, se tiene un conjunto de instrucciones que le indican al computador cmo realizar una tarea. Los lenguajes imperativos se basan en comandos u rdenes que se le dan a la computadora para que haga algo, con el fin de organizar o cambiar valores en ciertas partes de la memoria. La ejecucin de estos comandos se realiza, en la mayor parte de ellos, secuencialmente, es decir, hasta que un comando no ha sido ejecutado no se lee el siguiente. Segn el dominio, o mejor dicho con el propsito que se utiliza el programa, se puede hablar de lenguajes de dominio especfico y de dominio general. Lenguajes imperativos procedurales es la aplicacin quien controla qu porciones de cdigo se ejecuta, y la secuencia en que este se ejecuta. La ejecucin de la aplicacin se inicia con la primera lnea de cdigo, y sigue una ruta predefinida a travs de la aplicacin, llamando procedimientos segn sea necesario. Los lenguajes procedurales estn fundamentados en la utilizacin de variables para almacenar valores y en la realizacin de operaciones con los datos almacenados. En este tipo de lenguajes, la arquitectura consta de una secuencia de celdas, llamadas memoria, en las cuales se pueden guardar en forma codificada, lo mismo datos que instrucciones; y de un procesador, el cual es capaz de ejecutar de manera secuencial una serie de operaciones, principalmente aritmticas y booleanas, llamadas comandos. En general, un lenguaje procedural ofrece al programador conceptos que se traducen de forma natural al modelo de la mquina. El programador tiene que traducir la solucin abstracta del problema a trminos muy primitivos, cercanos a la mquina. Con un lenguaje procedural el usuario (normalmente ser un programador) especifica qu datos se necesitan y cmo obtenerlos. Esto quiere decir que el usuario debe especificar todas las operaciones de acceso a datos llamando a los procedimientos necesarios para obtener la informacin requerida. Estos lenguajes

acceden a un registro, lo procesan y basndose en los resultados obtenidos, acceden a otro registro, que tambin deben procesar. As se va accediendo a registros y se van procesando hasta que se obtienen los datos deseados. Las sentencias de un lenguaje procedural deben estar embebidas en un lenguaje de alto nivel, ya que se necesitan sus estructuras (bucles, condicionales, etc.) para obtener y procesar cada registro individual.

Lenguajes de programacin orientados a objetos

En la Programacin Orientada a Objetos se definen los programas en trminos de "clases de objetos", objetos que son entidades que combinan estado (es decir, datos) comportamiento (esto es, procedimientos o mtodos) e identidad (propiedad del objeto que lo diferencia del resto). La programacin orientada a objetos expresa un programa como un conjunto de estos objetos, que colaboran entre ellos para realizar tareas. Esto permite hacer los programas mdulos ms fciles de escribir, mantener y reutilizar. De esta forma, un objeto contiene toda la informacin, (los denominados atributos) que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases (e incluso entre objetos de la misma clase, al poder tener valores bien diferenciados en sus atributos). A su vez, dispone de mecanismos de interaccin (los llamados mtodos) que favorecen la comunicacin entre objetos (de una misma clase o de distintas), y en consecuencia, el cambio de estado en los propios objetos. Esta caracterstica lleva a tratarlos como unidades indivisibles, en las que no se separan (ni deben separarse) informacin (datos) y procesamiento (mtodos).

Las principales diferencias entre la programacin imperativa y la programacin orientada a objetos:

La programacin orientada a objetos es ms moderna, es una evolucin de la programacin imperativa plasmada en el diseo de una familia de lenguajes conceptos que existan previamente, con algunos nuevos. La programacin orientada a objetos se basa en lenguajes que soportan sintctica y semnticamente la unin entre los tipos abstractos de datos y sus operaciones (a esta unin se la suele llamar clase). La programacin orientada a objetos incorpora en su entorno de ejecucin mecanismos tales como el polimorfismo y el envo de mensajes entre objetos.

Traductores. Definicin.

Un traductor (compilador o intrprete) es un software que lee un programa escrito en un lenguaje (lenguaje fuente) y lo traduce a un programa equivalente en otro lenguaje (lenguaje objeto). Como parte importante de este proceso de traduccin, el traductor informa a su usuario de la presencia de errores en el programa fuente. (Fig. 1.4)

Figura 1. 1. Traductor.

Etapas del proceso de traduccin.

El proceso de traduccin se divide en dos fases o etapas:

Fase de anlisis.- La parte del anlisis divide al programa fuente en sus elementos componentes y crea una representacin intermedia del programa fuente. Fase de sntesis.- La parte de la sntesis construye el programa objeto deseado a partir de la representacin intermedia.

De las dos partes, la sntesis es la que requiere las tcnicas ms especializadas. Adems de un traductor, se pueden necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en mdulos almacenados en archivos distintos. La tarea de reunir el programa fuente a menudo se confa a un programa distinto, llamado preprocesador. El preprocesador tambin puede expandir abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente. Es til pensar en estas fases como en piezas separadas dentro del traductor, y pueden en realidad escribirse como operaciones codificadas separadamente aunque en la prctica a menudo se integren juntas.

Fase de Anlisis

Anlisis lxico

El anlisis lxico constituye la primera fase, aqu se lee el programa fuente de izquierda a derecha y se agrupa en componentes lxicos (tokens), que son secuencias de caracteres que tienen un significado. Adems, todos los espacios en blanco, lneas en blanco, comentarios y dems informacin innecesaria se elimina del programa fuente. Tambin se comprueba que los smbolos del lenguaje (palabras clave, operadores,...) se han escrito correctamente. Como la tarea que realiza el analizador lxico es un caso especial de coincidencia de patrones, se necesitan los mtodos de especificacin y

reconocimiento de patrones, y estos mtodos son principalmente las expresiones regulares y los autmatas finitos. Sin embargo, un analizador lxico tambin es la parte del traductor que maneja la entrada del cdigo fuente, y puesto que esta entrada a menudo involucra un importante gasto de tiempo, el analizador lxico debe funcionar de manera tan eficiente como sea posible.

Anlisis sintctico

En esta fase los caracteres o componentes lxicos se agrupan jerrquicamente en frases gramaticales que el compilador utiliza para sintetizar la salida. Se comprueba si lo obtenido de la fase anterior es sintcticamente correcto (obedece a la gramtica del lenguaje). Por lo general, las frases gramaticales del programa fuente se representan mediante un rbol de anlisis sintctico. La estructura jerrquica de un programa normalmente se expresa utilizando reglas recursivas. Por ejemplo, se pueden dar las siguientes reglas como parte de la definicin de expresiones: 1. Cualquier identificador es una expresin. 2. Cualquier nmero es una expresin. 3. Si expresin1 y expresin2 son expresiones, entonces tambin lo son: expresin1 + expresin2 expresin1 * expresin2 ( expresin1 )

Las reglas 1 y 2 son reglas bsicas (no recursivas), en tanto que la regla 3 define expresiones en funcin de operadores aplicados a otras expresiones. La divisin entre anlisis lxico y anlisis sintctico es algo arbitraria. Un factor para determinar la divisin es si una construccin del lenguaje fuente es inherentemente recursiva o no. Las construcciones lxicas no requieren recursin,

mientras que las construcciones sintcticas suelen requerirla. No se requiere recursin para reconocer los identificadores, que suelen ser cadenas de letras y dgitos que comienzan con una letra. Normalmente, se reconocen los identificadores por el simple examen del flujo de entrada, esperando hasta encontrar un carcter que no sea ni letra ni dgito, y agrupando despus todas las letras y dgitos encontrados hasta ese punto en un componente lxico llamado identificador. Por otra parte, esta clase de anlisis no es suficientemente poderoso para analizar expresiones o proposiciones. Por ejemplo, no podemos emparejar de manera apropiada los parntesis de las expresiones, o las palabras begin y end en proposiciones sin imponer alguna clase de estructura jerrquica o de anidamiento a la entrada.

Anlisis semntico

La fase de anlisis semntico revisa el programa fuente para tratar de encontrar errores semnticos y rene la informacin sobre los tipos para la fase posterior de generacin de cdigo. En ella se utiliza la estructura jerrquica determinada por la fase de anlisis sintctico para identificar los operadores y operandos de expresiones y proposiciones. Un componente importante del anlisis semntico es la verificacin de tipos. Aqu, el compilador verifica si cada operador tiene operandos permitidos por la especificacin del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programacin requieren que el compilador indique un error cada vez que se use un nmero real como ndice de una matriz. Sin embargo, la especificacin del lenguaje puede imponer restricciones a los operandos, por ejemplo, cuando un operador aritmtico binario se aplica a un nmero entero y a un nmero real.

Fase de sntesis

Consiste en generar el cdigo objeto equivalente al programa fuente. Slo se genera cdigo objeto cuando el programa fuente est libre de errores de anlisis, lo cual no quiere decir que el programa se ejecute correctamente, ya que un programa puede tener errores de concepto o expresiones mal calculadas. Por lo general el cdigo objeto es cdigo de mquina relocalizable o cdigo ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa. Despus, cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de mquina que ejecuta la misma tarea. Un aspecto decisivo es la asignacin de variables a registros.

Generacin de cdigo intermedio

Despus de los anlisis sintctico y semntico, algunos compiladores generan una representacin intermedia explcita del programa fuente. Se puede considerar esta representacin intermedia como un programa para una mquina abstracta. Esta representacin intermedia debe tener dos propiedades importantes; debe ser fcil de producir y fcil de traducir al programa objeto. La representacin intermedia puede tener diversas formas. Existe una forma intermedia llamada "cdigo de tres direcciones" que es como el lenguaje ensamblador de una mquina en la que cada posicin de memoria puede actuar como un registro. El cdigo de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como mximo tres operandos. Esta representacin intermedia tiene varias propiedades: Primera.- Cada instruccin de tres direcciones tiene a lo sumo un operador, adems de la asignacin, por tanto, cuando se generan estas instrucciones, el traductor tiene que decidir el orden en que deben efectuarse las operaciones.

Segunda.- El traductor debe generar un nombre temporal para guardar los valores calculados por cada instruccin. Tercera.- Algunas instrucciones de "tres direcciones" tienen menos de tres operandos, por ejemplo, la asignacin.

Optimizacin de cdigo

La fase de optimizacin de cdigo consiste en mejorar el cdigo intermedio, de modo que resulte un cdigo mquina ms rpido de ejecutar. Esta fase de la etapa de sntesis es posible sobre todo si el traductor es un compilador (difcilmente un interprete puede optimizar el cdigo objeto). Hay mucha variacin en la cantidad de optimizacin de cdigo que ejecutan los distintos compiladores. En los que hacen mucha optimizacin, llamados "compiladores optimizadores", una parte significativa del tiempo del compilador se ocupa en esta fase. Sin embargo, hay optimizaciones sencillas que mejoran sensiblemente el tiempo de ejecucin del programa objeto sin retardar demasiado la compilacin.

Tipos de traductores

Existen dos tipos importantes de traductores: Los que van adaptando las instrucciones conforme son encontradas. A este proceso se lo llama interpretar y a los programas que lo hacen se los conoce como intrpretes. La traduccin es simultnea y se produce de forma dialogada con el programador. Los que convierten el conjunto de instrucciones en lenguaje de programacin, al programa equivalente escrito en lenguaje de mquina. A ese proceso se lo llama compilar y al programa traductor se le denomina compilador. No se

realiza simultneamente y no hay un dialogo con el programador durante la programacin.

Intrprete

Un intrprete es un programa informtico capaz de analizar y ejecutar otros programas, escritos en un lenguaje de alto nivel. Los intrpretes se diferencian de los compiladores en que mientras estos traducen un programa desde su descripcin en un lenguaje de programacin al cdigo mquina del sistema destino, los primeros (los intrpretes) slo realizan la traduccin a medida que sea necesario, tpicamente, instruccin por instruccin, y normalmente no guardan el resultado de dicha traduccin. Los programas interpretados suelen ser ms lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son ms flexibles como entornos de programacin y depuracin (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o aadir mdulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la mquina donde se ejecuta el intrprete, sino del propio intrprete (lo que se conoce comnmente como mquina virtual). Comparando su actuacin con la de un ser humano, un compilador equivale a un traductor profesional que, a partir de un texto, prepara otro independiente traducido a otra lengua, mientras que un intrprete corresponde al intrprete humano, que traduce de viva voz las palabras que oye, sin dejar constancia por escrito. En la actualidad, uno de los entornos ms comunes de uso de los intrpretes informticos es Internet, debido a la posibilidad que estos tienen de ejecutarse independientemente de la plataforma.

Compilador

Un compilador es un programa informtico que traduce un programa escrito en un lenguaje de programacin a otro lenguaje de programacin, generando un programa equivalente que la mquina ser capaz de interpretar. Usualmente el segundo lenguaje es cdigo mquina, pero tambin puede ser simplemente texto. Este proceso de traduccin se conoce como compilacin. Un compilador es un programa que permite traducir el cdigo fuente de un programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior (tpicamente lenguaje mquina). De esta manera un programador puede disear un programa en un lenguaje mucho ms cercano a cmo piensa un ser humano, para luego compilarlo a un programa ms manejable por una computadora. Normalmente los compiladores estn divididos en dos partes (Fig. 1.5): Front End: es la parte que analiza el cdigo fuente, comprueba su validez, genera el rbol de derivacin y rellena los valores de la tabla de smbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar. Back End: es la parte que genera el cdigo mquina, especfico de una plataforma, a partir de los resultados de la fase de anlisis, realizada por el Front End.

Figura 1. 2. Partes de un compilador

Esta divisin permite que el mismo Back End se utilice para generar el cdigo mquina de varios lenguajes de programacin distintos y que el mismo Front End que sirve para analizar el cdigo fuente de un lenguaje de programacin concreto sirva para generar cdigo mquina en varias plataformas distintas. El cdigo que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker).

CAPITULO 2
INTRODUCCIN A LA PROGRAMACIN ORIENTADA A OBJETOS

2.1.

Introduccin a la programacin orientada a objetos.

Desde principios de la era computacional se

crearon diversas tcnicas de

programacin que a medida han evolucionado para poder adaptarse a nuevos retos y poder crear soluciones ms realistas que se amolden a el entorno real. Podemos notar que a inicios la programacin era no estructurada. Este estilo de Programacin No Estructurada, consista en un solo programa principal, el cual se establece como una secuencia de comandos o instrucciones que modifican datos que son a su vez globales en el transcurso de todo el programa. Esta tcnica de programacin no estructurada ofrece tremendas desventajas una vez que el programa se hace suficientemente grande. Por ejemplo, si la misma secuencia de instrucciones se necesita en diferentes situaciones dentro del programa, la secuencia debe ser repetida. Esto ha llevado a la idea de extraer estas secuencias, dando origen a nuevas tcnicas como lo son la programacin procedimental y modular, conducindonos a un estilo de programacin estructurada. La Programacin Estructurada es un mtodo de programacin basado sobre el concepto de la unidad y del alcance. La programacin estructurada ofrece muchas ventajas sobre la programacin secuencial, es ms fcil de leer y ms conservable; siendo muy flexible, facilitando el buen diseo de programas. La programacin estructurada, es un estilo de programacin con el cual el programador elabora programas, cuya estructura es la ms clara posible, mediante el uso de tres estructuras bsicas de control lgico: secuencia, seleccin e iteracin.

Los programas son ms fciles de entender. Un programa estructurado puede ser ledo en secuencia, de arriba hacia abajo, sin necesidad de estar saltando de un sitio a otro en la lgica, lo cual es tpico de otros estilos de programacin. La estructura del programa es ms clara puesto que las instrucciones estn ms ligadas o relacionadas entre si, por lo que es ms fcil comprender lo que hace cada funcin. Reduccin del esfuerzo en las pruebas. El programa se puede tener listo para produccin normal en un tiempo menor del tradicional; por otro lado, el seguimiento de las fallas o depuracin se facilita debido a la lgica ms visible, de tal forma que los errores se pueden detectar y corregir ms fcilmente. Los programas quedan mejor documentados internamente. A pesar de las mltiples ventajas que ofrecen la programacin estructurada, surge necesidades y problemas complejos los cuales necesitan recrear o representar mundos reales, lo cual, se dificulta con la tcnicas de programacin estructurada. La Programacin Orientada a Objetos (POO) aporta un nuevo enfoque a los retos que se plantean en la programacin estructurada cuando los problemas a resolver son complejos. Al contrario que la programacin procedimental que enfatiza en los algoritmos, la POO enfatiza en los datos. En lugar de intentar ajustar un problema al enfoque procedimental de un lenguaje, POO intenta ajustar el lenguaje al problema. La idea es disear formatos de datos que se correspondan con las caractersticas esenciales de un problema. Los lenguajes orientados combinan en una nica unidad o mdulo, tanto los datos como las funciones que operan sobre esos datos. Tal unidad se llama objeto. Si se desea modificar los datos de un objeto, hay que realizarlo mediante las funciones miembro del objeto. Ninguna otra funcin puede acceder a los datos. Esto simplifica la escritura, depuracin y mantenimiento del programa. La tecnologa orientada a objetos se define como una metodologa de diseo de software que modela las caractersticas de objetos reales o abstractos por medio del uso de clases y objetos. Hoy en da, la orientacin a objetos es fundamental en el desarrollo de software, sin embargo, esta tecnologa no es nueva, sus orgenes se

remontan a la dcada de los aos sesenta (Simula, uno de los lenguajes de programacin orientados a objetos ms antiguos, fue desarrollado en 1967). La Programacin Orientada a Objetos, la podemos definir como una tcnica o estilo de programacin que utiliza objetos como bloque esencial de construccin. ASCUI El objeto, es el concepto principal sobre el cual se fundamenta la programacin orientada a objetos, el cual puede ser visto como una entidad que posee atributos y efecta acciones. En el mundo real podemos encontrar cientos de ejemplos que cumplen con sta definicin, algunos de ellos son: una bicicleta, un automvil, una persona, una computadora, etc. Los programas creados con la POO, se organizan como un conjunto finito de objetos que contienen datos y operaciones (funciones miembro en C++) que llaman a esos datos y que se comunican entre s mediante mensajes.(Figura 2.1).

Figura 2. 1. Representacin POO.

Un programa orientado a objetos es una coleccin de clases. Necesita de una funcin principal que cree objetos y comience la ejecucin mediante la invocacin de sus funciones o mtodos. En primer lugar, se crean los objetos. Segundo, los mensajes se envan desde unos objetos y se reciben en otros a medida que el programa se ejecuta. Y tercero, se borran los objetos cuando ya no son necesarios y se recupera la memoria ocupada por ellos.

Los objetos son tipos de datos abstractos definidos por el programador. En realidad son unidades que contienen datos y funciones que operan sobre esos datos. A los objetos tambin se les conoce como instancias de clase. A los elementos de un objeto se les conoce como miembros (datos miembros y funciones miembro).

2.1.1. Caractersticas de la POO

Las caractersticas ms importantes que debe soportar un lenguaje que lo definen como "orientado a objetos", son: Abstraccin. Encapsulamiento. Principio de ocultacin. Polimorfismo. Herencia. Recoleccin de basura.

2.1.1.1.

Abstraccin.

Denota las caractersticas esenciales de un objeto, donde se capturan sus comportamientos. Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar cmo se implementan estas caractersticas. Los procesos, las funciones o los mtodos pueden tambin ser abstrados y cuando lo estn, una variedad de tcnicas son requeridas para ampliar una abstraccin. Un ejemplo de esto puede identificarse en un automvil. Aunque se observa un automvil como un nico ente, este estar compuesto por: caractersticas y mtodos o funciones. (Figura 2.2).

Figura 2. 2. Objeto abstracto: automvil.

2.1.1.2.

Encapsulamiento.

Significa reunir a todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstraccin. Esto permite aumentar la cohesin de los componentes del sistema. La encapsulacin es un mecanismo que consiste en organizar datos y mtodos de una estructura, conciliando el modo en que el objeto se implementa, es decir, evitando el acceso a datos por cualquier otro medio distinto a los especificados. Por lo tanto, la encapsulacin garantiza la integridad de los datos que contiene un objeto. El encapsulamiento nos permite considerar a los objetos como cajas negras: como objetos que podemos utilizar sin enfocarnos en la forma en que trabajan.

Ejemplo: en un automvil, un mecnico debe saber cmo trabaja el motor, la transmisin, etc., pero un conductor, puede usar estos componentes sin preocuparse por estos detalles, el automvil encapsula todos los detalles de las partes que lo constituyen, por lo que un conductor tan solo necesita conocer su interfaz: el acelerador, el freno y el volante.

2.1.1.3.

Principio de ocultacin.

Cada objeto est aislado del exterior, es un mdulo natural, y cada tipo de objeto expone una interfaz a otros objetos que especfica cmo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificacin por quien no tenga derecho a acceder a ellas, solamente los propios mtodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstraccin. La aplicacin entera se reduce a un agregado o rompecabezas de objetos. El usuario de una clase en particular no necesita saber cmo estn estructurados los datos dentro de ese objeto, es decir, un usuario no necesita conocer la implementacin Al evitar que el usuario modifique los atributos directamente y forzndolo a utilizar funciones definidas para modificarlos (llamadas interfaces), se garantiza la integridad de los datos (por ejemplo, uno puede asegurarse de que el tipo de datos suministrados cumple con nuestras expectativas bien que los se encuentran dentro del periodo de tiempo esperado). La encapsulacin define los niveles de acceso para elementos de esa clase. Estos niveles de acceso definen los derechos de acceso para los datos, permitindonos el acceso a datos a travs de un mtodo de esa clase en particular, desde una clase heredada o incluso desde cualquier otra clase. Existen tres niveles de acceso: Pblico: funciones de toda clase pueden acceder a los datos o mtodos de una clase que se define con el nivel de acceso pblico. Este es el nivel de proteccin de datos ms bajo Privado: el acceso a los datos est restringido a los mtodos de esa clase en particular. Este es nivel ms alto de proteccin de datos

Protegido: el acceso a los datos est restringido a las funciones de clases heredadas, es decir, las funciones miembro de esa clase y todas las subclases

2.1.1.4.

Polimorfismo

Comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre, al llamarlos por ese nombre se utilizar el comportamiento correspondiente al objeto que se est usando. O dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocacin de un comportamiento en una referencia producir el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecucin", esta ltima caracterstica se llama asignacin tarda o asignacin dinmica. Algunos lenguajes proporcionan medios ms estticos (en "tiempo de compilacin") de polimorfismo, tales como las plantillas y la sobrecarga de operadores de C++. Polimorfismo de sobrecarga. El polimorfismo de sobrecarga ocurre cuando las funciones del mismo nombre existen, con funcionalidad similar, en clases que son completamente independientes una de otra (stas no tienen que ser clases secundarias de la clase objeto). Por ejemplo, la clase complex, la clase image y la clase link pueden todas tener la funcin "display". Esto significa que no necesitamos preocuparnos sobre el tipo de objeto con el que estamos trabajando si todo lo que deseamos es verlo en la pantalla. Por lo tanto, el polimorfismo de sobrecarga nos permite definir operadores cuyos comportamientos varan de acuerdo a los parmetros que se les aplican. As es posible, por ejemplo, agregar el operador + y hacer que se comporte de manera distinta cuando est haciendo referencia a una operacin entre dos nmeros enteros (suma) o bien cuando se encuentra entre dos cadenas de caracteres (concatenacin).

Polimorfismo paramtrico (tambin llamado polimorfismo de plantillas). El polimorfismo paramtrico es la capacidad para definir varias funciones utilizando el mismo nombre, pero usando parmetros diferentes (nombre y/o tipo). El polimorfismo paramtrico selecciona automticamente el mtodo correcto a aplicar en funcin del tipo de datos pasados en el parmetro. Por lo tanto, podemos por ejemplo, definir varios mtodos homnimos de addition() efectuando una suma de valores. El mtodo int addition(int, int) devolvera la suma de dos enteros. float addition(float, float) devolvera la suma de dos flotantes. char addition(char, char) dara por resultado la suma de dos caracteres.

Polimorfismo de inclusin (tambin llamado redefinicin o subtipado). La habilidad para redefinir un mtodo en clases que se hereda de una clase base se llama especializacin. Por lo tanto, se puede llamar un mtodo de objeto sin tener que conocer su tipo intrnseco: esto es polimorfismo de subtipado. Permite no tomar en cuenta detalles de las clases especializadas de una familia de objetos, enmascarndolos con una interfaz comn (siendo esta la clase bsica). Imagine un juego de ajedrez con los objetos rey, reina, alfil, caballo, torre y pen, cada uno heredando el objeto pieza. El mtodo movimiento podra, usando polimorfismo de subtipado, hacer el movimiento correspondiente de acuerdo a la clase objeto que se llama. Esto permite al programa realizar el movimiento de pieza sin tener que verse conectado con cada tipo de pieza en particular.

2.1.1.5.

Herencia.

Por herencia se entiende la capacidad de poder crear nuevas clases a partir de alguna anterior, de forma que las nuevas "heredan" las caractersticas de sus ancestros (propiedades y mtodos). Se trata por tanto de la capacidad de crear nuevos tipos de

datos a partir de los anteriores. Una caracterstica especial de la herencia es que si se cambia el comportamiento de la clase antecesora (tambin llamada padre, base o super), tambin cambiar el comportamiento de las clases derivadas de ella (descendientes). Como puede deducirse fcilmente, la herencia establece lo que se llama una jerarqua de clases del mismo aspecto que el rbol genealgico de una familia. Se entiende tambin que estos conceptos representan niveles de abstraccin que permiten acercar la programacin a la realidad del mundo fsico tal como lo concebimos. Por ejemplo, todas las guitarras, ya sean Elctricas, ElectroAcsticas o normales, cumplen con caractersticas similares como nmero de cuerdas (6), mtodo de afinacin, cambio de tono, cambio de postura y rasgueo entre otras. Si no se siguiera con una metodologa de herencia, por cada clase (Guitarra Electrica y ElectroAcstica) se tendra que repetir la definicin de todos los atributos y mtodos que pertenecen a la clase padre Guitarra, que corresponde a la abstraccin ms amplia del concepto "Guitarra". Mediante el uso de la herencia, se puede definir una clase "Guitarra" que cumpla con todas las caractersticas generales del concepto guitarra y sus evoluciones, con el fin de acotar el nmero de especificaciones de las clases "GuitarraElectrica" y "ElectroAcstica", y permitir la herencia a stas ltimas clases con las caractersticas del objeto padre. (Figura 2.3).

Figura 2. 3. Herencia.

2.1.1.6.

Recoleccin de basura.

La Recoleccin de basura o Garbage Collection es la tcnica por la cual el ambiente de Objetos se encarga de destruir automticamente, y por tanto desasignar de la memoria, los Objetos que hayan quedado sin ninguna referencia a ellos. Esto significa que el programador no debe preocuparse por la asignacin o liberacin de memoria, ya que el entorno la asignar al crear un nuevo Objeto y la liberar cuando nadie lo est usando. En la mayora de los lenguajes hbridos que se extendieron para soportar el Paradigma de Programacin Orientada a Objetos como C++ u Object Pascal, esta caracterstica no existe y la memoria debe desasignarse manualmente.

2.1.2. Uso de los lenguajes de POO

Actualmente una de las reas ms candentes en la industria y en el mbito acadmico es la orientacin a objetos. La orientacin a objetos promete mejoras de

amplio alcance en la forma de diseo, desarrollo y mantenimiento del software ofreciendo una solucin a largo plazo a los problemas y preocupaciones que han existido desde el comienzo en el desarrollo de software: la falta de portabilidad del cdigo y reusabilidad, cdigo que es difcil de modificar, ciclos de desarrollo largos y tcnicas de codificacin no intuitivas. La introduccin de tecnologa de objetos como una herramienta conceptual para analizar, disear e implementar aplicaciones permite obtener aplicaciones ms modificables, fcilmente extensibles y a partir de componentes reusables. Esta reusabilidad del cdigo disminuye el tiempo que se utiliza en el desarrollo y hace que el desarrollo del software sea ms intuitivo porque se piensa naturalmente en trminos de objetos ms que en trminos de algoritmos de software. La Programacin Orientada a Objetos ofrece algunas de ventajas respecto a otros paradigmas de la programacin: Fomenta la reutilizacin y extensin del cdigo. Facilita el mantenimiento del software. Permite crear sistemas ms complejos. Agiliza el desarrollo de software. Facilita la creacin de programas visuales. Facilita el trabajo en equipo relacionar el sistema al mundo real.

2.2.

Introduccin a las Clases y Objetos.

2.2.1.

Conceptos Clases y Objetos

Un objeto se define como la unidad que en tiempo de ejecucin realiza las tareas de un programa. Tambin a un nivel ms bsico se define como la instancia de una clase.

Estos objetos interactan unos con otros, en contraposicin a la visin tradicional en la cual un programa es una coleccin de subrutinas (funciones o procedimientos), o simplemente una lista de instrucciones para el computador. Cada objeto es capaz de recibir mensajes, procesar datos y enviar mensajes a otros objetos de manera similar a un servicio. (Figura 2.4). Un objeto es una abstraccin encapsulada que tiene un estado interno como dado por una lista de atributos cuyos valores son nicos al objeto. El objeto tambin conoce la lista de mensajes al que puede responder y cmo responder en cada uno. Un objeto est constituido por:

Atributos: estos son los datos que caracterizan al objeto. Son variables que almacenan datos relacionados al estado de un objeto.

Mtodos (usualmente llamados funciones miembro): Los mtodos de un objeto caracterizan su comportamiento, es decir, son todas las acciones (denominadas operaciones) que el objeto puede realizar por s mismo. Estas operaciones hacen posible que el objeto responda a las solicitudes externas (o que acte sobre otros objetos). Adems, las operaciones estn estrechamente ligadas a los atributos, ya que sus acciones pueden depender de, o modificar, los valores de un atributo.

Figura 2. 4. Constitucin de objetos.

Una clase es la estructura de un objeto, es decir, la definicin de todos los elementos de que est hecho un objeto. Un objeto es, por lo tanto, el "resultado" de

una clase. En realidad, un objeto es una instancia de una clase, por lo que se pueden intercambiar los trminos objeto o instancia (o incluso evento). Los objetos son miembros o pertenecen a una clase. Una clase es un tipo definido por el usuario que determina las estructuras de datos y las operaciones asociadas con ese tipo. Las clases son como plantillas o modelos que describen cmo se construyen ciertos tipos de objetos. Incluye en su descripcin un nombre para el tipo de objeto, una lista de atributos (y sus tipos), y una lista de mensajes con mtodos correspondientes al que un objeto de la clase puede responder. Cada vez que se construye un objeto de una clase, se crea una instancia de esa clase. Una clase se compone de dos partes: Atributos (denominados, por lo general, datos miembros): esto es, los datos que se refieren al estado del objeto Mtodos (denominados, por lo general, funciones miembros): son funciones que pueden aplicarse a objetos

2.2.2.

Sintaxis de la definicin de clases

Una clase define la estructura que tendrn los objetos que se creen a partir de esta, la cual contiene las caractersticas de los objetos o atributos y los mtodos o funciones miembros necesarios para modificar y evaluar los atributos. Se describen tambin el tipo de ocultamiento que posee cada atributo y mtodo. Si tenemos una clase llamada auto, los objetos Peugeot y Renault sern instancias de esa clase. Tambin puede haber otros objetos Peugeot 406, diferenciados por su nmero de modelo. Asimismo, dos instancias de una clase pueden tener los mismos atributos, pero considerarse objetos distintos independientes. En un contexto real: dos camisas pueden ser idnticas, pero no obstante, tambin ser diferentes de alguna manera. Sin embargo, si las mezclamos es imposible distinguir una de la otra.

La sintaxis tpica de una clase es: clase Nombre { // Variables miembro (habitualmente privadas) miembro_1; //lista de miembros miembro_2; miembro_3; ... // Funciones o mtodos (habitualmente pblicas) funcion_miembro_1( ); //funciones miembro conocidas funcion_miembro_2 ( ); // funciones como mtodos ... // Propiedades (habitualmente pblicas) propiedad_1; propiedad_2; propiedad_3; ... }

2.2.3.

Mensajes y mtodos

Los objetos, las clases y sus instancias se comunican a travs del paso de mensajes. Esto elimina la duplicacin de datos y garantiza que no se propaguen los efectos de los cambios en las estructuras de datos encapsuladas dentro de objetos sobre otras partes del sistema. A menudo los mensajes se realizan como llamadas a funciones. El mensaje es la accin que realiza un objeto sobre otro, la peticin de servicio. Se considera al mensaje como una llamada, posiblemente comprendido en el tiempo de ejecucin, al objeto o clase que pide un servicio o la notificacin de un suceso especfico. Un mensaje es representado por un identificador, o combinacin de identificadores que implican una accin para ser tomada por un objeto. Los mensajes pueden ser simples o pueden incluir parmetros que afectan como el objeto receptor

responde. La manera en que un objeto responde al mensaje puede tambin ser afectado por los valores de sus atributos. El mtodo es la respuesta al mensaje, la forma de proporcionar el servicio. Un mtodo consiste en la implementacin en una clase de un protocolo de respuesta a los mensajes dirigidos a los objetos de la misma. La respuesta a tales mensajes puede incluir el envo por el mtodo de mensajes al propio objeto y aun a otros, tambin como el cambio del estado interno del objeto.(Figura 2.5).

Figura 2. 5. Comunicacin entre objetos.

2.2.4.

Mtodos constructores y destructores

Un mtodo constructor es una funcin miembro especial que lleva a cabo la inicializacin automtica de cada objeto de la clase en el momento en que se declara. Un constructor es una funcin miembro pblica con el mismo nombre de la clase, sin indicacin de tipo devuelto y se ejecuta automticamente al crearse un objeto de la clase. Cuando un objeto no va a ser utilizado, el espacio de memoria de dinmica que utiliza ha de ser liberado, as como los recursos que posea, permitiendo al programa disponer de todos los recursos posibles. A esta accin se la da el nombre de destruccin del objeto. El sistema de recogida de basura se ejecuta peridicamente, buscando objetos que ya no estn referenciados. Todas las clases tienen uno y slo un destructor. Si no se indica lo contrario, el compilador genera un destructor por defecto cuya nica funcin es liberar el espacio que ocupan los miembros estticos (no reservados dinmicamente) del objeto que se

destruye. El destructor es una funcin miembro que realiza la tarea de limpieza. Un destructor es una funcin miembro pblica con el mismo nombre de la clase pero precedido por el smbolo (~), sin indicacin de tipo devuelto, que se ejecuta automticamente cuando se destruye un objeto.

2.2.5.

Definicin de datos miembro

Un dato miembro representan los datos internos del objeto, se define fuera de cualquier mtodo pero dentro de la clase, es una buena costumbre definirlos inmediatamente despus de la llave que abre la clase, es decir antes de la definicin de cualquier mtodo. Para definir un dato miembro:

Modificador_de_visibilidad tipo nombre;

El tipo de un dato miembro puede ser un tipo de datos primitivo o un objeto. Los modificadores de visibilidad controlan el acceso al dato miembro de la clase. Pueden ser aplicados tanto a mtodos como a datos miembro y son: Pblico Privado Protegidos Si un mtodo o dato tiene visibilidad pblica entonces puede ser referenciado directamente desde fuera del objeto y si tiene visibilidad privada no puede ser referenciada externamente solo puede ser usada dentro de la clase, si la visibilidad es protegida solo podr ser referenciada a travs de mtodos dentro de la misma clase nicamente. En general, si un mtodo ofrece servicios de una clase, puede ser declarado con visibilidad pblica. La encapsulacin evita que los valores sean cambiados por cualquiera. Por defecto la visibilidad es privada. Los datos miembros

de una clase tienen que ser privados, no pblicos ni protegidos. De esta manera aseguramos la encapsulacin de la clase.

2.2.6.

Definicin de funciones miembro.

Son funciones que pueden aplicarse a los objetos, son las acciones o operaciones que puede realizar un objeto. Las funciones pueden ser: estticas, no estticas, constructoras, etc. Para definir una funcin:

Modificador_Visibilidad modificador_tipoRegreso nombre (parmetros) { } //cuerpo

El modificador de visibilidad puede ser pblico o privado. El tipo de regreso puede ser: un tipo primitivo, una clase o bien sin retorno. Los nombres de las funciones miembro (mtodos) de una clase tiene que ser autoexplicativos de la finalidad de dichos mtodos. Como ocurra con las funciones. Las funciones miembros de una clase que no modifiquen los datos miembros ni llamen a funciones que modifiquen los datos miembros de la misma deberan declararse como constantes. De otra forma los objetos creados como constantes no tendran acceso a las funciones miembro de la clase.

2.3.

Estructura de un Programa Orientado a Objetos.

La programacin orientada a objetos (POO) es una de las tcnicas ms modernas de desarrollo que trata de disminuir el coste del software, aumentando la eficiencia y reduciendo el tiempo de espera para la puesta en escena de una nueva aplicacin. Por eso, donde la POO toma verdadera ventaja es en poder compartir y

reutilizar el cdigo. Existen varios lenguajes que permiten escribir un programa orientado a objetos y entre ellos se encuentra C++. Se trata de un lenguaje de programacin basado en el lenguaje C, compilado, estandarizado, ampliamente difundido, y con una biblioteca estndar C++ que lo ha convertido en un lenguaje universal, de propsito general, y ampliamente utilizado tanto en el mbito profesional como en el educativo. El lenguaje C++ es tomado como lenguaje de aprendizaje en este material de apoyo por todas las caractersticas que nos brinda C++ es un lenguaje de programacin diseado a mediados de los aos 1980 por Bjarne Stroustrup. La intencin de su creacin fue el extender al exitoso lenguaje de programacin C con mecanismos que permitan la manipulacin de objetos. En ese sentido, desde el punto de vista de los lenguajes orientados a objetos, el C++ es un lenguaje hbrido. Posteriormente se aadieron facilidades de programacin genrica, que se sum a los otros dos paradigmas que ya estaban admitidos (programacin estructurada y la programacin orientada a objetos). Por esto se suele decir que el C++ es un lenguaje de programacin multiparadigma. Una particularidad del C++ es la posibilidad de redefinir los operadores (sobrecarga de operadores), y de poder crear nuevos tipos que se comporten como tipos fundamentales. La meta de C++ es mejorar la productividad. sta viene por muchos caminos, pero el lenguaje est diseado para ayudarle todo lo posible, y al mismo tiempo dificultarle lo menos posible con reglas arbitrarias o algn requisito que use un conjunto particular de caractersticas. C++ est diseado para ser prctico; las decisiones de diseo del lenguaje C++ estaban basadas en proveer los beneficios mximos al programador.

2.3.1. Estructura de un programa en C ++.

El lenguaje de programacin C++ nos expresa un conjunto le reglas semnticas, sintcticas, lxico, necesarias para que la computadora pueda entender lo que se pide o quiere, de no ser adecuada una expresin introducida no podr ser entendida. Existen variedad de errores sintcticos que la maquina es capaz de discernir y denunciar, para mayor facilidad del usuario. Un programa en el lenguaje C++ estar compuesto por: Comentarios: Muestra informacin en cuanto a que realiza el programa, la utilidad de las funciones, variables y objetos, estos no sern procesados por el compilador. Encabezados: se realizan las llamadas y accesos a archivos de Biblioteca de funciones estndar y diseadas por los usuarios. Definiciones de prototipos: se definen las estructuras de nuevos tipos de datos como lo son las clases, estructuras, etc., se implementan las funciones que cumplirn un objetivo determinado. Declaraciones globales: Se manifiestan el uso de variables, objetos, constantes, etc., el mbito de estas se extiende desde el punto en el que se definen hasta el final del programa, proporcionan un mecanismo de intercambio de informacin entre funciones sin necesidad de utilizar argumentos. Adems se declaran las existencias de funciones si no han sido implementadas. Declaraciones locales: Se manifiesta la existencia de variables, objetos, constantes, etc., que sern utilizadas en una funcin determinada o cuerpo, la cual no podr extender su mbito de existencia fuera de la funcin. Declaracin de la funcin principal main( ): La funcin main es imprescindible en cualquier programa C/C++ representa el punto de inicio de su ejecucin. Es la funcin de control principal de un programa, reflejndose como el cuerpo del mismo programa.

Implementacin y cuerpo de funciones: Se define la forma o cuerpo de una funcin para resolver determinada tarea.

Ejemplo:
#include <iostream.h> // Encabezados permite inclusin de biblioteca class Punto { // Definicin de prototipo public: int x, y; public: Punto(int x, int y) {x=0; y=0;} int extraer_x( ) { return x; } int extraer_y( ) { return y; } }; Punto aux; //Objeto aux declarado global void main( ) //Cuerpo de Programa { Punto punto; // Objeto punto declarado local

cout << "Coordenada X:" << punto.extraer_x( ) << endl; cout << "Coordenada Y:" << punto.extraer_y( )<< endl; }

Como observamos en el ejemplo, un programa ser una secuencia de lneas que contendrn instrucciones, expresiones, sentencias, directivas de compilacin, comentarios, smbolos, etc.

2.3.1.1.

Operadores de lnea

En el lenguaje se utilizaran conjuntos de smbolos denominados operadores de lnea que permiten dar orden y control en las lneas de cdigo. Entre estos tenemos:

operador de separacin, operador de fin de instruccin, operadores de comentarios, operadores de agrupacin o bloque.

2.3.1.1.1.

Operadores de comentarios ( //, /* */)

Estos smbolos nos permiten indicar la presencia de un comentario, el cual no es ms que la documentacin de algn propsito a cumplir en el programa, solo ser de carcter informativo a los usuarios. Es decir, lo encontrado dentro de estos no ser procesado por el compilador, por lo tanto la maquina no notara la existencia del contenido en la ejecucin del programa. Los comentarios se introducirn en el programa separados por /* y */ (comentario de bloque) o comenzndolos con // (comentario de lnea). Los comentarios entre /* y */ pueden tener la longitud que queramos, pero no se anidan, es decir, si escribimos /* hola /* amigo */ mo */, el compilador interpretar que el comentario termina antes de mo, y dar un error. Los comentarios que comienzan por // slo son vlidos hasta el final de la lnea en la que aparecen. El uso de los comentarios son opcionales ya que no intervienen directamente sobre el programa.

2.3.1.1.2.

Operador de fin de instruccin (;)

El punto y coma es uno de los operadores ms usados en C++; este se usa con el fin de indicar el final de una lnea de instruccin. El punto y coma es de uso obligatorio, toda instruccin deber ser finalizada por este operador sino se generara un error, excepto en el uso de directivas y definicin de funciones. Tambin es conocido como sentencia nula al ser controlada por una sentencia cclica o al usarse innecesariamente de forma repetida.

instruccin1;

// el operador ; indica el fin de la instruccin1

instruccion2;;;

// el primer operador ; indica el fin de la instruccin2 // los siguiente operadores ; indica sentencias nulas

El punto y coma se usa tambin separador de contadores, condicionales e incrementadores dentro de un sentencia for.

2.3.1.1.3.

Operadores de agrupacin o bloque ({ })

Un bloque es un grupo de instrucciones contenidas entre los smbolos de llave izquierda '{' (inicio de bloque) y llave derecha '}' (fin de bloque). Las sentencias compuestas se agrupan en bloques que pueden contener combinaciones de sentencias elementales (denominadas sentencias de expresin) y otras sentencias compuestas. As las sentencias compuestas pueden estar anidadas, una dentro de otra. Cada inicio de bloque debe tener un fin de bloque. Su uso es obligatorio en la definicin de funciones, prototipos, sentencias que controles ms de una instruccin y opcionalmente pueden aparecer en cualquier otra parte del programa.

void main() { Instruccin_a; { Instruccin_b; Instruccin_c; } }

2.3.1.1.4.

Operador separacin (,)

La coma tiene una doble funcin, por una parte separa elementos de una lista de argumentos de una funcin. Por otra, puede ser usado como separador en expresiones

"de coma". Ambas funciones pueden ser mezcladas, pero hay que aadir parntesis para resolver las ambigedades.

E1, E2, ..., En ;

En una expresin "de coma", cada operando es evaluado como una expresin, pero los resultados obtenidos anteriormente se tienen en cuenta en las subsiguientes evaluaciones. Por ejemplo:

func(i, (j = 1, j + 4), k);

Llamar a la funcin con tres argumentos: (i, 5, k). La expresin de coma (j = 1, j+4), se evala de izquierda a derecha, y el resultado se pasar como argumento a la funcin.

2.3.1.2.

Directivas

El preprocesador analiza el fichero fuente antes de la fase de compilacin real, y realiza las sustituciones de macros y procesa las directivas de compilacin (C++ es un lenguaje compilado). Una directiva de compilacin o preprocesador es una lnea cuyo primer carcter es un #. Las directivas sern instrucciones que le daremos al compilador para indicarle que realice alguna operacin antes de compilar nuestro programa, como el incluir funciones de alguna biblioteca como son los encabezados. Algunas de las directivas tenemos: #define, sirve para definir macros. Las macros suministran un sistema para la sustitucin de palabras, con y sin parmetros.

#define identificador_de_macro <secuencia>

El preprocesador sustituir cada ocurrencia del identificador_de_macro en el fichero fuente, por la secuencia. Cada sustitucin se conoce como una expansin de la macro. La secuencia es llamada a menudo cuerpo de la macro. #include, permite insertar ficheros externos dentro de nuestro fichero de cdigo fuente. Estos ficheros son conocidos como ficheros incluidos, ficheros de cabecera o "headers".

#include <nombre de fichero cabecera> #include "nombre de fichero de cabecera" #include identificador_de_macro

El preprocesador elimina la lnea #include y, conceptualmente, la sustituye por el fichero especificado. El tercer caso haya el nombre del fichero como resultado de aplicar la macro.El cdigo fuente en si no cambia, pero el compilador observa el fichero incluido. La diferencia entre escribir el nombre del fichero entre < > o " ", est en el algoritmo usado para encontrar los ficheros a incluir. En el primer caso el preprocesador buscar en los directorios "include" definidos en el compilador (libreras estndar). En el segundo, se buscar primero en el directorio actual, es decir, en el que se encuentre el fichero fuente, si no existe en ese directorio, se trabajar como el primer caso (libreras creadas por el usuario).

2.3.1.3.

Palabras reservadas

El lenguaje C++ est compuesto por un conjunto de palabras reservadas que tiene un significado determinado para el compilador, de manera tal que cuando las encuentra en el programa sabe que hay que llevar a cabo una determinada accin. Las variables que se declaren a lo largo de todo el programa, as como las funciones y dems no pueden llevar el nombre de estas palabras reservadas, ya que son de uso por parte del compilador, ya que si se hace esto, se produciran errores, por lo que es importante tener una buena familiarizacin con las mismas, a fin de no cometer errores. Algunas de las palabras reservadas del lenguaje se muestran en la tabla siguiente (Figura 2.6.):

Palabras reservadas lenguaje C++


asm catch default enum for int operator return struct true unsigned while Figura 2. 6. Tabla de palabras reservadas en C++. auto char delete explicit friend long private short switch try using bool class do extern goto mutable protected signed template typedef virtual break const double false if namespace public sizeof this typename void case continue else float inline new register static throw union volatile

asm. Medio definido por la puesta en prctica de utilizacin de lenguaje de ensamblaje a lo largo de C++ .

break. La declaracin de pausa o descanso manda pasar el argumento al partidario de la declaracin, es utilizada en las llamadas a do, while, for o switch. case. Se define dentro de una estructura switch, case, y default. const. Variable contante cuyo valor no puede ser alterado. continue. Envo de los pasos a seguir sin detenerse como es caso siguiente. catch. Maneja una excepcin generado por un throw. class. Define una nueva clase. Pueden crearse objetos de esta clase. delete. Destruye un objeto de memoria creado con new. new. Asigna dinmicamente un objeto de memoria libre. Determina automticamente el tamao del objeto. friend. Declara una funcin o una clase que sea un friend (amigo) de otra clase. Los amigos pueden tener acceso a todos los miembros de datos y a todas las funciones miembro de una clase. operador. Declara un operador homnimo. private. Un miembro de clase accesible a funciones miembro y a funciones friend de la clase de miembros private. protected. Una forma extendida de acceso private; tambin se puede tener acceso a los miembros protected por funciones miembros de clases derivadas y amigos de clases derivadas. public. Un miembro de clase accesible a cualquier funcin. template. Declara variedad de tipos. this. Un apuntador declarado en forma implcita en toda funcin de miembro no static de una clase. Seales al objeto al cual esta funcin miembro ha sido invocada. como construir una clase o una funcin, usando una

throw. Transfiere control a un manejador de excepcin o termina la ejecucin del programa si no puede ser localizado un manejador apropiado. virtual. Declara una funcin virtual.

2.3.1.4.

Identificadores.

Los identificadores son palabras no reservadas correspondientes a nombres de declaraciones de variables, constantes, prototipos, funciones, etc. Debemos seguir ciertas reglas al nombrar tipos de datos, variables, funciones, etc. Los identificadores vlidos del C++ son los formados a partir de los caracteres del alfabeto (el ingls, no podemos usar ni la ni palabras acentuadas), los dgitos (0...9) y el subrayado (_), la nica restriccin es que no podemos comenzar un identificador con un dgito (es as porque se podran confundir con literales numricos). Hay que sealar que el C++ distingue entre maysculas y minsculas, por lo que Hola y hola representan dos cosas diferentes. Hay que evitar el uso de identificadores que slo difieran en letras maysculas y minsculas, porque inducen a error.

2.3.1.5.

Ejemplo de un programa en C++.

Un programa simple puede ser el siguiente:

/* Este es un programa simple en C++, escribe una frase en la pantalla */ #include <iostream.h>

int main( ) { cout << "Hola mundo\n"; return 0; } // imprime en la pantalla la frase "hola mundo"

Analizando el cdigo del ejemplo observamos: La primera parte separada entre /* y */ es un comentario. Es recomendable que se comenten los programas, explicando que es lo que estamos haciendo en cada caso, para que cuando se lean sean ms comprensibles. La lnea que empieza por # es una directiva. En este caso indica que se incluya el fichero "iostream.h", que contiene las definiciones para entrada/salida de datos en C++. En la declaracin de main ( ) hemos incluido la palabra reservada int, que indica que la funcin devuelve un entero al finalizar su propsito. La llave izquierda nos indica el inicio del cuerpo de la funcin main ( ). La sentencia separada entre llaves indica que se escriba la frase "Hola mundo". El operador << escribe (inserta) el segundo argumento en el primero. En este caso la cadena "Hola mundo\n" se escribe en la salida estndar (cout). El carcter \ seguido de otro carcter indica un solo carcter especial, en este caso un salto de lnea (\n). La palabra reservada return nos indica retornar un valor de la mismo tipo que el definido en la funcin. En este caso retornamos el valor numrico entero 0. La llave derecha nos indica el fin del cuerpo de la funcin main ( ).

CAPITULO 3
TIPOS DE DATOS

3.1.

Tipos de datos.

C++ no soporta un gran nmero de tipos de datos predefinidos, pero tiene la capacidad para crear sus propios tipos de datos. Posee un conjunto de tipos simples correspondientes a las unidades de almacenamiento tpicas de un computador y a las distintas maneras de utilizarlos. Todos los tipos de datos simples o bsicos de C/C++ son, esencialmente, nmeros. Los tres tipos de datos bsicos son: Enteros: int Nmeros flotantes (reales): float, double Caracteres: char Los tipos simples de datos admitidos se muestran en la siguiente tabla de rango de valores. (Figura 3.1)

Denominacin char int float

Tipo de datos Carcter Nmero entero Nmero real de precisin simple Nmero real de precisin doble Tipo vaco

Tamao en bits 8 16 32

Rango de valores de 0 a 255 de 32768 a 32767 de 3.4 x 10-38 a 3.4 x 1038

double void

64 0

de 1.7 x 10-308 a 1.7 x 10308 sin valor

Figura 3. 1. Tabla de los tipos de datos simples en C++.

Los tamaos en bits pueden variar dependiendo del compilador empleado. Por ejemplo, gcc interpreta que el entero es de 32 bits, y para usar enteros de 16 bits hay que indicarlo expresamente. Por tanto, no debe usted presuponer ningn tamao concreto para los tipos si quiere escribir programas portables. El tipo char se usa normalmente para variables que guardan un nico carcter, aunque lo que en realidad guardan es un cdigo ASCII, es decir, un nmero entero de 8 bits sin signo (de 0 a 255). Los caracteres se escriben siempre entre comillas simples (). Por lo tanto, si suponemos que x es una variable de tipo char, estas dos asignaciones tienen exactamente el mismo efecto, ya que 65 es el cdigo ASCII de la letra A: x = 'A'; x = 65; A diferencia de las comillas simples de los caracteres sueltos cadenas de caracteres se escriben con comillas dobles (). El tipo int se usa para nmeros enteros, mientras que los tipos float y double sirven para nmeros reales. El segundo permite representar nmeros mayores, a costa de consumir ms espacio en memoria. Un tipo especial del C++ es el denominado void (vaco). Este tipo tiene caractersticas muy peculiares, ya que es sintcticamente igual a los tipos elementales pero slo se emplea junto a los derivados, es decir, no hay objetos del tipo void. Se emplea para especificar que una funcin no devuelve nada, para declarar funciones sin argumentos; o como base para punteros a objetos de tipo desconocido. Por ejemplo:

void BoraPrantalla (void);

indica que la funcin BorraPantalla no tiene parmetros y no retorna nada.

3.1.1. Modificadores de tipo.

Existen, adems, unos modificadores de tipo que pueden preceder a los tipos de datos. Dichos modificadores son: signed: obliga a que los datos se almacenen con signo. unsigned: los datos se almacenan sin signo. long: los datos ocuparn el doble de espacio en bits del habitual, y, por lo tanto, aumentar su rango de valores. short: los datos ocuparn la mitad del espacio habitual, y, por lo tanto, disminuir su rango de valores.. De este modo, nos podemos encontrar, por ejemplo, con estos tipos de datos: unsigned int: Nmero entero de 16 bits sin signo. Rango: de 0 a 65535. signed int: Nmero entero de 16 bits con signo. No tiene sentido, porque el tipo int ya es con signo por definicin, pero es sintcticamente correcto. signed char: Carcter (8 bits) con signo. Rango: de 128 a 127 long int: Nmero entero de 32 bits. Rango: de 2147483648 a 2147483647 Incluso podemos encontrar combinaciones de varios modificadores. Por ejemplo: unsigned long int: Nmero entero de 32 bits sin signo. Rango: de 0 a 4294967295 3.1.2. Tipos enumerados.

Un tipo especial de tipos enteros son los tipos enumerados. Estos tipos sirven para definir un tipo que slo puede tomar valores dentro de un conjunto limitado de valores. Estos valores tienen nombre, luego se da una lista de constantes asociadas a este tipo. La sintaxis es:

enum booleano {FALSE, TRUE};

// definimos el tipo booleano

Aqu hemos definido el tipo booleano que puede tomar los valores FALSE o TRUE. En realidad hemos asociado la constante FALSE con el nmero 0, la constante TRUE con 1, y si hubiera ms constantes seguiramos con 2, 3, etc. Si por alguna razn nos interesa dar un nmero concreto a cada valor podemos hacerlo en la declaracin:

enum colores {rojo = 4, azul, verde = 3, negro = 1};

El azul tomar el valor 5 (4+1), ya que no hemos puesto nada. Tambin se pueden usar nmeros negativos o constantes ya definidas. Si al definir un tipo enumerado no se le da nombre al tipo declaramos una serie de constantes:

enum { CERO, UNO, DOS };

Hemos definido las constantes CERO, UNO y DOS con los valores 0, 1 y 2.

3.1.3. Tipos derivados

De los tipos fundamentales podemos derivar otros mediante el uso de los siguientes operadores de declaracin:

* Puntero: Para cualquier tipo T, el puntero a ese tipo es T*. Una variable de tipo T* contendr la direccin de un valor de tipo T. & Referencia: Una referencia es un nombre alternativo a un objeto, se emplea para el paso de argumentos y el retorno de funciones por referencia. T& significa referencia a tipo T.

[] Arreglos: Para un tipo T, T[n] indica un tipo arreglo con n elementos. Los ndices del arreglo empiezan en 0, luego llegan hasta n-1. Podemos definir arreglos multidimensionales como arreglos de arreglos. () Funcin: La declaracin de una funcin nos da el nombre de la funcin, el tipo del valor que retorna y el nmero y tipo de parmetros que deben pasrsele. Ejemplos:

int *n; int v[20]; int *c[20];

// puntero a un entero // arreglo de 20 enteros // arreglo de 20 punteros a entero

void f(int j); // funcin con un parmetro entero

3.1.4. Tipos compuestos

Los tipos de datos compuestos en C++ son: Estructuras. Las estructuras son el tipo equivalente a los registros de otros lenguajes, se definen poniendo la palabra struct delante del nombre del tipo y colocando entre llaves los tipos y nombres de sus campos. Si despus de cerrar la llave ponemos una lista de variables las declaramos a la vez que definimos la estructura. Uniones. Las uniones son idnticas a las estructuras en su declaracin, con la particularidad de que todos sus campos comparten la misma memoria (el tamao de la unin ser el del campo con un tipo mayor). Clases. Las clases son estructuras con una serie de caractersticas especiales.

3.1.5. Datos estticos y datos dinmicos

Otra forma de clasificar los tipos de datos: Datos estticos: su tamao y forma es constante durante la ejecucin de un programa y, por tanto, se determinan en tiempo de compilacin. El ejemplo tpico son los arreglos. Tienen el problema de que hay que dimensionar la estructura de antemano, lo que puede conllevar desperdicio o falta de memoria. Datos dinmicos: su tamao y forma es variable (o puede serlo) a lo largo de un programa, por lo que se crean y destruyen en tiempo de ejecucin. Esto permite dimensionar la estructura de datos de una forma precisa: se va asignando memoria en tiempo de ejecucin segn se va necesitando.

3.2.

Variables y constantes.

3.2.1. Variable.

En C/C++ una variable es una posicin con nombre en memoria donde se almacena un valor de un cierto tipo de dato y puede ser modificado. Las variables pueden almacenar todo tipo de datos: Caracteres, nmeros, estructuras. Las variables estn compuestas por dos partes importantes que son: El contenido, que es el valor que se almacena o est almacenado en la variable y est directamente relacionada al mismo nombre de la variable. La direccin de memoria, que nos indica la posicin o direccin donde se almacena el contenido de la variable en la memoria de ejecucin. Esta se representa mediante el operador de direccin & acompaada del nombre de la variable.

Sea una variable con el nombre A. Se representa de esta: su contenido es A, y su direccin es &A. (Figura 3.2)

Figura 3. 2. Variable.

3.2.1.1.

Declaracin de las variables

Una variable tpicamente tiene un nombre (un identificador) que describe su propsito. Toda variable utilizada en un programa debe ser declarada previamente. La definicin utilizada en un programa en cualquier parte del programa. Una definicin reserva un espacio de almacenamiento en memoria. El procedimiento para definir (crear) una variable es escribir el tipo de dato, el identificador o nombre de la variable y, en ocasiones, el valor inicial que tomar. La declaracin de variables puede considerarse como una sentencia. Desde este punto de vista, la declaracin terminar con un ";". Sintaxis de declaracin de una variable:

tipodato nombrevariable;

Ejemplos:

int a; float d; char e;

Sintaxis de declaracin de n variables:

tipodato nomvar1, nomvar2, nomvar3,, nomvarn;

Ejemplo:

int a, b, c;

Cuando declaramos ms de una variable usando el separador (,), estas reservan posiciones de memorias consecutivas del tamao indicado por el tipo de dato. Observando el ejemplo anterior se notara que las variables a, b y c reservan

posiciones de memoria del tamao del tipo de dato int que es de 2 bytes. Es decir que si la direccin de la variable a (&a) es 0x1000, entonces la direccin de la variable b (&b) ser la igual a la siguiente posicin de memoria del tamao del tipo int, 0x1002 (las posiciones de memoria del computador se representan en notacin hexadecimal y su tamao ser de 1 byte). (Figura 3.3)

Figura 3. 3. Declaracin de variables consecutivas.

Tambin es posible inicializar las variables dentro de la misma declaracin. Sintaxis de declaracin e inicializacin de variables:

tipodato nombrevariable = inicializacin; tipodato nomvar1=inicial1, nomvar2=inicial2, , nomvarn= inicialn;

Ejemplos:

int a = 5; int a = 2, b = 4, c = 6;

Las variables no inicializadas tienen un valor, este valor lo conocemos como "basura", ya que el valor es desconocido que puede interferir en un programa. Las variables no pueden tener el mismo nombre que una palabra reservada del lenguaje. No se les pueden colocar espacios en blanco. Los nombres de variables solo pueden tener letras, dgitos numricos y el guin bajo subguin (_).

Los nombres de variables no pueden llevar caracteres especiales, ejemplo: caracteres acentuados, , *, /, -, etc. Deben comenzar por un carcter (letra no numero) o tambin pueden comenzar con un guin bajo (_), ejemplo: _costo.

3.2.1.2.

mbito de las variables

Dependiendo de dnde se declaren las variables, podrn o no ser accesibles desde distintas partes del programa. Las variables declaradas dentro de un bucle, sern accesibles slo desde el propio bucle, sern de mbito local del bucle. Las variables declaradas dentro de una funcin, slo sern accesibles desde esa funcin. Esas variables son variables locales o de mbito local de esa funcin. Las variables declaradas fuera de las funciones, normalmente antes de definir las funciones, en la zona donde se declaran los prototipos, sern accesibles desde todas las funciones. Estas variables sern globales o de mbito global.

3.2.1.2.1.

Variables Locales

Las variables locales son aquellas definidas en el interior de una funcin y son visibles slo en esta funcin especfica. Las reglas por las que se rigen las variables locales son: En el interior de una funcin, una variable local no puede ser modificada por ninguna sentencia externa a la funcin. Los nombres de las variables locales no han de ser nicos. Dos, tres o ms funciones - por ejemplo: pueden definir variables de nombre Interruptor. Cada variable es distinta y pertenece a la funcin en que est declarada.

Las variables locales de las funciones no existen en memoria hasta que se ejecuta la funcin. Esta propiedad permite ahorrar memoria, ya que permite que varias funciones compartan la misma memoria para sus variables locales (pero no a la vez).

Ejemplo:

#include <iostream.h> #include <conio.h> void main() { //declaracin de variables locales de la funcin main() int x, y, a; //variables locales x, y, a } void suma() { //declaracin de variables locales de la funcin suma() int a, b; //variable locales a, b }

3.2.1.2.2.

Variables Globales

Las Variables Globales son variables que se declaran fuera de la funcin y por defecto (omisin) son visibles a cualquier funcin incluyendo main (). Ejemplo:

#include <iostream.h> #include <conio.h> int a, c, b, x; //declaracin de variables globales main() { //declaracin de variables locales

} 3.2.1.3. Tipos de Almacenamientos

Las variables por su parte pueden tener distinto tipo de almacenamiento, dependiendo ste de las partes del cdigo en el que van a ser utilizadas.

Static Una variable esttica existe desde que el programa comienza su ejecucin y dura hasta que el programa termina. Esta caracterstica permite retener el valor de una variable incluso aunque la ejecucin del programa salga fuera del mbito en el que ha sido declarada. Se declara anteponiendo la palabra reservada static a la declaracin de la variable. Considere el siguiente fragmento de cdigo: ejemplo( ) { static int x=0; x++; ... } En este caso, static modifica la declaracin de la variable x, que por defecto es local a la funcin, de manera que si bien el mbito de x sigue siendo la funcin (no se puede utilizar fuera de ella), sta no se destruye una vez ejecutada la funcin, sino que sigue en memoria conservando su valor, y si la funcin es llamada por segunda vez, el valor de la variable x ya no ser 0 sino 1. Las variables globales que se declaran en cada archivo son por defecto static.

Extern La palabra reservada extern sirve para declarar un nombre de funcin o variable como externa, y permite referencia una declaracin que se encuentra

en otro archivo. Esta caracterstica fue diseada originalmente para facilitar la compilacin separada de archivos, en este curso, no la utilizaremos de momento. Auto Es la declaracin de una variable local. Se usa para definir el mbito temporal de una variable local, es utilizada por defecto en las funciones.
Register

Cuando a la declaracin de una variable le antecede la palabra reservada register se indica al compilador que la variable se almacenar en uno de los registros del hardware del microprocesador. La palabra clave register, en una sugerencia, no un mandato, al compilador. Una variable register debe ser local a una funcin. La razn de utilizar variables register reside en que las operaciones sobre los valores situadas en los registros son normalmente ms rpidas que las realizadas sobre valores situados en memoria, por lo que se aumente la eficacia y velocidad del programa. Una aplicacin tpica es el uso de una variable register como variable de control de un bucle; de este modo se reduce el tiempo en el la CPU requiere para buscar el valor de la variable en memoria. Por ejemplo:

register int i; for (i=1; i<10000; i++) { ... } 3.2.1.4. Conversin explcita de tipos de datos

En C++ est permitida una conversin explcita del tipo de una expresin mediante una construccin que tiene la forma nombre_del_tipo (expresin). La expresin es convertida al tipo especificado. Por ejemplo la funcin raz cuadrada

(sqrt) devuelve un resultado de tipo double. Para poder asignar este resultado a una variable de otro tipo, por ejemplo de tipo int, tendremos que escribir:

int a; a = int (sqrt ( 2 )); Una variable de un determinado tipo no siempre puede ser convertida explcitamente a otro tipo.

3.2.2. Constantes

Las constantes son tipos de datos (con valores numricos o de cadena) que permanecen invariables, sin posibilidad de cambiar el valor que tienen durante el curso del programa. Una constante corresponde a una longitud fija de un rea reservada en la memoria principal del ordenador, donde el programa almacena valores fijos. Una constante tambin puede ser definida, como una variable cuyo valor o contenido no puede ser modificado. Por ejemplo: El valor de pi = 3.141592

3.2.2.1.

Constantes definidas.

Las constantes pueden recibir nombres simblicos mediante la directiva #define, esto significa que esa constante tendr el mismo valor a lo largo de todo el programa. El identificador de una constante as definida ser una cadena de caracteres que deber cumplir los mismos requisitos que el de una variable (sin espacios en blanco, no empezar por un dgito numrico, etc.). Ejemplo:

#include <stdio.h>

#define PI 3.1415926 int main() {

// constante definida PI

printf("Pi vale %f", PI); return 0; }

Lo cual mostrar por pantalla:

Pi vale 3.1415926

Es decir, PI es una constante a la que le hemos asignado el valor 3.1415926 mediante la directiva #define. La directiva #define tambin se puede utilizar para definir expresiones ms elaboradas con operadores (suma, resta, multiplicacin, etc.) y otras constantes que hayan sido definidas previamente, por ejemplo:

#define X 2.4 #define Y 9.2 #define Z X + Y

Otro ejemplo del uso de las constantes definidas:

#include <stdio.h> #define escribe printf main() {

int r; escribe("Ingrese un numero: "); scanf("%d",&r); escribe("El cuadrado del numero es: %d",r*r); }

3.2.2.2.

Constantes de enumeracin.

Se caracterizan por poder adoptar valores entre una seleccin de constantes enteras denominadas enumeradores; estos valores son establecidos en el momento de la declaracin del nuevo tipo. Como se ha sealado, son enteros y (una vez establecidos) de valor constante. Ejemplo:

enum { MALO, BUENO, REGULAR };

Hemos definido las constantes MALO, BUENO y REGULAR con los valores 0, 1 y 2.

enum { PRIMERO=1, SEGUNDO, TERCERO= 5 };

Hemos definido las constantes PRIMERO, SEGUNDO y TERCERO con los valores 1, 2 (si no se establece asume el siguiente valor numrico) y 5.

3.2.2.3.

Constantes declaradas

El especificador constante (const), permite crear o declarar entidades cuyo valor no se puede modificar. Una vez que una constante se declara no se puede

modificar dentro del programa. Las constantes deben ser inicializadas cuando se declaran.

La palabra clave const se utiliza para hacer que un objeto-dato, sealado por un identificador, no pueda ser modificado a lo largo del programa (sea constante). El especificador const se puede aplicar a cualquier objeto de cualquier tipo, dando lugar a un nuevo tipo con idnticas propiedades que el original pero que no puede ser cambiado despus de su inicializacin (se trata pues de un verdadero especificador de tipo). Cuando se utiliza en la definicin de parmetros de funciones o con miembros de clases, tiene significados adicionales especiales. Sintaxis:

const [<tipo-de-variable>] <nombre-de-variable> [ = <valor> ];

Ejemplo:

const int longitud = 20; char array[longitud];

La palabra clave const declara que un valor no es modificable por el programa. Puesto que no puede hacerse ninguna asignacin posterior a un identificador especificado como const, esta debe hacerse inevitablemente en el momento de la declaracin, a menos que se trate de una declaracin extern. Las constantes se pueden utilizar para sustituir a #define. Ejemplo:

const PI = 3.141592 const long = 128

// sustituye a #define PI 3.141592 // sustituye a #define long 128

3.3.

Operadores y operaciones.

3.3.1. Operadores

Un operador es un carcter o grupo de caracteres que acta sobre una, dos o ms variables u operandos o expresiones que se encuentran en una operacin para obtener un resultado. Ejemplo tpicos de operadores son la suma (+), la diferencia (-), el producto (*), etc. Los operadores pueden ser unarios, binarios y terciarios, segn acten sobre uno, dos o tres operandos, respectivamente. Hay varios tipos de operadores, clasificados segn el tipo de objetos sobre los que actan.

3.3.1.1.

Operadores aritmticos

Son usados para crear expresiones matemticas. Existen dos operadores aritmticos unitarios, '+' y '-' que tienen la siguiente sintaxis:

+ <expresin> - <expresin>

Asignan valores positivos o negativos a la expresin a la que se aplican. En cuanto a los operadores binarios existen varios. '+', '-', '*' y '/', tienen un comportamiento anlogo, en cuanto a los operandos, ya que admiten enteros y de coma flotante. Se trata de las conocidsimas operaciones aritmticas de suma, resta, multiplicacin y divisin. Sintaxis:

<expresin> + <expresin>

<expresin> - <expresin> <expresin> * <expresin> <expresin> / <expresin> <expresin> % <expresin>

El operador de mdulo '%', devuelve el resto de la divisin entera del primer operando entre el segundo. Por esta razn no puede ser aplicado a operandos en coma flotante. Cuando las expresiones que intervienen en una de estas operaciones sean enteras, el resultado tambin ser entero. Por otro lado si las expresiones son en punto flotantes, con decimales, el resultado ser en punto flotante.

3.3.1.2.

Operadores incrementales

Son dos operadores unitarios, se trata de operadores un tanto especiales, ya que slo pueden trabajar sobre variables, pues implican una asignacin. Se trata de los operadores '++' y '--'. El primero incrementa el valor del operando y el segundo lo decrementa, ambos en una unidad. Existen dos modalidades, dependiendo de que se use el operador en la forma de prefijo o de sufijo. Sintaxis:

<variable> ++ ++ <variable> <variable>--- <variable>

// (post-incremento) // (pre-incremento) // (post-decremento) // (pre-decremento)

En su forma de prefijo, el operador es aplicado antes de que se evale el resto de la expresin; en la forma de sufijo, se aplica despus de que se evale el resto de la

expresin. Veamos un ejemplo, en las siguientes expresiones "a" vale 100 y "b" vale 10:

c = a + ++b;

En este primer ejemplo primero se aplica el pre-incremento, y b valdr 11 a continuacin se evala la expresin "a+b", que dar como resultado 111, y por ltimo se asignar este valor a c, que valdr 111.

c = a + b++;

En este segundo ejemplo primero se avala la expresin "a+b", que dar como resultado 110, y se asignar este valor a c, que valdr 110. Finalmente se aplica en post-incremento, y b valdr 11. Los operadores unitarios sufijos (post-incremento y post-decremento) se evalan despus de que se han evaluado el resto de las expresiones. En el primer ejemplo primero se evala ++b, despus a+b y finalmente c =<resultado>. En el segundo ejemplo, primero se evala a+b, despus c = <resultado> y finalmente b++.

3.3.1.3.

Operadores de asignacin

Los operadores de asignacin atribuyen a una variable, es decir, depositan en la zona de memoria correspondiente a dicha variable, el resultado de una expresin o valor de otra variable. Existen varios operadores de asignacin, el ms evidente y el ms usado es el "=", pero no es el nico. Entre los operadores de asignacin tenemos: "=", "*=", "/=", "%=", "+=", "-=". Y la sintaxis es:

<variable> <operador de asignacin> <expresin>

En general, para todos los operadores mixtos la expresin:

Expresion1 op= Expresion2

Tiene el mismo efecto que la expresin:

Expresion1 = Expresion1 op Expresion2

El funcionamiento es siempre el mismo, primero se evala la expresin de la derecha, se aplica el operador mixto, si existe y se asigna el valor obtenido a la variable de la izquierda. En la siguiente tabla se muestra estas operaciones y sus equivalencias. (Figura 3.4).

Operador += -= *= /= %=

Sentencia Abreviada m=+n m-=n m*=n m/=n m=%n

Sentencia no Abreviada m = m + n; m = m - n; m = m * n; m = m / n; m=m%n

Figura 3. 4. Tabla de Equivalencia de Operadores de Asignacin

3.3.1.4.

Operadores relacionales

Los operadores relacionales comprueban la igualdad o desigualdad entre dos valores o expresiones. Sintaxis:

<expresin1> > <expresin2> <expresin1> < <expresin2> <expresin1> <= <expresin2> <expresin1> >= <expresin2> <expresin1> == <expresin2> <expresin1> != <expresin2>

El resultado de cualquier evaluacin de este tipo, es un valor verdadero (true) o falso (false). Siendo verdadero cualquier valor distinto de 0, aunque por lo general se usa el valor 1 y falso representado por el valor 0.

El significado de cada operador es evidente: > mayor que < menor que >= mayor o igual que <= menor o igual que == igual a != distinto a

Todos los operadores relacionales son operadores binarios (tienen 2 operandos), y su forma general es:

Expresin1 op Expresin2

3.3.1.5.

Operadores lgicos

Los operadores "&&", "||" y "!" relacionan expresiones lgicas, formando a su vez nuevas expresiones lgicas. Sintaxis:

<expresin1> && <expresin2> <expresin1> || <expresin2> !<expresin>

El operador "&&" equivale al "AND" o "Y"; devuelve "true" slo si las dos expresiones evaluadas son "true" o distintas de cero, en caso contrario devuelve "false" o cero. Si la primera expresin evaluada es "false", la segunda no se evala. Generalizando, con expresiones AND con ms de dos expresiones, la primera expresin falsa interrumpe el proceso e impide que se contine la evaluacin del resto de las expresiones. Esto es lo que se conoce como "cortocircuito", y es muy importante. A continuacin se muestra la tabla de verdad del operador && (Figura 3.5):

Expresin1 false true true

Expresin2 ignorada false true

Expresin1 && Expresin2 false false true

Figura 3. 5. Tabla de verdad del operador "&&":

El operador "||" equivale al "OR" u "O inclusivo"; devuelve "true" si cualquiera de las expresiones evaluadas es "true" o distinta de cero, en caso contrario devuelve

"false" o cero. Si la primera expresin evaluada es "true", la segunda no se evala. A continuacin se muestra la tabla de verdad del operador "||". (Figura 3.6):

Expresin1 false false true

Expresin2 false true ignorada

Expresin1 || Expresin2 false true true

Figura 3. 6. Tabla de verdad del operador "||" .

El operador "!" es equivalente al "NOT", o "NO", y devuelve "true" slo si la expresin evaluada es "false" o cero, en caso contrario devuelve "false". La expresin "!E" es equivalente a (0 == E). A continuacin se muestra la tabla de verdad del operador "!" (Figura 3.7):

Expresin false true

!Expresin true false

Figura 3. 7. Tabla de verdad del operador "!".

3.3.1.6.

Operador "sizeof"

Este operador tiene dos usos diferentes. Sintaxis:

sizeof (<expresin>) sizeof (nombre_de_tipo)

En ambos casos el resultado es una constante entera que da el tamao en bytes del espacio de memoria usada por el operando, que es determinado por su tipo. El espacio reservado por cada tipo depende de la plataforma. En el primer caso, el tipo del operando es determinado sin evaluar la expresin, y por lo tanto sin efectos secundarios. Si el operando es de tipo "char", el resultado es 1. A pesar de su apariencia, sizeof() NO es una funcin, sino un OPERADOR.

3.3.1.7.

Operadores a nivel de bit enteros

Los operadores a nivel de bit operan independientemente sobre cada uno de los bits de un valor.
NOT: El operador NOT unario, ~, invierte todos los bits de su operando. Por

ejemplo, en nmero 42, que tiene el siguiente patrn de bits 00101010 se convierte en 11010101 despus de aplicar el operador NOT.
AND: El operador AND, &, combina los bits de manera que se obtiene un 1 si

ambos operandos son 1, obteniendo 0 en cualquier otro caso. 00101010 (representacin en byte del numero 42) & 00001111 = 00001010 (representacin en byte del numero 15) (representacin en byte del numero 10)

OR: El operador OR, |, combina los bits de manera que se obtiene un 1 si

cualquiera de los operandos es un 1. 00101010 (representacin en byte del numero 42) | 00001111 = 00101111 (representacin en byte del numero 15) (representacin en byte del numero 47)

XOR: El operador XOR, ^, combina los bits de manera que se obtiene un 1 si

cualquiera de los operandos es un 1, pero no ambos, y cero en caso contrario. 00101010 (representacin en byte del numero 42)

^ 00001111 = 00100101 (representacin en byte del numero 15) (representacin en byte del numero 37)

La tabla siguiente muestra cmo acta cada operador a nivel de bit sobre cada combinacin de bits de operando (Figura 3.8):

A 0 1 0 1

B 0 0 1 1

OR 0 1 1 1

AND 0 0 0 1

XOR 0 1 1 0

NOT 1 1 1 0

Figura 3. 8. Tabla de los operadores a nivel de bit.

Desplazamiento a la izquierda: El operador desplazamiento a la izquierda,

<<, mueve hacia la izquierda todos los bits del operando de la izquierda un nmero de posiciones de bit especificado en el operando de la derecha. Al realizarse el desplazamiento se pierden por el extremo izquierdo del operando el nmero de bits desplazados y se rellena el operando con ceros por la derecha el mismo nmero de bits.
Desplazamiento a la derecha: El operador desplazamiento a la derecha, >>,

mueve hacia la derecha todos los bits del operando de la izquierda un nmero de posiciones de bit especificado por el operando de la derecha. Ejemplo: Si se desplaza el valor 35 a la derecha dos posiciones de bit, se obtiene como resultado que el valor 8.

a = a >> 2;

int a = 35;

Cuando un valor tiene bits que se desplazan fuera por la parte izquierda o derecha de una palabra, esos bits se pierden. Si se estudian en binario estas operaciones se observa con mayor claridad. 00100011 (representacin en byte del numero 35) >> 2 = 00001000 (representacin en byte del numero 8)

3.3.1.8.

Operador condicional ternario ?:

El operador condicional (?:) el cual es conocido por su estructura como ternario. Este operador permite controlar el flujo de ejecucin del programa. Permite evaluar situaciones tales como: Si se cumple tal condicin entonces haz esto, de lo contrario haz esto otro. Sintaxis:

( (condicin) ? proceso1 : proceso2 )

En donde, condicin es la expresin que se evala, proceso1 es la tarea a realizar en el caso de que la evaluacin resulte verdadera, y proceso2 es la tarea a realizar en el caso de que la evaluacin resulte falsa. Ejemplo:

int edad; cout << "Cual es tu edad: "; cin >> edad; cout << ( (edad < 18) ? "Eres joven aun" : "Ya tienes la mayora de edad" );

3.4.

Expresiones.

Una expresin es una combinacin de operadores y operandos de cuya evaluacin se obtiene un valor. Los operandos pueden ser nombres que denoten objetos variables o constantes, funciones, literales de cualquier tipo adecuado de acuerdo con los operadores u otras expresiones ms simples. La evaluacin de una expresin da lugar a un valor de algn tipo, una expresin se dice que es del tipo de su resultado. Ejemplos de expresiones:

a + 5*b (a >= 0) && ((b+5) > 10) a -a * 2 + b --b + (- 4*a*c)

Las expresiones se evalan de acuerdo con la precedencia de los operadores. Ante una secuencia de operadores de igual precedencia, la evaluacin se realiza segn el orden de escritura, de izquierda a derecha. El orden de evaluacin puede modificarse usando operadores que denoten precedencia como los parntesis.

3.4.1. Reglas de precedencias

El resultado de una expresin depende del orden en que se ejecutan las operaciones. Por ejemplo considere la siguiente expresin: 3 + 4 * 2. Si se resuelve primero la suma y luego la multiplicacin el resultado ser 14. Pero si se realiza primero la multiplicacin y luego la suma el resultado es 11. Con el objeto de que el

resultado de una expresin sea claro e inequvoco, es necesario crear reglas que definan el orden de ejecucin. La interpretacin de cualquier expresin en C++ est determinada por la precedencia y asociatividad de los operadores en dicha expresin. Cada operador tiene una precedencia, y los operadores en una expresin se evalan en orden de mayor a menor precedencia. La evaluacin de operadores con la misma precedencia viene determinada por su asociatividad. Los parntesis anulan las reglas de precedencia. En la siguiente tabla se listan los operadores en C++, su precedencia y su asociatividad. Los operadores se listan en orden de prioridad decreciente (los situados ms arriba tienen mayor prioridad). Los operadores en la misma lnea horizontal tienen la misma precedencia.

3.4.2. Tabla de precedencia de los operadores en C++.

En la siguiente tabla se muestran las prioridades de los operadores en el lenguaje C++. (Figura 3.9):

Operador ()

Propsito Denota precedencia en una expresin

Asociatividad De izquierda a derecha

sizeof ++ -! ~ + * / %

Tamao de un objeto Incremento y decremento prefijo Operadores Unario Operaciones aritmticas multiplicacin, divisin y modulo

De derecha a izquierda De derecha a izquierda De derecha a izquierda De izquierda a derecha

+ -

Operaciones aritmticas adiccin y sustraccin

De izquierda a derecha

<< >> < > <= >= == != & ^ | && || ?: = *= /= += = &= ^= |= %= <<= ++ -,

Desplazamiento binario Operadores de relacin Operadores de igualdad Y binario O exclusivo binario O inclusivo binario Y lgico O lgico Operador condicional Operadores de asignacin

De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De izquierda a derecha De derecha a izquierda

Incremento y decremento sufijo Separador coma

De derecha a izquierda De izquierda a derecha

Figura 3. 9. Tabla de prioridades de los operadores.

3.4.3. Ejemplo de expresiones.

Ejemplo 1: Se tiene la siguiente expresin y=2*5*5+3*5+7, se desea evaluarla y encontrar el resultado. Solucin: Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. y = 2 * 5 * 5 + 3 * 5 + 7; 2 * 5 = 10 (multiplicacin ms a la izquierda primero) y = 10 * 5 + 3 * 5 + 7; 10 * 5 = 50 (Multiplicacin ms a la izquierda) y = 50 + 3 * 5 + 7; 3 * 5 = 15 (Multiplicacin antes de la suma) y = 50 + 15 + 7; 50 + 15 = 65 (Suma ms a la izquierda) y = 65 + 7; 65 + 7 = 72 (Se resuelve la ltima operacin aritmtica) y = 72 (por ltimo se realiza la asignacin a la variable y)

Ejemplo 2: Dados a=1, b=2 y c=3 efecte la siguiente expresin: d = 10 * a > c * 10 + b Solucin: Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. d = 10 * 1 > 3 * 10 + 2 (Se realiza primero la operacin aritmtica de mayor precedencia ms a la izquierda 10*1 y luego 3*10)

d = 10 > 30 + 2 (Se realiza primero la operacin aritmtica 30 + 2) d = 10 > 32 (Se resuelve la operacin relacional 10>32 dando como resultado un valor falso. Todo valor falso es igual a 0) d = 0 (por ltimo se realiza la asignacin a la variable d)

Ejemplo 3: Efecte la siguiente expresin: d = 10 > 5 && 3 * 10 Solucin: Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. A pesar de que el operador lgico && tiene menor prioridad obliga a resolver la expresin ms a la izquierda 10 > 5, aunque el operador aritmtico * tenga mayor prioridad. d = 10 > 5 && 3 * 10 (Se separa la expresin debido a la presencia del operador lgico y se resuelve la primera expresin 10 > 5, siendo su resultado verdadero, todo valor verdadero ser representado por el valor 1) d = 1 && 3 * 10 (Dado un resultado verdadero en la primera expresin se resuelve la siguiente 3 * 10, de haber resultado falsa toda la expresin seria falsa y no realizara dicha operacin. Al resolver la operacin 3 * 10 el resultado es 30, donde todo valor diferente a cero es un valor verdadero.) d = 1 && 1 (El resultado final de la expresin ser un valor verdadero) d = 1 (por ltimo se realiza la asignacin a la variable d)

Ejemplo 4: Dado a = 1, b = 2 efecte la siguiente expresin:

d = a++ > 5 / 2 || 3 * --b < ( 3 + a) Solucin: Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. A pesar de que el operador lgico || tiene menor prioridad obliga a resolver la expresin mas a la izquierda a++ > 5 / 2, aunque el las operacin decremento prefijo tenga mayor prioridad. d = a++ > 5 / 2 || 3 * --b < (3 + a) (Resolvemos la expresin a++ > 5 / 2) a++ > 5 / 2 (La operacin incremento sufijo por tener menor prioridad se resuelve despus de todas las operaciones siendo resuelta despus de finalizar toda la expresin a++ > 5 / 2, se asigna el valor de la variable a) 1>5/2 (se resulte la operacin aritmtica de mayor precedencia 5 / 2 y luego la operacin relacional 1 > 2, siendo falsa) d = 0 || 3 * --b < (3 + a) (Antes de resolver la prxima expresin primero se realiza el incremento de sufijo, dando como resultado el valor a en 2) (Resolvemos la expresin a++ > 5 / 2) 3 * --b < (3 + a) (El parntesis denota prioridad en la expresin por lo cual se deber resolver la operacin 3 + a antes, sustituyendo la variable por su valor 2 el resultado es 5) 3 * --b < 5 (Se resuelve la operacin de mayor prioridad b el cual decrementar en memoria inmediatamente el valor de la variable b) 3*1<5 (Resolvemos la operacin aritmtica y luego la operacin relacional dando como resultado un valor verdadero)

d = 0 || 1 (El resultado final de la expresin ser un valor verdadero) d = 1 (por ltimo se realiza la asignacin a la variable d)

3.5.

Sentencias

Las sentencias son unidades completas, ejecutables en si mismas. Existen muchos tipos de sentencias que incorporan expresiones aritmticas, lgicas o generales como componentes de dichas sentencias. Las sentencias simples se separan por punto y coma y las compuestas se agrupan en bloques mediante llaves.

3.5.1. Sentencias Simple

Una sentencia simple es una expresin de algn tipo terminada por un carcter (;). Por ejemplo las declaraciones o las sentencias aritmticas.

flota real; area = base * altura;

// declaracin de variable // expresin aritmtica

3.5.2. Sentencia vaca o nula

En algunas ocasiones es necesario introducir en el programa una sentencia que ocupe un lugar, pero que no realice ninguna tarea. A esta sentencia se le denomina sentencia vacia y consta de un simple carcter (;). Por ejemplo:

3.5.3. Sentencia compuesta

Es un conjunto de declaraciones y de sentencias agrupadas dentro de llaves {}. Tambin conocido como bloques. Una sentencia compuesta puede incluir otras sentencias, simples y compuestas. Ejemplo:

{ int i = 1, j = 2; double peso; peso = 5.5; j = i + j; }

3.6.

Operaciones de entrada y salida estndar.

Cuando nos referimos a entrada/salida estndar (E/S estndar) queremos decir que los datos o bien se estn leyendo del teclado, bien se estn escribiendo en el monitor de video. Como se utilizan muy frecuentemente se consideran como los dispositivos de E/S por defecto y no necesitan ser nombrados en las instrucciones de E/S. Las operaciones de entrada y salida no forman parte del conjunto de sentencias de C++, sino que pertenecen al conjunto de funciones y clases de la biblioteca estndar de C++. Ellas se incluyen en los archivos de cabecera mediante la directiva #include por lo que siempre que queramos utilizarlas deberemos introducir la lnea de cdigo:

#include <nombrelibreria>

En el lenguaje C++ tenemos varias alternativas para ingresar y/o mostrar datos, dependiendo de la librera que vamos a utilizar para desarrollar el programa, entre estas estn: iostream.h, stdio.h, conio.h. <STDIO.H> Esta librera incorpora las sentencias de entrada y salida bsicas entre ellas tenemos la sentencia scanf y la sentencia printf, denominadas sentencias de entrada y salida con formato, ya que se les indica el tipo de conversin de tipo a realizar. < IOSTREAM.H> Esta biblioteca es una implementacin orientada a objetos y est basada en el concepto de flujos. A nivel abstracto un flujo es un medio de describir la secuencia de datos de una fuente a un destino o sumidero. As, por ejemplo, cuando se introducen caracteres desde el teclado, se puede pensar en caracteres que fluyen o se trasladan desde el teclado a las estructuras de datos del programa. Entre los objetos de flujo que vienen predefinidos tenemos: cin, que toma caracteres de la entrada estndar (teclado); cout, pone caracteres en la salida estndar (pantalla); cerr y clog, ponen mensajes de error en la salida estndar. Estos objetos se utilizan mediante los operadores << y >>. <CONIO.H> Esta librera incorpora las sentencias de entrada y salida simples de carcter o cadenas como lo son: getch, getche, getchar, gets, putchar, puts.

3.6.1. Sentencias de Salida Estndar.

El dispositivo de salida estndar como podemos suponer es el monitor o pantalla de nuestro ordenador. Las sentencias de salida envan datos al puerto de video para ser visualizados. Entre estas sentencias tenemos:

3.6.1.1.

Sentencia de Salida cout

La salida estndar en C++ es la pantalla de nuestro ordenador. El objeto asociado con dicha salida estndar es cout. El objeto cout emplea al operador de insercin "<<" y apunta al objeto donde tiene que enviar la informacin. Por lo tanto la sintaxis de cout ser:

cout<<variable1<<variable2<<...<<variablen;

Las cadenas de texto son variables y se ponen entre " " (comillas dobles).

cout << "Hola"; cout << 489; cout << 13.69; cout << x; cout << "El valor de pi es = " << 3.1416;

Si queremos incluir saltos de lnea podemos emplear el cdigo de escape '\n' o bien el manipulador "endl".

cout << "Una linea.\n "; cout << "segunda linea.\n"; cout << "tercera linea." << endl; cout << "cuarta linea." << endl;

3.6.1.2.

Sentencia de Salida printf

La rutina printf permite la aparicin de valores numricos, caracteres y cadenas de texto por pantalla. El prototipo de la sentencia printf es el siguiente:

printf (control, arg1,arg2...);

En la cadena de control indicamos la forma en que se mostraran los argumentos posteriores, tambin podemos introducir una cadena de texto (sin necesidad de argumentos) o combinar ambas posibilidades, as como secuencia de escape. En el caso de que utilicemos argumentos deberemos indicar en la cadena de control tanto modificadores como argumentos se vayan indicar. El modificador esta compuesto por el carcter % seguido por un carcter de conversin indica de que tipo de dato se trata. Ejemplo:

printf("Color %s, num1 %d, num2 %5d, real %5.2f.\n", "rojo", 12, 8, 3.4);

Imprimir la siguiente lnea en la pantalla (incluyendo el carcter de nueva lnea \n):

Color rojo, num1 123, num2 00089, real 3.14.

3.6.1.3.

Tabla de caracteres de formato salida

Las letras de control de formato ms usadas son (Figura 3.10):

Carcter

Descripcin Esto imprime un nmero como un carcter ASCII. Por lo que, `printf

"%c", 65' imprimira la letra A. La salida para un valor cadena es el primer carcter de la cadena.

d i

Esto imprime un entero decimal. Esto tambin imprime un entero decimal. Esto imprime un nmero en notacin cientfica (exponencial). Por

ejemplo, printf "%4.3e", 1950 imprime 1.950e+03, con un total de 4 cifras significativas de las cuales 3 siguen al punto decimal. Los modificadores 4.3 son descritos ms abajo.

f g o s x

Esto imprime un nmero en notacin punto flotante. Esto imprime en notacin cientfica o en notacin punto flotante, la que quiera que sea ms corta. Esto imprime un entero octal sin signo. Esto imprime una cadena. Esto imprime un entero hexadecimal sin signo. Esto imprime un entero hexadecimal sin signo. Sin embargo, para los

valores entre 10 y 15, utiliza las letras desde la A a la F en lugar de esas mismas letras pero en minsculas. Esta no es realmente una letra de control de formato. Pero tiene un

significado especial cuando se usa despus de un %: la secuencia %% imprime el carcter %. No consume ni necesita ningn item o argumento correspondiente. Figura 3. 10. Tabla de caracteres de formato salida

El formato completo de los modificadores es el siguiente:

% [signo][longitud][.][precisin] carcter de conversin.

Signo: indicamos si el valor se ajustara a la izquierda, en cuyo caso utilizaremos el signo menos, o a la derecha (por defecto). Longitud: Especifica la longitud mxima del valor que aparece en por pantalla. Si la longitud mxima del valor que aparece por pantalla. Si la longitud es menos que el nmero de dgitos del valor, este aparecern ajustado a la izquierda. Precisin: Indicamos el numero mximo de decimales que tendr el valor.

La sentencia printf puede incluir caracteres especiales o secuencias de escape que permitan modificar la impresin de los datos. Caracteres especiales ms utilizados: \n // salto de lnea

\t // tabulador horizontal \v \b // tabulador vertical // retroceso

\r // retorno de carro \f \a \\ \? \' \" // salto de pgina // alerta (campana) // carcter \ // interrogante // comilla simple // comilla doble

\ooo // carcter ASCII dado por tres dgitos octales (ooo sern dgitos) \xhh // carcter ASCII dado por dos dgitos hexadecimales (hh sern dgitos) \0 // carcter nulo

Los argumentos de la sentencia de entrada pueden estar representados por operaciones o sentencias. La sentencia printf resulte estas operaciones antes de

ejecutar la etapa de control. Se resolvern los argumentos de derecha a izquierda unas vez finalizados se resuelve la etapa de control de izquierda a derecha. Ejemplo:

int edad = 5; printf("edad2: %d, edad1: %d, edad inicial: %d", edad, ++edad, edad++);

Muestra por salida:

edad2: 7, edad1: 7, edad inicial: 5

3.6.1.4.

Sentencia de Salida puts

Esta sentencia muestra por la salida estndar una cadena de caracteres o literales y salta a la prxima lnea, su sintaxis:

puts(direccion_cadena_caracteres); puts(literales);

Ejemplo:

char cadena[25]=Casa; // se declara una cadena de caracteres {C,a,s,a,\0}

puts(cadena); // Muestra los caracteres de cadena hasta encontrar el fin de cadena puts(100); // Muestra los caracteres desde la posicin de memoria 100 hasta // encontrar el carcter de fin de cadena puts(cadena); // Muestra la palabra: cadena por pantalla

3.6.1.5.

Sentencia de Salida putchar

Esta sentencia muestra por la salida estndar un carcter, su sintaxis:

putchar (variable_caracter); putchar (valor_caracter); putchar (simbolo_caracter);

Ejemplo:

char car = 65; putchar (car); putchar (65); putchar (A); // Muestra por pantalla el carcter A // Muestra por pantalla el carcter A // Muestra por pantalla el carcter A

3.6.2. Sentencias de Entradas Estandar

El dispositivo de entrada estndar como podemos suponer es el teclado de nuestro ordenador. Las sentencias de entrada escanean este puerto para atrapar datos y ser utilizados. Entre estas sentencias tenemos:

3.6.2.1.

Sentencia de Entrada cin

Para extraer datos desde el teclado empleamos el objeto "cin", que se utiliza en conjuncin con el operador de extraccin representado como ">>", lee informacin del flujo cin (a la izquierda del operador) y las almacena en las variables indicadas a la derecha). La sintaxis sera la siguiente:

cin>>variable1>>...>>variablen;

Un ejemplo de cdigo utilizando ambos objetos podra ser el siguiente:

#include <iostream.h> void main () { int i; cout<<"Introduce un nmero"; cin>>i; } // atrapa un valor entero ingresado por teclado

Muestra por pantalla la frase "Introduce un nmero" y posteriormente almacenara el valor introducido por teclado en la variable i.

3.6.2.2.

Sentencia de Entrada scanf

La rutina scanf permite entrar datos en la memoria del ordenador a travs del teclado. El prototipo de la sentencia scanf es el siguiente:

scanf(control, arg1, arg2, ...);

En la cadena de control indicaremos por regla general, los modificadores que harn referencia al tipo de dato de los argumentos. Al igual que en la sentencia printf los modificadores, estarn formado por el carcter % seguido de un carcter de conversin. Los argumentos indicados sern, nuevamente las variables. La principal caracterstica de la sentencia scanf es que necesita saber la posicin de la memoria del ordenador en que se encuentra la variable para poder almacenar la informacin obtenida, para indicarle est posicin utilizamos el smbolo ampersand (&), aunque colocaremos delante del nombre de cada variable (esto no es necesario en las cadenas de caracteres o punteros). Ejemplo:

include<stdio.h> void main( ) /*solicita dos datos*/ { char nombre[10]; int edad; printf ("introduce tu edad:"); scanf("%d", &edad); printf ("introduce tu nombre:"); scanf("%s", nombre); } // nombre no lleva & por ser una referencia

3.6.2.3.

Sentencia de Entrada gets

Esta sentencia lee y guarda una cadena introducida por la entrada estndar, su sintaxis:

char cadena[25];

puts(Ingrese un nombre:); gets(cadena); // Enva los caracteres a partir de la posicin de memoria de la cadena // y transforma el carcter intro (enter) en un carcter fin de cadena puts(cadena); // Muestra lo que se ingreso por la entrada en pantalla

3.6.2.4.

Sentencia de Entrada getchar

Esta sentencia lee y retorna cuando se presione la tecla intro, un nico carcter introducido mediante el teclado y salta a la prxima lnea. Muestra el carcter por la pantalla. Su sintaxis:

char letra; letra=getchar( ); // atrapa un carcter y lo retorna despus del carcter intro.

3.6.2.5.

Sentencia de Entrada getch

Lee y retorna un nico carcter al presionar una tecla. No muestra el carcter por pantalla. Su sintaxis:

char letra; letra=getch( ); // atrapa un carcter al momento de presionarlo y no lo muestra

3.6.2.6.

Sentencia de Entrada getche

Esta sentencia lee y retorna un nico carcter introducido mediante el teclado por el usuario al igual que la sentencia getch pero a diferencia esta si muestra el carcter por pantalla. Su sintaxis:

char letra; letra=getche( ); // atrapa un carcter al momento de presionarlo y lo muestra

CAPITULO 4
ESTRUCTURAS DE CONTROL

4.1.

Concepto.

Para existir un control de un proceso o situacin, se deben dar condiciones necesarias para ello, es decir que las condiciones son el punto de partida principal de una sentencia de control. Podemos definir las estructuras de control como sentencias condicionales compuesta, que al cumplirse la condicin necesaria, se realicen las sentencias simples contenidas en esta.

4.2.

Tipos de estructuras de control

El C++, como todo lenguaje de programacin basado en la algortmica, posee una serie de estructuras de control para gobernar el flujo de los programas. Debemos recordar que la evaluacin de una condicin producir como resultado un cero si es falsa y un nmero cualquiera distinto de cero si es cierta, este hecho es importante a la hora de leer los programas, ya que una operacin

matemtica, por ejemplo, es una condicin vlida en una estructura de control. Las estructuras de control bsicas las podemos dividir en: sentencias de control selectivas y las sentencias de control iterativo o ciclos.

4.2.1. Estructuras de control selectivas.

Las sentencias de control selectivas son estructuras de control que funciona de esta manera: Las instrucciones comienzan a ejecutarse de forma secuencial (en orden) y cuando se llega a una estructura condicional, la cual est asociada a una condicin, se decide que camino tomar dependiendo siempre del resultado de la condicin siendo esta falsa o verdadera. Cuando se termina de ejecutar este bloque de instrucciones se reanuda la ejecucin en la instruccin siguiente a la de la condicional. Dentro de las estructuras de seleccin encontramos en el C++, las de

condicin simple (sentencia if), bicondicionales (sentencia if-else) y las de condicin mltiple (switch).

4.2.1.1.

La sentencia if o condicional simple

Es una sentencia condicional simple cuya traduccin es: si la expresin a evaluar es verdadera realiza las instrucciones que controle dicha sentencia. Si el resultado de la expresin es falso el flujo del programa continuar con las sentencias debajo del final del if. Su sintaxis es:

if (expresin) { //sentencias }

Si solo controla una sentencia no es necesario usar los operadores de bloque.

if (expresin) sentencia_unica;

Podemos representar esta sentencia con el siguiente diagrama (Figura 4.1),

Fiugra 4. 1. Diagrama de flujo sentencia if.

donde se muestra que solo se realizara la sentencia 1 si el resultado lgico de la expresin es verdadera de no serlo contina el flujo del programa. Ejemplo:

int x=6; if(x>5) k++;

Como se ve x tiene un valor y el if evala su estatus, como el resultado es verdadero k incrementara su valor una sola vez y el flujo de programa continuar.

Ejemplo 1: Determine si un nmero es igual mayor o menor que cero.

#include <iostream.h> void main() { int numero; cout<<"Ingrese un numero:"; cin>>numero; if(numero == 0) //La condicin indica que tiene que ser igual a Cero

{ cout<<"El Numero Ingresado es Igual a Cero"; } if(numero > 0) // la condicin indica que tiene que ser mayor a Cero { cout<<"El Numero Ingresado es Mayor a Cero"; } if(numero < 0) // la condicion indica que tiene que ser menor a Cero { cout<<"El Numero Ingresado es Menor a Cero"; } }

Ejemplo 2: Determine si un nmero entero es par o impar.

#include <iostream.h> void main() { int num; cout<<"Ingrese un numero:"; cin>>num; //Un numero ser par s es divisible por 2 if(num %2==0) //La condicin indica que se cumpla si es divisible cout<<"El numero ingresado es par"; //Un numero ser impar s no es divisible por 2 if(num %2!=0) //La condicin indica que se cumpla si no es divisible cout<<"El numero ingresado es impar"; }

Ejemplo 3: Convertir un carcter atrapado en un nmero entre [0,9].

#include <iostream.h> #include <stdio.h> #include <conio.h> void main() { int num=-1; char car; cout<<"Ingrese un carcter:"; car=getche(); //atrapa un smbolo //La condicin se cumple se asignara el nmero correspondiente if(car==0) num=0; if(car==1) num=1; if(car==2) num=2; if(car==3) num=3; if(car==4) num=4; if(car==5) num=5; if(car==6) num=6; if(car==7) num=7; if(car==8) num=8; if(car==9) num=9;

if(num!=-1) cout<<"El Numero es ="<<num; if(num==-1) cout<<"Carcter no es un smbolo numrico"; }

4.2.1.2.

La sentencia if-else o bicondicional

Esta estructura cumple las mismas caractersticas de la sentencia if, cuando la condicin es verdadera realizara una sentencia o conjunto de sentencias verdaderas, pero si esta es falsa realizara una sentencia o conjunto de sentencias falsas.

if (expresin) { //sentencias condicin verdadera } else { // sentencias condicin falsa }

Si solo controla una sentencia no es necesario usar los operadores de bloque.

if(expresin) sentencia_unica1; else sentencia_unica2;

Podemos representar esta sentencia con el siguiente diagrama (Figura 4.2),

Fiugra 4. 2. Diagrama de flujo sentencia if-else.

donde se muestra que solo se realizara la sentencia 1 si el resultado lgico de la expresin es verdadera, pero si esta no se cumple realiza la sentencia 2, una vez realice alguna de las sentencias dado el resultado de la expresin contina el flujo del progama. De esta manera podemos mostrar el siguiente ejemplo:

x=0; if( x ==5) { k++; } else { k--; }

Como la evaluacin de x es falsa, k decrementar en uno su valor y continuar con el flujo del programa.

Ejemplo 1: Determine si un numero entero es positivo o negativo.

#include <iostream.h>

void main() { int num; cout<<"Ingrese un numero:"; cin>>num; if(num>= 0) //La condicin indica que tiene mayor o igual a cero { cout<<"El numero ingresado es positivo"; } else { cout<<"El numero ingresado es negativo"; } } // de no cumplirse, entonces debe ser menor que cero

Ejemplo 2: Determine si un nmero entero es par o impar.

#include <iostream.h> void main() { int num;

cout<<"Ingrese un numero:"; cin>>num; if(num %2==0) //La condicin indica que se cumpla si es divisible cout<<"El numero ingresado es par"; else //si la condicin no se cumple entonces no es divisible cout<<"El numero ingresado es impar"; }

Las sentencias pueden controlar otras sentencias de control secuencial permitiendo evaluar los procesos solo cuando sean necesarios conocidas como sentencias secuenciales anidadas. Por ejemplo si queremos determinar si un nmero es igual mayor o menor que cero, usando sentencias anidadas if-else resulta:

#include <iostream.h> void main() { int numero; cout<<"Ingrese un numero:"; cin>>numero; if(numero == 0) { } else if(numero > 0) { } else { cout<<"El Numero Ingresado es Menor a Cero"; } } cout<<"El Numero Ingresado es Mayor a Cero"; cout<<"El Numero Ingresado es Igual a Cero";

4.2.1.3.

La sentencia switch.

Sirve para seleccionar una de entre mltiples alternativas de acuerdo al valor de una expresin. La sentencia switch es especficamente til cuando la seleccin se

basa en el valor de una variable simple o de una expresin simple denominada expresin de control mltiple o selector. Su sintaxis:

switch (expresin) { case valor_expresion_1: //sentencias 1 break; case valor_expresion_2: //sentencias 2 break; .... case valor_expresion_n: //sentencias n break; default: //sentencias x }

Podemos representar esta sentencia mediante el diagrama siguiente (Figura 4.3),

Fiugra 4. 3. Diagrama de flujo sentencia switch.

donde dado el valor de la expresin realizara las operaciones y continuara con el flujo del programa. Esta sentencia la podemos representar usando sentencias anidadas ifelse, si la sentencia break no fuese utilizada entonces se representara por un conjunto de sentencias if una tras otra. Como vern dependiendo de valor se selecciona el caso por ejemplo:

x=3; switch (x) { case 1: k= 20*2; break; case 2: k=20/2; break; case 3: k=20+2; //no es necesario usar break }

Como x es igual a 3 el case efectuar la operacin k=20+2, el uso de default es opcional.

Ejemplo: Escribir un programa que lea por teclado las notas desde la A-H, y muestre por pantalla el rendimiento acadmico del alumno.

#include <conio.h> #include <iostream.h> main() { char letra;

cout<<"Ingrese la Calificacin y presione Enter: "; cin>>letra; switch (letra) { case 'A': cout<<"Excelente"; break; case 'B': cout<<"Notable"; break; case 'C': cout<<"Aprobado"; break; case 'D': case 'E': case 'F': cout<<"Desaprobado"; break; default: } } cout<<"No esposible esta nota";

La sentencia break es opcional. Cuando se encuentra, provoca la salida de switch. En caso contrario continua la siguiente secuencia case o default aunque no se cumpla la condicin. Para aclarar esto, tomemos el siguiente ejemplo:

int c; ... scanf ("%d", &c); switch (c) { case 1: case 2: Funcion2 (); case 3: Funcion3 ();

break; case 4: Funcion4_1 (); Funcion4_2 (); break; case 5: Funcion_5 (); default: FuncionX (); }

La siguiente tabla indica qu funcin se ejecuta dependiendo del valor de c (Figura 4.4). Si se pulsa 1 2 3 4 5 Otra cosa Se ejecuta las funciones Funcion2() y Funcion3() Funcion2() y Funcion3() Funcion3() Funcion4_1() y Funcion4_2() Funcion5() y FuncionX() FuncionX()

Fiugra 4. 4. Tabla de ejecucin de funciones.

4.2.2. Estructuras de control iterativas.

Las Sentencias de Iteracin o Ciclos son estructuras de control que repiten la ejecucin de un grupo de instrucciones. Bsicamente, una sentencia de iteracin es una estructura de control condicional, ya que dentro de la misma se repite la ejecucin de una o ms instrucciones mientras o hasta que una a condicin especfica se cumpla. Muchas veces tenemos que repetir un nmero definido o indefinido de veces un grupo de instrucciones por lo que en estos casos utilizamos este tipo de sentencias. En C++ los ciclos o bucles se construyen por medio de las

sentencias for, while y do - while. La sentencia for es til para los casos en donde se conoce de antemano el nmero de veces que una o ms sentencias han de repetirse. Por otro lado, la sentencia while es til en aquellos casos en donde no se conoce de antemano el nmero de veces que una o ms sentencias se tienen que repetir.

4.2.2.1.

Sentencia for

Es un bucle o sentencia repetitiva que, permite realizar un proceso de manera cclica, desde un punto partida inicial, hasta un punto final, atreves de un incremento o contador de actividad. La sentencia for: 1. Ejecuta la sentencia de inicializaciones. 2. Verifica la expresin booleana de condicin de trmino:
a. si es cierta, ejecuta la sentencia entre llaves y la sentencia de iteracin para volver a verificar la expresin booleana de condicin de trmino.

b. si es falsa, sale del bucle.

Podemos representar el flujo de la sentencia en el siguiente diagrama (Figura 4.5):

Fiugra 4. 5. Diagrama de flujo sentencia for.

Sintaxis:

for (inicio; condicin; iteracin) sentencia;

o si se desean repetir varias sentencias:

for (inicio; condicin; iteracin) { sentencia_1; sentencia_2; sentencia_n; }

Vemos que la sentencia for tiene tres secciones: inicio, en dnde se da un valor inicial a una variable o variables de control del bucle; condicin, que es una expresin que devuelve un valor verdadero o falso, y hace que el bucle se repita mientras sea cierta y salga de este solo cuando la condicin sea falsa; e iteracin, en dnde se determina el cantidad del incremento o decremento de la variable o variables de control. Las tres secciones estn separadas por punto y coma. El cuerpo del bucle puede estar formado por una o por varias sentencias. En este ltimo caso deben encerrarse entre llaves {}. Las llaves slo son necesarias si se quieren repetir varias sentencias, aunque se recomienda su uso porque facilita la lectura del cdigo fuente y ayuda a evitar errores al modificarlo. Habitualmente, en la expresin lgica de condicin de trmino se verifica que la variable de control alcance un determinado valor. Por ejemplo:

for (i = valor_inicial; i <= valor_final; i++)

{ }

sentencia;

Algunos ejemplos de la sentencia for: En la siguiente secuencia se muestran en pantalla los nmeros del 1 al 10 y sus cuadrados.

int i; for (i = 1; i <= 10; i++) { printf ("\nValor de i: %d", i); printf ("|tValor de i2: %d|n", i * i); }

Esta secuencia, se muestran en pantalla las letras maysculas de la A a la Z.

char letra; for (letra = 'A'; letra <= 'Z'; letra++) cout<< letra<<endl;

El valor de incremento/decremento de las variables de control

puede ser

diferente de 1. El siguiente ejemplo muestra en pantalla los nmeros pares comprendidos entre 1 y 100, descendentemente:

int i; for (i = 100; i >= 1; i = i - 2) cout << i <<"\t ";

Es posible tener ms de una variable de control del bucle. En el bucle for las secciones de inicializacin e incremento pueden tener, a su vez, subsecciones, en cuyo caso van separadas por el operador secuencial (,). Un ejemplo es:

int i, j; for (i = 0, j = 1; i + j < N; i++, j++) cout<< i + j<<endl;

que visualiza los N primeros nmeros impares. No debe confundirse esta sentencia con un anidamiento de bucles for. Un anidamiento tiene el siguiente aspecto:

int i, j; for (i = 0; i <= 100; i++) { //cuerpo_del_bucle_externo; for (j = 0; j <= 100; j++) { } } //cuerpo_del_bucle_interno;

La condicin de salida del bucle no tiene por qu referirse a la variable de control. Esto queda ilustrado en el siguiente ejemplo:

char a; int i; for (i = 1; a != 's'; i++) { printf ("\n%d", i); a = getch ();

En este ejemplo se van mostrando en pantalla los nmeros 1, 2,...mientras presionemos cualquier carcter hasta que se teclee el carcter s. El bucle for puede no tener cuerpo. Esta caracterstica permite crear retardos en un programa.

int i; for (i = 0; i < 100; i++);

El bucle provoca un retardo de 100 ciclos, saldr del bucle cuando la variable sea mayor o igual a100. El bucle for puede tener vaca cualquier seccin. En un bucle for puede faltar una, dos o las tres secciones. Por ejemplo, es correcto escribir

register int i; for (i = 0; i != 10; ) { scanf ("%d", &i); printf ("\n%d", i); } /* Falta la 3 seccin (incremento) */

que va mostrando en pantalla los valores que se ingresen, finalizando al ingresar el nmero 10 (que tambin se visualiza). Tambin podemos escribir un bucle como:

for ( ; ; ) {

cuerpo_del_bucle; }

que es un bucle sin fin, debe haber en el cuerpo del bucle una sentencia que rompa el ciclo del programa como lo es una sentencia break. Ejemplo:

void main () { int n; for ( ; ; ) { printf ("\nTeclee un nmero: "); scanf ("%d", &n); if (!n) break; printf ("\nEl cuadrado es %d", n * n); } }

4.2.2.2.

Sentencia while

La sentencia while tiene una condicin del bucle (una expresin lgica) que controla la secuencia de repeticin. La sentencia evala la condicin antes de que se ejecute el cuerpo del bucle si se cumple la condicin, realiza los procesos que controla la sentencia, sino sale de esta y contina con el flujo del programa. Como podemos observar en la figura 4.6:

Fiugra 4. 6. Diagrama de flujo sentencia while.

El cuerpo del bucle no se ejecutar nunca si la primera vez no se cumple la condicin. El bucle puede ser infinito si no se modifican adecuadamente las variables de la condicin dentro del bucle. Sintaxis:

while ( condicin ) { sentencias .......... ; }

Veamos algunos ejemplos. En esta sentencia se solicita un carcter del teclado mientras no se teclee el carcter n ni el carcter s. Cuando se teclea alguno de estos caracteres, se almacena en c y se abandona el bucle.

char c; while (c != 's' && c != 'n') c = getche (); El siguiente ejemplo es un caso de bucle while sin cuerpo. Se mantendr en el ciclo hasta que se teclea el carcter s.

while (getch () !=s); El siguiente programa utiliza un bucle while para solicitar del usuario que adivine un nmero. Realizar un programa que muestre los nmero del 1 al 100.

#include <conio.h> #include <iostream.h> main() { int contador=0;

while ( contador < 100 ) { contador++; cout<<"\t "<<contador; } cout<<"Presione Enter para salir"; }

4.2.2.3.

Equivalencias ente las sentencias for y while.

Las sentencias for y while son equivalentes entre si ya que se pueden emular entre s, aunque podramos usar ambas sin problemas, se recomienda el uso de sentencias for para recorridos y la sentencia while cuando dependa del resultado de un proceso: Emulando un while mediante una sentencia for:

for ( ; condicin ; ) { sentencias; }

// while carece de inicio y de iteraciones

Emulando un for mediante una sentencia while:

inicio; // la sentencia for posee valores de inicio while ( condicin ) { sentencias; iteraciones; // la sentencia for posee valores de iteraciones } Ejemplo 1: Determine si un numero es capico (se lee igual en ambos sentidos).

Usando la sentencia while #include <conio.h>

Usando la sentencia for #include <conio.h>

#include <iostream.h> void main() { int a, inv, aux; cout<<Ingrese un numero:; cin>>a; aux = a; inv = 0; while ( aux > 0 ) { // separar dgitos e invertir inv = inv * 10 + aux % 10; aux = aux / 10; } if(a == inv) cout<<"El numero es capico; else cout<<"El numero no es capico; }

#include <iostream.h> void main() { int a, inv, aux; cout<<Ingrese un numero:; cin>>a; for(aux=a, inv=0; aux>0; aux/=10) { // separar dgitos e invertir inv = inv * 10 + aux % 10; } if(a == inv) cout<<"El numero es capico; else cout<<"El numero no es capico; }

Ejemplo 2: Muestre un cuadro usando el carcter x y una dimensin n. Sera necesario usar sentencia anidadas para desplazar el cursor de manera horizontal y vertical.

Usando la sentencia while #include <conio.h> #include <iostream.h> void main() { int i, j, n; cout<<Ingrese la dimensin:; cin>>num; i = 0; while(i < n ) { j=0; while( j < n) { if(i==0||i==n-1||j==0||j==n-1) cout<<"x; else cout<< ; j++; }

Usando la sentencia for #include <conio.h> #include <iostream.h> void main() { int i, j, n; cout<<Ingrese la dimensin:; cin>>num; for(i = 0; i < n ; i++) { for(j = 0; j < n; j++) if(i==0 || i==n-1|| j==0|| j==n-1) cout<<"x; else cout<< ; cout<<endl; } }

cout<<endl; i++; } } Ejemplo 2: Muestre una X usando el carcter x y una dimensin n.

Usando la sentencia while #include <conio.h> #include <iostream.h> void main() { int i, j, n; cout<<Ingrese la dimensin:; cin>>num; i = 0; while(i < n ) { j=0; while( j < n) { if(i==j || i+j==n-1) cout<<"x; else cout<< ; j++; } cout<<endl; i++; } }

Usando la sentencia for #include <conio.h> #include <iostream.h> void main() { int i, j, n; cout<<Ingrese la dimensin:; cin>>num; for(i = 0; i < n ; i++) { for(j = 0; j < n; j++) if(i==j || i+j==n-1) cout<<"x; else cout<< ; cout<<endl; } }

4.2.2.4.

Sentencia do-while

La sentencia do - while se utiliza para especificar un bucle condicional que se ejecuta al menos una vez. Esta situacin se suele dar en algunas circunstancias en las que se ha de tener la seguridad de que una determina accin se ejecutara una o varias

veces, pero al menos un vez. El flujo de ejecucin podemos obsrvala en la siguiente figura 4.7:

Fiugra 4. 7. Diagrama de flujo sentencia do-while.

En esta sentencia a diferencia de la sentencia for y while, primero realizara las sentencias que controle una vez realizada evaluara la condicin, si esta es verdadera, volver a realizar las sentencias hasta que la condicin en algn momento sea falsa. Las sentencias se ejecuta al menos una vez, incluso aunque la expresin se evale como falsa, puesto que la evaluacin se hace al final, a diferencia de la sentencia while y for, en el que la evaluacin de la condicin se hace al principio.

Sintaxis:

do{ sentencias; }while(condicin); Esta sentencia por su conformacin la hacen preferibles en problemas que se espere un valor antes de poder ejecutar procesos, como por ejemplo: validaciones, mens de espera, ingreso de datos con clave nica, etc. Ejemplo: Realizar un programa que convalide el ingreso de dos notas con rango [0 20] y halle el promedio de ambas notas.

#include <conio.h> #include <iostream.h> void main() { int nota1, nota2; do{ //termina del ciclo solo si el valor nota1 est en el rango cout << "Ingrese la primera nota: "; cin>>nota1; if(nota1<0 || nota1>20) cout << "Nota fuera de los rangos[0-20]"<<endl; }while(nota1<0 || nota1>20)); do{ //termina del ciclo solo si el valor nota2 est en el rango cout << "Ingrese la segunda nota: "; cin>>nota2; if(nota2<0 || nota2>20) cout << "Nota fuera de los rangos[0-20]"<<endl; }while(nota2<0 || nota2>20)); cout<<"El promedio de las nontas es:"<<(nota1+nota2)/2; } En el siguiente ejemplo se solicita un carcter del teclado hasta que se pulse cualquiera de los caracteres 'S' o 'N'.

#include <iostream.h> void main () { char tecla; do { cout<<Pulse S o N: "<<endl; tecla = getch (); } while (tecla != 'S' && tecla != 'N'); }

4.2.2.5.

La sentencia break

Es una sentencia de ruptura de secuencia, permite cortar ciclos de programas. La sentencia break se puede colocar dentro de un bucle o bucles anidados. Cuando se

ejecuta la sentencia break se abandona el bucle ms interno. A todos los efectos la sentencia break acta como un salto a la instruccin siguiente al bucle en el que se ejecuta.

4.2.2.6.

La sentencia continue

La sentencia continue, no abandona el bucle si no hace que se ejecute la siguiente iteracin. En el bucle while la ejecucin del continue hace que el flujo del programa salte a la condicin. En el bucle for la ejecucin del continue hace que la expresin de incremento, para despus continuar normalmente con la condicin. Es decir, la ejecucin del continue evita que se ejecute el resto del cuerpo del bucle. Esta sentencia se utiliza en los bucles for, while y do/while. Cuando se ejecuta fuerza un nuevo ciclo del bucle, saltndose cualquier sentencia posterior. Por ejemplo,

int i, n; for (i = 1; i <= 100; i++) { n = i / 2; if (i == 2 * n) continue; printf ("\n%d", i); } el bucle :muestra en pantalla slo los nmeros impares, puesto que para los nmeros pares la expresin i == 2 * n se evala como cierta, ejecutndose la sentencia continue que fuerza de inmediato un nuevo ciclo del bucle.

CAPITULO 5
ARREGLOS

5.1.

Definicin

Los arreglos son usados extensamente por los programadores para contener listas de datos en la memoria, por ejemplo, los datos almacenados en un disco suelen leerse y ponerse dentro de un arreglo con el objetivo de facilitar la manipulacin de dichos datos, ya que los datos en memoria pueden ser modificados, clasificados, marcados para su eliminacin, etc. para luego ser reescritos al disco. Un arreglo (array) es una coleccin de datos del mismo tipo, que se almacenan en posiciones consecutivas de memoria y reciben un nombre comn. Para diferenciar cada elemento de un arreglo se utiliza un ndice, que especifique su posicin relativa en el arreglo. Los ndices son nmeros que se utilizan para identificar a cada uno de los componentes de un arreglo. Por ejemplo podemos pensar en los casilleros, as que si deseamos guardar o retirar un paquete nos dirigimos al casillero el cual sera el arreglo; y dado el nmero especfico el cual representa el ndice para identificar el lugar del casillero en donde qued guardado el paquete.

Un arreglo es una coleccin finita, homognea y ordenada de elementos. Finita: Todo arreglo tiene un lmite; es decir, debe determinarse cul ser el nmero mximo de elementos que podrn formar parte del arreglo. Homognea: Todos los elementos del arreglo deben ser del mismo tipo. Ordenada: Se puede determinar cul es el primer elemento, el segundo, el tercero,.... y el n-simo elmento.

5.2.

Declaracin de arreglos

Para declarar un arreglo se emplea la sintaxis:

tipo identificador[ [tamao] ] [ = { lista de inicializacin } ] ;

donde, tipo se refiere al tipo de datos que contendr el arreglo. El tipo puede ser cualquiera de los tipos estndar (char, int, float, etc.) o un tipo definido por el usuario. Es ms, el tipo del arreglo puede ser de una estructura creada con: struct, class. identificador se refiere al nombre que le daremos al arreglo. tamao es opcional e indica el nmero de elementos que contendr el arreglo. Si un arreglo se declara sin tamao, el mismo no podr contener elemento alguno a menos que en la declaracin se emplee una lista de inicializacin. lista de inicializacin es opcional y se usa para establecer valores para cada uno de los componentes del arreglo. Si el arreglo es declarado con un tamao especifico el nmero de valores inicializados no podr ser mayor a dicho tamao.

Ejemplos:

int int_A[5]; long long_A[5] = { 1, 2, 3, 4, 5 }; char char_A[] = { 'a', 'b', 'c' ); int bidim_A[4][4]={{1,1},{2,3}};

5.3.

Clasificacin de los arreglos

Los arreglos los podemos clasificar de acuerdo con el nmero de dimensiones que tienen. As se tienen los: Unidimensionales (vectores): representados por una coleccin de elementos con un mismo nombre y diferenciados por un ndice. Multidimensionales: Tridimensionales. Bidimensionales Representados por (tablas o matrices) de y

colecciones

arreglos

unidimensionales (matrices) o mltiples matrices.

5.3.1. Arreglos unidimensionales.

Los arreglos unidimensionales pueden ser apreciados en la vida cotidiana como por ejemplo un armario el cual est dividido por gavetas, una cola de personas que realizan un mismo proceso como la compra de un mismo artculo, etc. Podemos definir los arreglos unidimensionales como una coleccin de variables del mismo tipo, con un mismo nombre y diferenciadas a travs de un ndice. Tambin podramos representarlo como un conjunto compuesto por elementos internos con un universo limitado. (Figura 5.1)

Figura 5. 1.Representacin de un arreglo unidimensional.

El formato para declarar un arreglo unidimensional es:

tipo nomb_arr[tamao] = { lista de inicializacin } ; //La lista es opcional

donde, el tamao representa la dimensin o cantidad de elementos o variables del mismo tipo que componen al arreglo. El nombre de arreglo representa la direccin de todos los elementos declarado en el. Donde cada variable declarada en el arreglo est compuesta por una direccin y contenido. Por ejemplo, para declarar un arreglo de enteros llamado listanum con diez elementos se hace de la siguiente forma:

int listanum[10];

El ejemplo declara un arreglo de enteros con diez elementos o variables enteras desde listanum[0] hasta listanum[9]. Cada una de las variables declaradas puede ser utilizada referenciando su ndice. La forma como pueden ser accesados los elementos de un arreglo, es de la siguiente forma:

listanum[2] = 15; /* Asigna 15 al 3er elemento del arreglo */ num = listanum[2]; // Asigna el contenido del 3er elemento a la variable num Para evaluar, leer, modificar un arreglo de elementos es necesario realizar recorridos a travs de este, es decir si se quiere realizar alguna operacin sobre el arreglo es necesario utilizar sentencias iterativas que permitan recorrer el arreglo desde una posicin a otra.

Sea la declaracin de los arreglos A y B:

int A[10], B[10];

Si se desea leer o asignar a los 10 elementos del arreglo, es necesario desplazarnos por cada una de las variables desde la posicin 0 hasta la posicin 9. Si se desea leer los 10 elementos del arreglo A.

int i; for (i = 0; i < 10; i++) { cout<<Ingrese el elemento A[<<i<<]:; cin>>A[i]; } Para asignar a los 10 elementos del arreglo B el mismo valor del arreglo A.

int i; for (i = 0; i < 10; i++) { B[i] = A[i]; } Si se desea buscar un elemento en el arreglo A, es necesario comparar el valor buscado con cada elemento del arreglo.

int i, encontrado; for (encontrado=0, i = 0; encontrado==0 && i < 10; i++) { if ( buscado == A[i]) encontrado = 1; } if ( encontrado==1) cout<<El elemento buscado fue encontrado; else cout<<El elemento no fue localizado;

Si se desea ordenar los elementos del arreglo A, es necesario comparar cada valor del arreglo y ubicarlo en la posicin correspondiente, en la siguiente sentencia se utilizara el mtodo de la burbuja el cual consiste en comparar un elemento con el siguiente y dependiendo del criterio de comparacin y valor de peso este ser cambiado o no.

int i, cambio, aux, n=10; do{ // nos indica la cantidad de veces necesarias para ordenar cambio = 0; //si su valor se mantiene en cero el arreglo estar ordenado for (i = 0; i < n-1; i++) // el ltimo elemento no ser comparado if ( A[i] <criterio> A[i+1]) // criterio (>) ordena de menor a mayor { cambio = 1; // criterio (<) ordena de mayor a menor aux = A[i]; // intercambia los valores A[i] con A[i+1] A[i] = A[i+1]; A[i+1] = aux; } } }while( cambio!=0); El ejemplo anterior usando el mtodo de ordenamiento por seleccin seria:

int i, j, aux, n=10; for (i = 0; i < n-1; i++) // selecciona la posicin del elemento a ordenar for (j = i+1; i < n; j++) // busca si hay un elemento que cumpla criterio if ( A[i] <criterio> A[j]) // criterio (>) ordena de menor a mayor { // intercambia los valores A[i] con A[j] aux = A[i]; A[i] = A[j]; A[j] = aux; } Si desea mostrar los elementos del arreglo A:

int i; cout<<Los elementos del arreglo:<<endl;

for ( i = 0; i < 10; i++) { cout<<A[i]<<\t; } Ejemplo: Programa para determinar el mayor y menor de n nmeros enteros.

#include <conio.h> #include <iostream.h> #define max 100 void main() { int num[max]; int i, n, mayor, menor; do { cout<<Ingrese la cantidad de numeros a ingresar:; cin>>n; }while( n<1 || n>100); for(i = 0; i < n ; i++) // ingresa los n nmeros { cout<<Ingrese el numero[<<i+1<<]:; cin>>num[i]; } for(i = 1, mayor= num[0], menor=num[0]; i < n; i++) { // compara los nmeros y los guarda sea el resultado if(mayor < num[i]) mayor = num[i]; if(menor > num[i]) menor = num[i]; } cout<<"El mayor: <<mayor<< y el menor: <<menor<<endl; }

5.3.2. Arreglos multidimensionales.

Se podrn declarar arreglos de mayor dimensin, bidimensionales y tridimensionales como sigue:

ya sean arreglos

// Bidimensional tipo_de_dato identificador[tamao1][tamao2]; // Tridimensional

tipo_de_dato identificador[tamao1][tamao2][tamao3]; dnde: tipo_de_dato: Es el tipo de datos que contendr la matriz. Hasta ahora slo conocemos los tipos bsicos de datos; int, float, double, char. Posteriormente veremos cmo definir nuestros propios tipos de datos. identificador: Es el nombre que le damos a la variable matriz y por el cual la referenciaremos en un programa. [tamao]: Indica la dimensin o el nmero de elementos de tipo tipo_de_datos contendr la matriz identificada. Si se definen 2 dimensiones (arreglo bidimensional), la cantidad total ser igual al producto de ambas dimensiones o tamaos.

5.3.2.1.

Arreglo bidimensional.

Un arreglo bidimensional es aquel en donde los componentes son accesados por medio de una pareja de ndices que apunten a la fila y columna del componente requerido. Los arreglos de este tipo son conocidos tambin con el nombre de matrices o tablas. Conceptualmente, podemos pensar en un arreglo bidimensional como en una lista compuesta de filas y columnas, en donde para referirnos a una de ellas emplearemos un nmero para indicar la posicin de fila y otro nmero para indicar la posicin de la columna del componente deseado.(Figura 5.2)

Figura 5. 2. Representacin de un arreglo bidimensional.

La primera dimensin establece la cantidad de filas. La segunda dimensin establece la cantidad de columnas. Al igual que en los arreglos de una dimensin, todos los datos sern del mismo tipo y nombre y diferenciada por dos ndices. Tambin podemos decir que representa un conjunto compuesto por subconjuntos interno, donde la primera dimensin representa la cantidad de estos conjuntos los cuales tienen la misma cantidades de elementos todos del tipo declarado representado por la segunda dimensin. Es decir lo representamos como un arreglo de arreglos unidimensionales.

5.3.2.2.

Arreglo Tridimensional

Los arreglos tridimensionales estn compuestos por tres dimensiones donde la primera dimensin representa la cantidad de arreglos bidimensionales, la segunda dimensin representa la cantidad de arreglos unidimensionales y la tercera dimensin representa la cantidad de elementos que contiene cada arreglo unidimensional. Permite realizar representaciones en tres planos. (Figura 5.3)

Figura 5. 3. Representacin de un arreglo tridimensional.

5.3.2.3.

Declaracin de los arreglos bidimensionales y tridimensionales

Para declarar un arreglo bidimensional, matriz o tabla:

tipo_de_dato nomb_matriz[fila][columnas];

Para declarar un arreglo tridimensional:

tipo_de_dato nomb_arreglo[fila][columnas][elementos];

Algunas declaraciones de matrices y arreglos tridimensionales.

Matriz de nmeros reales de 10x10:

float matriz[10][10];

Matriz tridimensional de nmeros enteros 20x20x10:

int

Tridimensional[20][20][10];

Como ya se supondr el acceso a cada elemento de la matriz se realiza especificando su posicin, pero sta comienza a contarse desde el valor 0, es decir, la matriz que hemos declarado (matriz) tendr elementos desde el [0][0] al [9][9]. Esto puede causar algunos mal entendidos cuando se trabaja con matrices estticas. Por ejemplo:

a = matriz [2][1];

Al tomar el valor del elemento (2,1) comenzando a contar desde 0, es decir que el elemento se ubica en la tercera fila (fila 2) de la segunda columna (columna 1).

tridimensional [5][16][1] = 67;

Introduce el valor 67 en la entrada de la matriz especificada

Las variables de tipo matriz como el resto de las declaraciones, se pueden inicializar en el momento de su declaracin, ayudndose de las llaves ({}) para la inclusin de inicializaciones mltiples.

int matriz[2][3] = { { 1,2,3 }, { 4,5,6 } }; Estas lneas nos declararan una matriz llamada "matriz" de 2x3 elementos inicializada con los valores indicados. Las matrices son extremadamente tiles para trabajar con multitud de problemas matemticos que se formulan de esta forma o

para mantener tablas de datos a los que se accede con frecuencia y por tanto su referencia tiene que ser muy rpida. Se permite la inicializacin de arreglos, debiendo seguir el siguiente formato:

tipo nombre_arr[ n] = {lista- nvalores}; tipo nombre_arr[ n ][ m ] = {{lista-0},, {lista-n-1}}; tipo nombre_arr[ n][m][l] = {{{lista0-0},,{lista0-m-1}}, {{listan-1-0},,{listan-1-m-1}}; }; Por ejemplo:

int i[10] = {1,2,3,4,5,6,7,8,9,10}; int num[3][4]= { {0,1,2,3}, {4,5,6,7}, {8,9,10,11} }; int num[2][2][2]={{{0,1}, {2,3}}, {{4,5}, {6,7}}}; A igual que los arreglos unidimensionales, los arreglos multidimensionales utilizaran sentencias interactivas anidadas para cada una de las dimensiones.

5.3.2.4.

Ejemplo de arreglos multidimensionales

Ejemplo 1: Realice un programa que lea una matriz de n * n elementos enteros y muestre cuntos de estos elementos son primos. #include <conio.h> #include <iostream.h> #define max 100 void main() { int num[max][max]; int i, j, n, div, contprimos;

do { cout<<Ingrese la cantidad de nmeros a ingresar:; cin>>n; }while( n<1 || n>100); for(i = 0; i < n ; i++) // recorre las filas

for(j = 0; j < n ; j++) // recorre las columnas { cout<<Ingrese el numero[<<i+1<<][<<j+1<<]:; cin>>num[i][j]; } for(contprimos=0, i = 0; i < n ; i++) // recorre las filas for(j = 0; j < n ; j++) { for(div=2;div<num[i][j] && num[i][j]%div!=0; div++); if(div==num[i][j]) contprimos++; } cout<<"Existen : <<contprimos<< numeros primos<<endl; } // recorre las columnas

Ejemplo 2: calcular el determinante de una matriz de n * n elementos enteros.

#include<iostream.h> void main() { int i,j,k,l,m,n ; float a[50][50]; float det; cout << "Introducir el ORDEN DE LA MATRIZ : N = " << endl; cin >> n; m=n-1;

cout << "Introducir los elementos" << endl; cout << "------------------------" << endl;; for(i=0; i<n; i++) for(j=0; j<=n; j++) cin >> a[i][j]; det=a[0][0]; for(k=0;k=m;k++) { l=k+1; for(i=l;i<n;i++) { for(j=l;j<n;j++) a[i][j] = ( a[k][k]*a[i][j]-a[k][j]*a[i][k] )/a[k][k]; } det=det*a[k+1][k+1]; } cout << endl; cout << "DETERMINANTE = " << det << endl; cout << "------------------------" << endl; }

Ejemplo 3: Realice un programa que lea una matriz de n * n elementos enteros y muestre el arreglo solo ordenando los nmeros pares.

#include <conio.h> #include <iostream.h> #define max 20 void main() { int num[max][max]; int i, j, k, n, aux, auxA[max*max];

do { cout<<Ingrese la cantidad de nmeros a ingresar:; cin>>n; }while( n<1 || n>100); for(i = 0; i < n ; i++) for(j = 0; j < n ; j++) { cout<<Ingrese el numero[<<i+1<<][<<j+1<<]:; cin>>num[i][j]; } for(i = 0,k=0; i < n ; i++) for(j = 0; j < n ; j++) auxA[k++]=num[i][j];

for(i = 0; i < k-1 ; i++) if(auxA[i]%2==0) for(j = i+1; j < k ; j++) if(auxA[j]%2==0 && auxA[i] >auxA[j]) { aux=auxA[i];

auxA[i]=auxA[j]; auxA[j]=aux; }

cout<<"La matriz ordenado solo sus valores pares es:<<endl; for(i = 0,k=0; i < n ; i++) { for(j = 0; j < n ; j++) { num[i][j]= auxA[k++]; cout<<num[i][j]<< ; } cout<<endl;

} }

Ejemplo 4: Realice un programa que lea una matriz de n * n elementos enteros y muestre si la diagonal principal es igual a la secundaria. Adems muestre cuales filas son iguales a su columna.

#include <conio.h> #include <iostream.h> #define max 20 void main() { int num[max][max]; int i, j, k, n, v; do { cout<<Ingrese la cantidad de nmeros a ingresar:; cin>>n; }while( n<1 || n>100); for(i = 0; i < n ; i++) for(j = 0; j < n ; j++) { cout<<Ingrese el numero[<<i+1<<][<<j+1<<]:; cin>>num[i][j]; }

for(i = 0; i < n ; i++) if(num[i]i] != num[i][n-1-i]) break; if(i==n) cout<<la diagonal principal es igual a la secundaria<<endl; else

cout<<las diagonal principal y secundaria son distintas<<endl;

for(i = 0; i < n ; i++) for(k=0; k<n; k++) { for(j = 0; j< n ; j++) if(num[i]j] != num[k][j]) break; if(j==n) cout<<la Fila:<<i+1<< es igual a la Columna:<<k+1<<endl; } }

Adems de clasificar los arreglos segn su dimensin, tambin los podemos declarar segn sea su tipo de datos: En arreglos numricos y arreglos alfanumricos o de caracteres. Tomando como diferencia primordial el contenido que puede almacenar sus variables, notaremos que en los numricos puede existir diversidad de smbolos (como se ha reflejado en los apartados anteriores) y en los de carcter un nico smbolo, por lo que son llamadas cadenas de caracteres.

5.3.3. Cadenas de caracteres. Una cadena es un conjunto de caracteres, o valores de tipo "char", terminados con el carcter nulo, es decir el valor numrico 0. Internamente se almacenan en posiciones consecutivas de memoria. Este tipo de estructuras recibe un tratamiento especial, y es de gran utilidad y de uso continuo. Lo que distingue a una cadena de caracteres, con respecto a un arreglo numrico, es que la cadena de caracteres tiene como ltimo carcter al carcter nulo \0. Esto permite conocer hasta donde evaluaremos la secuencia de caracteres. La manera de definir una cadena es la siguiente:

char nombre_identificador [<longitud mxima>];

Por ejemplo, si se declara el arreglo:

char cadena[8];

Se podr asignar los siguientes valores a cada uno de sus elementos:

cadena[0] = 'A' ; cadena[1] = 'R' ; cadena[2] = 'R' ; cadena[3] = 'E' ; cadena[4] = 'G' ; cadena[5] = 'L' ; cadena[6] = 'O' ; cadena[7] = '\0';

Al contener el carcter nulo, el arreglo cadena ser reconocido por las funciones y objetos diseados para manipular cadenas de caracteres. Entre estas las sentencias de salida cout, printf, puts, etc. Para manejar y realizar operaciones con las cadenas de caracteres es necesario realizar sentencias de recorrido hasta encontrar el carcter fin de cadena. Lo que lo diferencia de los arreglos numricos que es necesario conocer la cantidad de elementos a evaluar. Un arreglo es necesario leer y mostrar cada elemento uno a uno en el caso de las cadenas solo es necesario usar una funcin que atrape cadenas de caracteres o las muestre, ejemplo:

char cadena[10]; get ( cadena); cin>>cadena; // Lee una cadena de caracteres // Lee la cadena y transforma el carcter intro en\0

scanf(%s, cadena); // Lee la cadena y transforma el carcter intro en\0 cout<<cadena; // muestra todos los caracteres hasta el carcter final

Para evaluar una cadena siempre sera necesario al menos una sentencia de recorrido. Ejemplo: realice un programa que lea una frase y cambie un carcter de la frase por un nuevo carcter.

#include <conio.h> #include <iostream.h> #define max 100 void main() { char frase[max]; char carV, carN; cout<<Ingrese una frase: gets(frase); cout<<Ingrese el carcter a modificar: carV = getch(); cout<<Ingrese el nuevo nuevo carcter: carN = getch();

for(i = 0; frase[i] !=\0 ; i++) if( frase[i] ==carV) frase[i] = carN ;

cout<<"La nueva frase es : <<frase<<endl; }

Para manejar un arreglo de cadenas de caracteres se debe declarar como un arreglo bidimensional de elementos de tipo char, como por ejemplo: Leer 10 nombres y una calificacin.

#include <iostream.h> #include <conio.h> void main() { unsigned short int calif[10]; char nombre[10][20]; // Se declara un arreglo bidimensional

// para 10 nombres de 20 caracteres por // nombre ms un carcter para el nulo. for( int x=0 ; x < 10 ; x++) { cout << "NOMBRE [" << x +1<< "] = " ; cin >> nombre[x]; cout << "CALIFICACION [" << x+1 << "] = " ; cin >> calif[x]; } }

Cuando se tiene un arreglo de cadenas de caracteres, se puede utilizar para asignar valores en las declaraciones de cadena. Por Ejemplo:

char nombres[][5] = { "HUGO", "PACO", "LUIS" } ;

Es equivalente a:

char nombres[3][5]; nombres[0] = "HUGO" ; // no aplicable nombres[1] = "PACO" ; // no aplicable nombres[2] = "LUIS" ; // no aplicable

Esto tambin puede manejarse a nivel de caracteres, as:

char nombres[][5] = { 'H','U','G','O','\0', 'P','A','C','O','\0', 'L','U','I','S','\0' };

o as:

char nombres[3][5];

nombres[0][0] = 'H' ; nombres[0][1] = 'U' ; nombres[0][2] = 'G' ; nombres[0][3] = 'O' ; nombres[0][4] = '\0' ; nombres[1][0] = 'P' ; nombres[1][1] = 'A' ; nombres[1][2] = 'C' ;

nombres[1][3] = 'O' ; nombres[1][4] = '\0' ; nombres[2][0] = 'L' ; nombres[2][1] = 'U' ; nombres[2][2] = 'I' ; nombres[2][3] = 'S' ; nombres[2][4] = '\0' ;

Al manejar arreglos bidimensionales de cadenas, no es necesario escribir el valor de la primera dimensin de los arreglos cuando, en su declaracin, se asignan valores constantes a los elementos. La ventaja que tiene es que, al no especificar una de las dimensiones, la cantidad de cadenas a manejar puede variarse con slo agregarlas a la lista o eliminarlas de ella.
Adems de las funciones gets() y puts(), existe otro grupo de funciones para el manejo de cadenas de caracteres, como strlen() y strupr(). Los prototipos de estas funciones se encuentran declarados en la libreria STRING. En la tabla (Figura 5.4) siguiente se describen brevemente algunas de las funciones para el manejo de cadenas de caracteres, cuyos prototipos se encuentran declarados en STRING.H.

FUNCION stpcpy strcat strchr strcmp strcmpi strcpy strdup _strerror strerror

DESCRIPCION Copia una cadena de caracteres en otra. Aade una cadena de caracteres a otra. Busca, en una cadena, un carcter dado. Compara dos cadenas. Macro que compara dos cadenas sin distinguir entre maysculas y minsculas. Copia una cadena. Copia una cadena a una nueva localidad. Genera un mensaje de error definido por el programador. Retorna el apuntador al mensaje asociado con el valor del error.

stricmp strlen strlwr strncat strncmp strncmpi strncpy strnset strpbrk strrchr strrev strset strspn strstr _strtime strtod strtol strtoul strupr

Compara dos cadenas sin diferenciar entre maysculas y minsculas Determina la longitud de una cadena. Convierte las maysculas de una cadena en minsculas. Aade el contenido de una cadena al final de otra. Compara parte de una cadena con parte de otra. Compara parte de una cadena con parte de otra, sin distinguir entre maysculas y minsculas. Copia un nmero de bytes dados, desde una cadena hacia otra. Hace que un grupo de elementos de una cadena tengan un valor dado. Busca la primera aparicin, en una cadena, de cualquier carcter de un conjunto dado. Busca la ltima aparicin de un carcter en una cadena. Invierte el orden de los caracteres de una cadena. Hace que los elementos de una cadena tengan un valor dado. Busca en una cadena el primer segmento que es un subconjunto de un conjunto de caracteres dado. Busca en una cadena la aparicin de una subcadena dada. Convierte la hora actual a una cadena. Convierte una cadena a un valor double long double. Convierte una cadena a un valor long. Convierte una cadena a un valor unsigned long. Convierte las minsculas de una cadena a maysculas. Figura 5. 4. Tabla de funciones para el manejo de cadenas de caracteres.

5.3.3.1.

Ejemplo de cadenas de caracteres

Ejemplo1: Realice un programa que lea una frase y muestre si es palindrome.

#include <conio.h> #include <iostream.h> #define max 100 void main() { char frase[max]; int i, j; cout<<Ingrese una frase: gets(frase); for(i = 0; frase[i] !=\0 ; i++); for(i=i-1, j = 0; frase[i] == frase[j] && i > j ; j++);

if( i<=j) cout<<"La frase : <<frase<< es palindrome<<endl; else cout<<"La frase : <<frase<< no es palindrome<<endl; }

Ejemplo2: Realice un programa que lea n nombres, convierta los caracteres a mayscula y los muestre ordenados alfabticamente.

#include <conio.h> #include <iostream.h> #define max 25 #define max2 100 void main() { char nom[max2][max], aux[max]; int i, j, k, v, n, cambio; cout<<Ingrese cantidad de nombres:

cin>>n; cout<<Ingrese los nombres:<<endl; for( i=0 ; i < n ; i++) { cout << "|tNombre: [" << i +1<< "] = " ;

cin >> nom[i]; } // transforma los n nombres a mayscula for(i = 0; i<n ; i++) for(j = 0; nom[i][j] !=\0 ; j++) if(nom[i][j]>=a && nom[i][j]<=z) nom[i][j]=nom[i][j] 32;

// ordena los n nombres mtodo burbuja do{ cambio=0; for(i = 0; i<n-1 ; i++) { v=0; for (j=0; v==0 && nom[i][j]!=\0&& nom[i+1][j]!=\0; j++) if(nom[i][j] > nom[i+1][j]) v=1; else if(nom[i][j] < nom[i+1][j]) v=2; if(v==0){ if(nom[i][j]!=\0) v=1;

if(nom[i+1][j]!=\0) v=2; } if( v==1){ cambio=1; for(j = 0; nom[i][j] !=\0 ; j++) aux[j]=nom[i][j]; aux[j]=nom[i][j]; for(j = 0; nom[i+1][j] !=\0 ; j++) nom[i][j]=nom[i+1][j];

nom[i][j]=nom[i+1][j]; for(j = 0; aux[j] !=\0 ; j++) nom[i+1][j]=aux[j]; nom[i+1][j]=aux[j]; } } }while(cambio==1);

cout<<"Los nombres ordenados alfabticamente:<<endl; for(i = 0; i<n ; i++) cout<< nom[i]<< endl; }

Ejemplo 3: Realice un programa que lea n nombres, convierta a mayscula y elimine los nombres repetidos.

#include <conio.h> #include <iostream.h> #define max 25 #define max2 100 void main() { char nom[max2][max], aux[max]; int i, j, k, l, v, n; cout<<Ingrese cantidad de nombres: cin>>n; cout<<Ingrese los nombres:<<endl; for( i=0 ; i < n ; i++) { cout << "|tNombre: [" << i +1<< "] = " ;

cin >> nom[i]; } // transforma los n nombres a mayscula for(i = 0; i<n ; i++) for(j = 0; nom[i][j] !=\0 ; j++) if(nom[i][j]>=a && nom[i][j]<=z) nom[i][j]=nom[i][j] 32;

// busca las frases repetidas y las elimina for(k=0;k<n-1; k++) for(i = k; i<n ; i++) { v=0; for (j=0; v==0 && nom[i][j]!=\0&& nom[i+1][j]!=\0; j++) if(nom[i][j] > nom[i+1][j]) v=1; else if(nom[i][j] < nom[i+1][j]) v=2; if(v==0) { if(nom[i][j]!=\0) v=1;

if(nom[i+1][j]!=\0) v=2; } if( v==0){ for(l = i; l<n ; l++) { for(j = 0; nom[l+1][j] !=\0 ; j++) nom[l][j]=nom[l+1][j]; nom[l][j]=nom[l+1][j]; } i--; n--; } }

cout<<"Los nombres sin repetir son:<<endl; for(i = 0; i<n ; i++) cout<< nom[i]<< endl; }

CAPITULO 6
APUNTADORES

6.1.

Referencias de memoria.

Las referencias son novedades absolutas del C++ (no se encuentran disponibles en C). Una referencia es un nuevo tipo de datos que nos va a permitir utilizar las caractersticas de los punteros pero tratndolos como variables ordinarias. Podis imaginaros una referencia como un "alias" de una variable o, mejor dicho, como la misma variable disponible pero con un nombre distinto. La inicializacin de una referencia es simple, slo tendremos que asociar una referencia a una variable que ya est creada. Una vez realizado la inicializacin, la referencia va a estar continuamente asociada con la variable correspondiente. Si quisiramos hacer que la referencia fuese el "alias" de otra variable o referenciar a otra variable no podramos, ocurre un error de compilacin, solo podr realizarse en el momento de su declaracin. La declaracin de una referencia:

Tipo_dato &nombre_referencia = variable_declarada;

Ejemplo:

// dato es una variable definida y es de tipo entero. int dato; // referenciaDato es la referencia creada de dato. int &referenciaDato = dato;

Como se observa para crear una referencia no necesitamos ms que la variable a la que queremos referenciar, que en el ejemplo es dato, junto la referencia en s, que se va a definir con el smbolo &. De este modo, referenciaDato es la referencia o alias de la variable dato. Una vez realizada, cualquier cambio que hagamos sobre dato se ver reflejado en referenciaDato y viceversa, es decir, si realizamos una modificacin en referenciaDato, esta tambin se va a ver reflejada en la variable dato. Ejemplo:

#include <iostream.h> void main() { int dato = 50; int& refDato = dato; cout << "La variable dato vale " << dato << \n; cout << "La variable refDato vale " << refDato << \n; // multiplicamos la variable dato por 2, ahora dato = 100 dato *= 2; cout << "La variable dato vale " << dato << /n; cout << "La variable refDato vale " << refDato << \n; // incrementamos el valor de refDato = 101; refDato ++; cout << "La variable dato vale " << dato << \n; cout << "La variable refDato vale " << refDato; } Si se observa los resultados en la salida, tenemos que:

La variable dato vale 50 La variable refDato vale 50 La variable dato vale 100

La variable refDato vale 100 La variable dato vale 101 La variable refDato vale 101

Los cambios efectuados en dato y refDato se ven involucrados. Debido a que dato y refDato comparten la misma direccin de memoria y por eso, cualquier cambio que efectuemos sobre dato afectar a refDato y viceversa. (Figura 6.1)

Figura 6. 1. Referencia de memoria.

Para comprobar que las direcciones de dato y refDato son las misma, realizamos:

void main() { int dato = 50; int& refDato = dato; cout << "La direccin de la variable dato es " << &dato << endl; cout << "La direccin de la referencia refDato es " << &refDato; }

6.2.

Apuntadores.

6.2.1. Concepto.

Los apuntadores o punteros se definen como una variable que contiene la direccin de memoria de un dato o de otra variable que contiene al dato. El puntero apunta al espacio fsico donde est el dato o la variable. Pueden apuntar a un objeto de cualquier tipo, como una estructura o una funcin. Se utilizan para referenciar y manipular estructuras de datos, bloques de memoria, paso de argumentos. Los punteros o apuntadores podemos conceptualizarlos como referencias de memoria variables, las cuales permiten realizar operaciones con las posiciones de memorias, permitiendo el desplazamiento entre las variables y adems con la posibilidad de modificar el contenido de estas. Es una herramienta cmoda, poderosa y directa para el manejo de variables complejas, argumentos, parmetros, etc.

6.2.2. Declaracin de un apuntador.

Para declarar un puntero, este deber tener un tamao de memoria a la cual se pueda ubicar y un nombre el cual se identifica su forma de referenciar y el operar * el cual nos indica la presencia del puntero:

tipo_de_variable_apuntada

*nombre_del_puntero ;

Ejemplo:

int *pint ; double *pfloat ; char *letra , *codigo , *caracter ;

En estas declaraciones indicamos al compilador que reserve una posicin de memoria para albergar la direccin de una variable, del tipo indicado, la cual ser referenciada con el nombre que hayamos dado al puntero. El tipo de dato del puntero indica la capacidad del puntero de ubicarse en una variable o estructura de dato, la cual deber ser del mismo tamao. Cuando declaramos un puntero como:

int *a;

Indicamos que: a representa la direccin de memoria que apunta. y *a representa el contenido de la direccin de memoria apuntada.

Obviamente, un puntero debe ser inicializado antes de usarse, y una de las eventuales formas de hacerlo es la siguiente:

int var1 ;

// declaro ( y creo en memoria ) una variable entera )

int *pint ; // un puntero que contendr la direccin de una variable entera pint = &var1 ; //escribo en la direccin del puntero la de la variable "&nombre_de_una_variable " implica la direccin de la misma. Esquemticamente, lo que hemos hecho se puede simbolizar como se muestra en la Figura 6.2:

Figura 6. 2. Representacin de un puntero.

La variable var1 reserva una direccin de memoria de 2 bytes solo para ella, el puntero apunta a esta posicin permitiendo utilizar el contenido de esta. En la declaracin del puntero, est implcita otra informacin: el tamao (en bytes) de la variable apuntada. El smbolo &, direccin, puede aplicarse a variables, funciones, etc., pero no a constantes expresiones, ya que stas no tienen una posicin de memoria asignada. La operacin inversa a la asignacin de un puntero, de referenciacin del mismo, se puede utilizar para hallar el valor contenido por la variable apuntada. As por ejemplo sern expresiones equivalentes:

y = var1 ; y = *pint ; printf("%d" , var1 ) ; printf("%d" , *pint) ; En estos casos, la expresin " *nombre_del_puntero ", implica " contenido de la variable apuntada por el mismo. Ejemplo de esto:

#include <stdio.h> void main() { char var1 ; //una variable del tipo carcter char *pchar; // un puntero a una variable del tipo carcter pchar = &var1 ; //*asignamos al puntero la direccin de la variable

for (var1 = 'a'; var1 <= 'z'; var1++) printf("%c", *pchar) ; // imprimimos el valor de la variable apuntada } Vemos ac, que en el for se incrementa el valor de la variable, y luego para imprimirla usamos la de referenciacin de su puntero. El programa imprimir las letras del abecedario de la misma manera que lo habra hecho si la sentencia del printf hubiera sido, printf("%c" , var1 ). Hay un error, que se comete con bastante frecuencia, y es cargar en la direccin apuntada por un puntero a un tipo dado de variable, el contenido de otro tipo de las mismas, por ejemplo:

double d = 10.0 ; int i = 7 , *pint ; pint = &i ; *pint = 10 ; // correcto, equivale a asignar a i el valor 10 *pint = d ; // ERROR se pretende cargar en una variable entera un valor double pint = &d ; // INCORRECTO se pretende apuntar a una variable double con un puntero declarado como apuntador a int pint = 4358 ; // ?????? El primer error, la asignacin de un double, produce la prdida de informacin dada por la conversin automtica de tipo de variable, el segundo produce un llamado de atencin rotulado como " asignacin sospechosa de un pointer. Resumiendo, las variables constantes cargadas por de referenciacin de un puntero, deben coincidir en tipo con la declaracin de aquel. La asignacin de una constante a un pointer, y no a la variable apuntada por l, es un serio error, ya que debe ser el compilador, el encargado de poner en l el valor de la direccin, aquel as lo declara dando un mensaje de "conversin de puntero no transportable" . Si bien lo compila, ejecutar un programa que ha tenido esta

advertencia es similar a jugar a la ruleta rusa, puede "colgarse" la mquina lo que es peor destruirse involuntariamente informacin contenida en un disco, etc. Hay un slo caso en el que esta asignacin de una constante a un puntero es permitida, muchas funciones para indicar que no pueden realizar una accin que se ha producido un error de algn tipo, devuelven un puntero llamado "Null Pointer", lo que significa que no apunta a ningn lado vlido, dicho puntero ha sido cargado con la direccin NULL (por lo general en valor 0), as la asignacin: pint = NULL; es vlida y permite luego operaciones relacionales del tipo if( pint ) ..... if( pint != NULL ) para convalidar la validez del resultado devuelto por una funcin. Una advertencia seria que se debe tener en cuenta que los punteros no son enteros, como parecera a primera vista, ya que el nmero que representa a una posicin de memoria, s lo es. Debido al corto alcance de este tipo de variable, algunos compiladores pueden, para apuntar a una variable muy lejana, usar cualquier otro tipo, con mayor alcance que el antedicho.

6.2.3. Apuntadores y arreglos

Hay una relacin muy cercana entre los punteros y los arreglos. El nombre de un arreglo es equivalente a la direccin del elemento[0] del mismo.

int a[10]; // La direccin del primer elemento: &a[0] // La direccin del arreglo se refleja como su mismo nombre: a // entonces a == &a[0], ambas direcciones son equivalentes

El nombre de un arreglo, para el compilador, es un apuntador inicializado con la direccin del primer elemento del arreglo. Sin embargo hay diferencias entre ambos.

6.2.4. Asignacin de los apuntadores.

Observemos las lneas siguientes:

float var1 , conjunto[] = { 9.0 , 8.0 , 7.0 , 6.0 , 5.0 }; float *punt ; punt = conjunto ; // equivalente a hacer : punt = &conjunto[0] var1 = *punt ; *punt = 25.1 ; Es vlido asignar a un puntero el valor de otro, el resultado de sta operacin es cargar en el puntero punt la direccin del elemento[0] del arreglo, y posteriormente en la variable var1 el valor del mismo (9.0) y para luego cambiar el valor de dicho primer elemento a 25.1. La diferencia entre un puntero y el denominador de un arreglo, el primero es variable, es decir que puedo asignarlo, incrementarlo, etc, en cambio el arreglo es una constante, que apunta siempre al primer elemento del arreglo con que fue declarado, por lo que su contenido no puede ser variado. Si lo piensa un poco, es lgico, ya que un "conjunto" implica la direccin del elemento conjunto[0], por lo que, si yo cambiara su valor, apuntara a otro lado dejando de ser un "conjunto. El siguiente ejemplo nos muestra un tipo de error frecuente:

int conjunto[5] , lista[] = { 5 , 6 , 7 , 8 , 0 ) ; int *apuntador ; apuntador = lista ; // correcto conjunto = apuntador; // ERROR (conjunto es una direccin constante) lista = conjunto ; // ERROR ( son direcciones constantes ) apuntador = &conjunto; //ERROR no se puede aplicar el operador & a una constante

6.2.5. Incremento y decremento de un apuntador.

Dado las siguientes instrucciones podemos analizar:

int *pint , arreglo_int[5] ; double *pdou , arreglo_dou[6] ; pint = arreglo_int ; // pint apunta a arreglo_int[0] pdou = arreglo_dou ; // pdou apunta a arreglo_dou[0] pint += 1 ; // pint apunta a arreglo_int[1] pdou += 1 ; // pdou apunta a arreglo_dou[1] pint++ ; // pint apunta a arreglo_int[2] pdou++ ; // pdou apunta a arreglo_dou[2]

Hemos declarado y asignado dos punteros, uno a int y otro a doubl, con las direcciones de dos arreglos. Ambos estarn ahora apuntando a los elementos[0] de los arreglos. En las dos instrucciones siguientes incrementamos en uno dichos punteros. En el compilador, estas sentencias se leen como: incremente el contenido del puntero (direccin del primer elemento del arreglo) en un nmero igual a la cantidad de bytes que tiene la variable con que fue declarado. Es decir que el contenido de pint es incrementado en dos bytes (un int tiene 2 bytes) mientras que pdou es incrementado 8 bytes (por ser un puntero a double), el resultado entonces es el mismo para ambos, ya que luego de la operacin quedan apuntando al elemento siguiente del arreglo, arreglo_int[1] y arreglo_dou[1].

Vemos que de sta manera ser fcil recorrer un arreglo, independientemente del tamao de variables que lo compongan, permitiendo por otro lado que el programa sea transportable a distintos hardwares sin preocuparnos de la diferente cantidad de bytes que pueden asignar los mismos, a un dado tipo de variable.

6.2.6. Aritmtica de referencia

Debido a que los operadores * y ++ -- tienen la misma precedencia y se evalan de derecha a izquierda, y los parntesis tienen mayor precedencia que ambos, muchas operaciones que los utilizan en conjunto a todos estos operadores, pueden parecer poco claras y dar origen a un sin nmero de errores, analicmoslas detalladamente, partiendo de:

int *p , a[] = { 0 , 10 , 20 , 30 , 40 , 50 , 60 , 70 , 80 , 90 } ; int var ; p=a; El puntero est apuntando a a[0] . Si:

*p = 27 ;

Se asignamos al elemento apuntado por p (que seria a[0] ) un valor constante. De forma inversa:

var = *p ;

var sera asignada al valor contenido de a[0] , y p seguira apuntando al mismo elemento. Si fuese de la forma:

var = *( p + 1 ) ;

Carga a var con el contenido del elemento siguiente al apuntado por p (el cual seria a[1] ). El puntero p, no vara sigue apuntando a a[0] . De la misma forma: var = *( p + 3 ) asignar 30 a var, sin modificar el contenido de p.

En cambio la expresin:

var = *( p++ ) ;

Se asigne a var el valor de lo apuntado por

p e incremente luego ste para

que apunte al prximo elemento. As en var quedara con el valor de a[0] y p apuntara a a[1] . Si en vez de esto hubiramos preincrementado a p tendramos:

var = *( ++p ) ;

Apunte con p al prximo elemento y asigne a var con el valor de ste. En este caso var sera igualada al valor de a[1] y p quedara apuntando al mismo .

En las dos operaciones anteriores los parntesis son superfluos ya que al analizarse los operadores de derecha a izquierda, dara lo mismo escribir:

var = *p++ ; // sintcticamente igual a var = *(p++) var = *++p ; // " " " var = *(++p)

6.2.7. Aritmtica de punteros

La aritmtica ms frecuentemente usada con punteros son las sencillas operaciones de asignacin, incremento decremento y de referenciacin. Todo otro tipo de aritmtica con ellos est prohibida es de uso peligroso poco transportable. Por ejemplo no est permitido, sumar, restar, dividir, multiplicar, etc., dos apuntadores entre s. Por ejemplo.

int *p, *q;

p = p + q; // no tendra caso realizar // le asignamos a p una direccin que no conocemos Otras operaciones estn permitidas, como la comparacin de dos punteros, por ejemplo (punt1 == punt2) (punt1 < punt2), sin embargo este tipo de operaciones son potencialmente peligrosas, ya que con algunos modelos de pointers pueden funcionar correctamente y con otros no.

6.2.8. Los apuntadores y las cadenas de caracteres

No hay gran diferencia entre el trato de punteros a arreglos, y a cadenas de caracteres, ya que estos dos ltimos son entidades de la misma clase. Sin embargo analicemos algunas particularidades. Los punteros prestan un mejor beneficio a la hora de As como inicializamos una cadena con un grupo de caracteres terminados en '\0', podemos asignar al mismo un puntero:

p = "Esto es una cadena constante ";

Esta operacin no implica haber copiado el texto, sino slo que a p se le ha asignado la direccin de memoria donde reside la "E" del texto. A partir de ello podemos manejar a p como lo hemos hecho hasta ahora. Veamos un ejemplo:

#include <iostream.h> #define TEXTO1 " Hola , como " #define TEXTO2 "le va a Ud. ? " void main() { char palabra[20] , *p ; int i ; p = TEXTO1 ; for( i = 0 ; ( palabra[i] = *p++ ) != '\0' ; i++ ) ; p = TEXTO2 ;

cout<< palabra ; cout<< p; } Definimos primero dos cadenas constantes TEXTO1 y TEXTO2, luego asignamos al puntero p la direccin del primero, y seguidamente en el for copiamos el contenido de ste en el arreglo palabra, observe que dicha operacin termina cuando el contenido de lo apuntado por p es el terminador de la cadena, luego asignamos a p la direccin de TEXTO2 y finalmente se muestra ambas cadenas, obteniendo una salida del tipo: " Hola , como le va a UD. ? ". Reconozcamos que esto se podra haber escrito ms compacto, ya que palabra tambin es un puntero y NULL es cero, cambiamos el for:

while( *palabra++ = *p++ ) ;

Un programa ejemplo del uso de puntero en cadena podra ser el modificar una frase dada a mayscula como se muestra a continuacin:

#include <iostream.h> #include <stdio.h> #include <conio.h> #define max 100 void main() { char frase [max]; char *p; p=frase; cout<<Ingrese una frase:; gets(p); for( ; *p!=|0 ; *p++) if(*p>=a && *p<=z) *p=*p-32; // como los caracteres difieren en 32 //de mayscula a minscula cout<<La frase ingresada en mayscula:<<frase<<endl;

6.2.9. Arreglos de apuntadores

Es una prctica muy habitual, sobre todo cuando se tiene que tratar con cadenas de distinta longitud, generar arreglos cuyos elementos son punteros, que albergarn las direcciones de dichas cadenas. Si imaginamos a un puntero como una flecha, un arreglo de ellos equivaldra a un conjunto de flechas. As como:

char *flecha;

Se declara un puntero a un carcter. Entonces la declaracin:

char *flecha[5];

implica un arreglo de 5 punteros a caracteres. Los arreglos de punteros pueden ser inicializados de la misma forma que un arreglo comn, es decir dando los valores de sus elementos, durante su declaracin, por ejemplo si quisiramos tener un arreglo donde el subndice de los elementos coincidiera con el nombre de los das de la semana, podramos escribir:

char *dias[] = { "nmero de da no vlido" , "lunes" , "martes" , "miercoles" , "jueves" , "viernes" , "sabado" , "domingo"

}; Igual que antes, no es necesario en este caso indicar la cantidad de elementos, ya que el compilador los calcula por la cantidad de trminos dados en la inicializacin. As el elemento dias[0] ser un puntero con la direccin de la primera cadena, dias[1] , la del segundo, etc. Sea A una matriz de enteros (arreglo de 2 dimensiones) y P un arreglo de punteros enteros:

int A[5][5]; int *P[5];

// Matriz de dos dimensiones //arreglo de punteros

Las declaraciones anteriores nos indican la declaracin de 25 elementos de tipo entero para la matriz A y de 5 elementos declarados como punteros de tipo int para P Como se muestra la Figura 6.3.

Figura 6. 3. Representacin de una matriz entera y un arreglo de punteros

Si queremos que cada puntero en el arreglo de punteros, apunte a cada arreglo de la matriz, entonces asignaremos a cada puntero con las filas de la matriz A:

int i; int A[5][5]; // Matriz o arreglo de dos dimensiones int *P[5]; // arreglo de punteros for (i=0; i<5; i++) P[i]=A[i];

Como ese muestra en la Figura 6.4.

Figura 6. 4. Arreglo de punteros apunta a cada fila de la matriz.

Aunque podramos pensar que el bucle que asigna a los elementos del arreglo de punteros P las filas de A (P[i]=A[i] ), puede sustituirse por P=A, no se puede ya que los niveles de direccin son diferentes. Expresados de otra forma, los tipos de P y A no son iguales ni admiten una conversin entre ellos:

El tipo de P El tipo de P[i] El tipo de A El tipo de A[i]

int *[5] int * int (*)[5] int *

( arreglo de 5 elementos tipo puntero a int) (puntero a int) ( puntero a una arreglo de 5 elementos tipo int) (puntero a int)

6.2.10. Apuntador a apuntador.

Para especificar que una variable es un puntero utilizada es la siguiente:

a un puntero, la sintaxis

tipo_de_variable_apuntada **nomb_var_puntero_a_puntero ;

donde tipo_de_variable_apuntada especifica el tipo del apuntador la doble direccin ** indica un puntero que apunta a un puntero y

nomb_var_puntero_a_puntero es el identificador de la variable puntero a puntero. Por ejemplo:

int A, *P, **PP; A = 10; // dato P = &A; //puntero que apunta al dato PP = &P; // puntero que apunta al puntero que apunta al dato Grficamente en memoria esto sera como se muestra en la figura 6.5.

Figura 6. 5. Apuntador a apuntador.

Un ejemplo utilizando un puntero a puntero seria el cdigo siguiente:

void main() { int i, j; int A[5][5]={{1,2,3,4,5}, {5,4,3,2,1},{0,1,2,3,4},{4,3,2,1,0},{0,1,0,1,0}}; int *p[5] ; // arreglo de punteros int **q ; //puntero a puntero entero for(i=0; i<5; i++) p[i] =A[i]; q = p; for(i=0; i<5; i++) { for(j=0; j<5; j++) cout<<q[i][j]; cout<<endl; } } Como podemos observar con q[i][j] podemos recorrer elementos del arreglo podemos notar, q[i] es misma direccin que A[i] , si q siendo la direccin de A que es

la misma direccin de A[0] , entonces q+1 es la posicin de A[1] y q+i es la direccin q+i. De esta observacin concluimos que las representaciones siguientes son iguales: q[i][j] , *(q[i]+j), *(*(q+i)+j) Segn lo expuesto, las direcciones q+1 y *(q+1) tienen significados diferentes, por ejemplo: q+1+2 *(q+1)+2 *(*(q+1)+2) es la direccin del elemento q[3] de la matriz de punteros. es la direccin del elemento q[1][2]. es el valor del elemento q[1][2].

6.3.

Asignacin de memoria dinmica.

Cuando se habla de asignacin dinmica de memoria se hace referencia al hecho de crear variables que reserven espacio en memoria en tiempo de ejecucin del programa, as como liberar el espacio reservado para dichas variables, cuando ya no son necesarias, tambin durante el tiempo de ejecucin. Supongamos que debemos recibir una serie de datos de entrada, digamos del tipo double, y debemos procesar segn un determinado algoritmo a aquellos que aparecen una ms veces con el mismo valor. Si no estamos seguros de cuantos datos van a ingresar a nuestro programa, pondremos alguna limitacin, suficientemente grande a los efectos de la precisin requerida por el problema, digamos 10000 valores como mximo, debemos definir entonces un arreglo de tipo double capaz de albergar a diez mil de ellos, por lo que el mismo ocupar del orden de los 80Kb de memoria. Si definimos este en main(), ese espacio de memoria permanecer ocupado hasta el fin del programa, aunque luego de aplicarle el algoritmo de clculo ya no lo necesitemos ms, comprometiendo seriamente nuestra disponibilidad de memoria para albergar a otras variables. Una solucin posible sera definirlo en una funcin llamada en main (), que se ocupara de llenar el arreglo con los datos, procesarlos y

finalmente devolviera algn tipo de resultado, borrando con su retorno a la masiva variable de la memoria. Los programas ejecutables creados dividen la memoria disponible en varios segmentos, uno para el cdigo (en lenguaje mquina), otro para albergar las variables globales, otro para el stack (a travs del cual se pasan argumentos y donde residen las variables locales) y finalmente un ltimo segmento llamado memoria de apilamiento amontonamiento.(Figura 6.6).

Figura 6. 6. Esquema de asignacin de memoria.

La memoria de apilamiento es la zona destinada a albergar a las variables dinmicas, es decir aquellas que crecen (en el sentido de ocupacin de memoria) y decrecen a lo largo del programa, pudindose crear y desaparecer (desalojando la memoria que ocupaban) en cualquier momento de la ejecucin. Supongamos que queremos ubicar un nico dato, declaramos un puntero al tipo de la variable, ejemplo:

double *p ;

notemos que sta declaracin no crea lugar para la variable, sino que asigna un lugar en la memoria para que posteriormente se guarde ah la direccin de aquella. Para reservar una cantidad dada de byte, se efecta una llamada a alguna de las funciones dedicadas al manejo del mismo. La ms tradicional es malloc() (su nombre deriva de memory allocation), a esta funcin se le da como argumento la cantidad de bytes que se quiere reservar, y nos devuelve un pointer apuntando a la primer posicin de la "pila" reservada. En caso que la funcin falle en su cometido (la memoria est llena) devolver un puntero inicializado con NULL.

p = malloc(8) ;

hemos pedido 8 bytes (los necesarios para albergar un double) y hemos asignado a p el retorno de la funcin, es decir la direccin de la memoria reservada. Como es algo engorroso recordar el tamao de cada tipo variable, agravado por el hecho de que, si reservamos memoria de esta forma, el programa no se ejecutar correctamente, si es compilado con otro compilador que asigne una cantidad distinta de bytes a dicha variable, es ms usual utilizar sizeof, para indicar la cantidad de bytes requerida:

p = malloc( sizeof(double) ) ;

Se comprueba si se reservo con xito mediante:

if( p == NULL ) rutina_de_error() ;

si no lo fue, estas sentencias me derivan a la ejecucin de una rutina de error que tomar cuenta de este caso. Por supuesto podra combinar ambas operaciones en una sola, como:

if( ( p = malloc( sizeof(double) ) ) == NULL ) { cout<<"no hay mas lugar en memoria!") ; exit(1) ; }

se ha reemplazado aqu la rutina de error, por un mensaje y la terminacin del programa, por medio de exit() retornando un cdigo de error .

6.3.1. La funcin malloc

Es la funcin genrica para asignar memoria dinmica a apuntadores. Su prototipo es:

void * malloc (size_t nbytes);

donde nbytes es el nmero de bytes que queremos que sean asignados al apuntador. La funcin retorna un apuntador de tipo void*, por lo que tenemos que hacer type cast al valor al tipo del apuntador destino, por ejemplo:

char * r; r = (char *) malloc (10);

Esto asigna a r un apuntador a un bloque de 10 bytes. Cuando queremos asignar un bloque de data a un tipo diferente a char (diferente a 1 byte) debemos multiplicar

el nmero de elementos deseados por el tamao de cada elemento. Tenemos a disposicin el operador sizeof, que retorna el tamao del tipo de un dato en concreto.

int * b; b = (int *) malloc (5 * sizeof(int));

Este cdigo asigna a b un apuntador a un bloque de 5 enteros de tipo int, este tamao puede ser igual a 2, 4 o ms bytes de acuerdo al sistema donde el programa es compilado.

6.3.2. La funcin calloc.

calloc es muy similar a malloc en su funcionamiento, su principal diferencia es en su prototipo:

void * calloc (size_t nelements, size_t size);

ya que admite 2 parmetros en vez de 1. Estos dos parmetros se multiplican para obtener el tamao total del bloque de memoria a ser asignado. Usualmente el primer parmetros (nelements) es el nmero de elementos y el segundo (size) sirve para especificar el tamao de cada elemento. Por ejemplo, podramos definir a b con calloc as:

int *b; b = (int *) calloc (5, sizeof(int));

Otra diferencia entre malloc y calloc es que calloc inicializa todos sus elementos a 0.

6.3.3. La funcin realloc

Cambia el tamao de un bloque de memoria ya asignado a un apuntador.

void * realloc (void * pointer, size_t size);

El parmetro pointer recibe un apuntador a un bloque de memoria ya asignado o un apuntador nulo, y size especifica el nuevo tamao que el bloque de memoria deber tener. La funcin asigna size bytes de memoria al apuntador. La funcin podra necesitar cambiar la localidad del bloque de memoria para que el nuevo tamao pueda encajar, en ese caso el contenido actual del bloque es copiado al nuevo para garantizar que la data existente no se pierda. La funcin retorna el nuevo apuntador. Si no ha sido posible asignar el bloque de memoria con el nuevo tamao retorna un apuntador nulo, pero el pointer especificado como parmetro y su contenido permanecen sin cambios.

6.3.4. La funcin free

Libera un bloque de memoria dinmica previamente asignado usando malloc, calloc o realloc.

void free (void * pointer);

Esta funcin debe ser usada solamente para liberar memoria asignada con las funciones malloc, calloc y realloc.

6.3.5. Operadores new

Este operador permite solicitar memoria dinmica. new es seguido por un tipo de dato y opcionalmente el nmero de elementos requeridos entre corchetes []. Retorna un apuntador al comienzo del nuevo bloque de memoria asignada. Su forma es:

pointer = new type pointer = new type [elementos] La primera expresin es usada para asignar memoria para contener un solo elemento de tipo type. La segunda se usa para asignar un bloque (un arreglo) de elementos de tipo type. Por ejemplo:

int *b; b = new int [5]; En este caso, se ha asignado espacio para 5 elementos de tipo int en un heap y ha retornado un apuntador a su comienzo que ha sido asignado a b. Por lo tanto, ahora, b apunta a un bloque de memoria vlido con espacio para 5 elementos int.

Podra preguntarse cul es la diferencia entre declarar un arreglo normal y asignar memoria a un apuntador como hemos hecho. La ms importante es que el tamao de un arreglo debe ser un valor constante, el cual limita su tamao a lo que decidamos al momento de designar el programa antes de su ejecucin, mientras que la asignacin dinmica de memoria permite asignar memoria durante la ejecucin del programa usando cualquier variable, constante o combinacin de ambas como tamao.

La memoria dinmica es generalmente administrada por el sistema operativo, y en interfaces multitarea puede ser compartida entre varias aplicaciones, por lo que existe la posibilidad de que la memoria se acabe. Si esto ocurre y el sistema operativo no puede asignar la memoria que solicitamos con el operador new, se retorna un apuntador nulo. Por esta razn se recomienda siempre chequear si el apuntador retornado es nulo, luego de una llamada a new.

int *b; b = new int [5]; if (bobby == NULL) { // error asignando memoria. };

6.3.6. Operador delete

Ya que la necesidad de memoria dinmica est limitada a momentos concretos dentro de un programa, una vez que no se necesita ms debera ser liberada para que se convierta en disponible para futuras solicitudes de memoria dinmica. Para este propsito existe el operador delete, cuya forma es:

delete pointer; delete [] pointer; La primera expresin debera ser utilizada para borrar memoria asignada para un nico elemento, y la segunda para memoria asignada para mltiples elementos (arreglos). En la mayora de los compiladores ambas expresiones son equivalentes y pueden ser utilizadas sin distincin, aunque en realidad son dos operadores diferentes y as deben ser considerados para sobrecarga de operadores.

6.3.7. Ejemplos de asignacin de memoria dinmica

Ejemplo1: Reserva de memoria de varios datos simples.

#include<stdlib.h> #include<iostream.h> void main() { int *dato_simple; dato_simple = (int *) malloc (3*sizeof(int)); }

Ejemplo2: Realice un programa que lea n enteros y los muestre.

#include<stdlib.h> #include<iostream.h>

void main() { int n, i;

int *datos; cout<<Ingrese la cantidad de datos:; cin>>n; datos = (int *) malloc (n*sizeof(int)); for(i=0; i<n; i++) { cout<<Ingrese el numero#<<i+1<<:;

cin>>datos[i]; }

cout<<Los nmeros ingresados:; for(i=0; i<n; i++) cout<<datos[i]<<endl; }

CAPITULO 7
FUNCIONES

7.1.

Concepto.

Las funciones son un conjunto de instrucciones que realizan una tarea especfica. En general toman ciertos valores de entrada, llamados parmetros y proporcionan un valor de salida o valor de retorno; aunque en C++, tanto unos como el otro son opcionales, y pueden no estar presentes. Desde un punto de vista prctico, podemos decir que una funcin es una parte de un programa (subrutina) con un nombre, que puede ser invocada (llamada a ejecucin) desde otras partes tantas veces como se desee. Una funcin en un mtodo de organizacin, creando una visin clara del cdigo de un programa, adems que permite su reutilizacin. Si observamos detalladamente notaremos que el cuerpo principal de un programa es una funcin, lo que cabe destacar que las funciones son la base del lenguaje. 7.2. Prototipos de funciones

Un prototipo es una declaracin de una funcin. Consiste en una presentacin de la funcin, exactamente con la misma estructura que la definicin, pero sin cuerpo y terminada con un ";". En C++ es necesario en muchos casos el uso de los prototipos. Esto permite identificar o reconocer la existencia de la funcin en el programa. La estructura de un prototipo es:

[extern|static]<tipovalor_retorno> <identificador>(<lista_parmetros>);

En general, el prototipo de una funcin se compone de las siguientes secciones: Opcionalmente, una palabra que especifique el tipo de almacenamiento, puede ser extern o static. Si no se especifica ninguna, por defecto ser extern. El tipo del valor de retorno, que puede ser void, si no necesitamos valor de retorno. En C, si no se establece, ser int por defecto, aunque en general se considera una mala tcnica de programacin omitir el tipo de valor de retorno de una funcin. En C++ es obligatorio indicar el tipo del valor de retorno. El identificador de la funcin. Es costumbre, muy til y muy recomendable, poner nombres que indiquen, lo ms claramente posible, qu es lo que hace la funcin, y que permitan interpretar qu hace el programa con slo leerlos. Cuando se precisen varias palabras para conseguir este efecto se puede usar alguna de las reglas ms usuales. Una consiste en separar cada palabra con un "_". Por ejemplo, si hacemos una funcin que busque el nmero de telfono de una persona en una base de datos, podramos llamarla "busca_telefono" o "BuscaTelefono". Una lista de declaraciones de parmetros entre parntesis. Los parmetros de una funcin son los valores de entrada (y en ocasiones tambin de salida). Para la funcin se comportan exactamente igual que variables, y de hecho cada parmetro se declara igual que una variable. Una lista de parmetros es un conjunto de declaraciones de parmetros separados con comas. Puede tratarse de una lista vaca. En C es preferible usar la forma "func(void)" para listas de parmetros vacas. En C++ este procedimiento se considera obsoleto, se usa simplemente "func()".

Por ejemplo:

int Mayor(int a, int b);

Un prototipo sirve para indicar al compilador los tipos de retorno y los de los parmetros de una funcin, de modo que compruebe si son del tipo correcto cada vez que se use esta funcin dentro del programa, o para hacer las conversiones de tipo cuando sea necesario. En el prototipo, los nombres de los parmetros son opcionales, y si se incluyen suele ser como documentacin y ayuda en la interpretacin y comprensin del programa. El ejemplo de prototipo anterior sera igualmente vlido si se escribiera como:

int Mayor(int, int);

Esto slo indica que en algn lugar del programa se definir una funcin "Mayor" que admite dos parmetros de tipo int y que devolver un valor de tipo int. No es necesario escribir nombres para los parmetros, ya que el prototipo no los usa. En otro lugar del programa habr una definicin completa de la funcin. Normalmente, los prototipos de las funciones se declaran dentro del fichero del programa, o bien se incluyen desde un fichero externo, llamado fichero de cabecera. Las funciones son extern por defecto. Esto quiere decir que son accesibles desde cualquier punto del programa, aunque se encuentren en otros ficheros fuente del mismo programa. En contraposicin las funciones declaradas static slo son accesibles dentro del fichero fuente donde se definen.

7.3.

Definicin de funciones

Al igual que hemos visto con las variables, las funciones deben declararse, para lo que usaremos los prototipos, pero tambin deben definirse. Una definicin contiene adems las instrucciones con las que la funcin realizar su trabajo, es decir, su cuerpo o cdigo. La sintaxis de una definicin de funcin es:

[extern|static] <tipo_valor_retorno> <identificador>(<lista_parmetros>) { [sentencias] //cuerpo de la funcin return valor; //debe ser del mismo valor que tipo_valor_retorno } Como vemos, la sintaxis es idntica a la del prototipo, salvo que se elimina el punto y coma final, y se aade el cuerpo de funcin que representa el cdigo que ser ejecutado cuando se llame a la funcin. El cuerpo de la funcin se encierra entre llaves "{}". La definicin de la funcin se hace ms adelante o ms abajo, segn se mire, es decir, se hace despus que el prototipo y cuerpo principal main(). Lo correcto es hacerlo despus de la funcin main() si existe el prototipo, de lo contrario solo se define por encima del cuerpo principal ya que la misma funcin sirve como prototipo en su definicin. Una funcin muy especial es la funcin main(). Se trata de la funcin de entrada, y debe existir siempre, ya ser la que tome el control cuando se ejecute el programa. El valor de retorno es el valor de respuesta que da la funcin una vez culminada mediante el uso de la palabra reservada return, este deber ser del mismo tipo que la funcin definida, cualquier otro valor de retorno ser errneo. Si la funcin est definida con la palabra void, se indica que no deber retornar valor de respuesta, es decir que en el cuerpo de la funcin esta la respuesta de esta de forma implcita.

7.4.

Invocacin a funciones

Una invocacin llamada a una funcin implica pasarle el control de la ejecucin del programa, as como los argumentos parmetros que requiere para realizar su tarea. Por ejemplo se tienen las lneas:

saludo(); precio = calcula(costo);

//invocacin a la funcin saludo() //invocacin a la funcin calcula()

En la primera, se invoca a la funcin saludo() y no se le pasa ningn argumento. En la segunda, se invoca a la funcin calcula(), pasndosele como argumento una copia del valor que tiene la variable costo. El valor retornado por calcula() se asigna a la variable precio. El programa seria:

#include <iostream.h> #include <conio.h> // Declaracin de funciones void saludo(); float calcula(float); // Funcin principal void main() { float costo, precio; clrscr(); cout << "COSTO : $ "; cin>> costo; saludo(); // invocacin a la funcin saludo() precio = calcula(costo); // invocacin a la funcin calcula() cout << "PRECIO : $ " << precio; getch(); } // Definicin de la funcin saludo()

void saludo() { cout << "!! BIENVENIDO A LA VENTA ESPECIAL !!"; } // Definicin de la funcin calcula() float calcula(float x) { return( x * 1.6); }

7.5.

Parmetros y Argumentos

Son el medio a partir del cual podemos expandir el mbito de variables locales de funciones, hacia otras funciones y adems quienes nos permiten establecer comunicaciones entre funciones. Si nos vemos ante la necesidad de visualizar o modificar el valor de una variable local en otra funcin que llamaremos, debemos invocar a dicha funcin haciendo referencia de su nombre, seguido de los parmetros o nombres de variables para las cuales, ampliaramos su mbito.

void funcion_llamada(int x) // funcin que recibe un argumento { } void una_funcion(void) // variables de mbito local { int a,b; funcion_llamada(a); // llamada de la funcin con un parmetro } Desde luego que, sobre la base de la comunicacin entre funciones y la teora del paradigma procedimental donde aplicamos la disgregacin de procesos, nos podemos encontrar con las siguientes variantes:

Llamado de funciones sin pasar parmetros. Llamado de funciones pasando parmetros.

Est claro que dichas funciones pueden o no devolvernos valores hacia el origen de su llamado.

7.5.1. Paso de parmetros

Cuando se invoca a una funcin, en ocasiones es necesario enviarle algunos elementos indispensables para realizar su tarea. Estos elementos, enviados en la invocacin, se llaman parmetros actuales. Dadas las dos necesidades bsicas en una funcin, de poder obtener el contenido de una variable o el de modificar el contenido de una variable, clasificaremos el paso de ellos en:

7.5.1.1.

Paso de parmetros por valor o contenido

Cuando surge la necesidad de obtener el valor o contenido de una variable original o local a una funcin, en otra funcin, se utiliza paso de parmetros por valor cuando se enva una copia de los valores de los parmetros actuales. En este caso, la funcin invocada no podr modificar los valores de las variables utilizadas como parmetros actuales, sino que trabajar con las copias que se le envan. Estas copias son recibidas en los parmetros formales, los cuales se comportan como variables locales pertenecientes a la funcin invocada. Al igual que las variables locales, una vez que termina la ejecucin de la funcin invocada, las variables pertenecientes a los parmetros formales se destruyen; y por lo tanto, se pierden los valores que envi el mdulo invocador. El siguiente programa se muestra el paso de parmetros por valor:

#include <iostream.h> void precio(double); void main(void) { double costo;

cout << "COSTO : "; cin>> costo; precio(costo); // Se invoco a precio() y se le enva una // copia del valor de costo cout << "\n" cout << costo; // El valor de costo se conserva despues // de la invocacin de precio() } void precio(double recibido) { recibido=recibido * 1.5; // Se modifica el valor de la copia // guardada en recibido cout << "\n" cout << recibido; } Supongamos que se desea intercambiar los valores enteros de a y b mediante una funcin intercambio con paso por valor:

#include <iostream.h> void intercambiar(int, int); void main(void) { int a = 5, b = 7; cout << "a= "<< a<< " , b= "<< b<<endl; intercambiar (a, b); // se enva el contenido de a y b cout << "a= "<< a<< " , b= "<< b<<endl; } void intercambiar(int a, int b) //asigna los contenidos a las variables a y b { int aux; aux = a; a = b; b = aux; } Aunque podemos pensar que en el programa anterior intercambia los valores de a y b, en la funcin nunca modifica a los valores y que recibe una copia de sus

contenidos. Las variables a y b locales de la funcin main() son diferentes a las variables locales de a y b en la funcin intercambiar().

7.5.1.2.

Paso de parmetros por referencia

La referencia indica trabajar sobre la direccin de memoria que ocupa el parmetro o variable original. A diferencia del paso por valor, el paso por referencia permite que la funcin invocada modifique el valor original de las variables usadas como argumentos. En C++, el paso de parmetros por referencia se realiza creando un alias del identificador de la variable que forma el parmetro actual, como se muestra en el siguiente programa.

#include <iostream.h> #include <conio.h> void oferta(float &); void main(void) { float precio; cout << "CUAL ES EL PRECIO :"<<endl ; cin>> precio; oferta(precio); cout << " DIJO USTED :" << precio << endl; cout << " ESO ES CON EL 20 % DE DESCUENTO"<<endl; } void oferta(float &bajo) { bajo *=0.8 ; cout << "PRECIO REBAJADO: " << bajo; } En el programa se puede decir que bajo es otro identificador asociado a la variable precio, por lo que la funcin oferta() realmente modifica el valor contenido en dicha variable. Segn lo anterior, podemos decir que es preferible utilizar una

variable existente en lugar crear una nueva, y eliminar el paso de parmetros por valor. Supongamos que se desea intercambiar los valores enteros de a y b mediante una funcin intercambio pero esta vez usamos paso por referencia:

#include <iostream.h> void intercambiar(int, int); void main(void) { int a = 5, b = 7; cout << "a= "<< a<< " , b= "<< b<<endl; intercambiar (a, b); // se enva el contenido de a y b cout << "a= "<< a<< " , b= "<< b<<endl; } void intercambiar(int &a, int &b) //asigna un alias a las variables a y b de main() { int aux=a; a = b; b = aux; } Salida:

a=5,b=7 a=7,b=5

En este caso mostrara por salida los cambios de las variables, ya que en la funcin se crea un alias de las mismas variables paramtricas. Si al argumento por referencia lo precedemos de la palabra const, dicha variable no podr ser alterada en el mbito de la funcin receptora, por lo tanto nunca afectar a la variable original.

7.5.1.3.

Arreglos como parmetros de funcin

Al pasar un arreglo como parmetro de una funcin en su invocacin, esta no enva el contenido de los elementos del arreglo sino que, pasara la direccin de comienzo del arreglo. El argumento de arreglo de la funcin invocada tomara la misma direccin que el del arreglo enviado como parmetro. Lo que modifiquemos en el arreglo dentro de la funcin tambin se ver afectado en el arreglo paramtrico envido. En el siguiente ejemplo se leen n nombres, convirtiendo a mayscula y se muestran:

#include <conio.h> #include <iostream.h> #define max 25 void Leer( char m[][], int n) { int i; for(i=0; i<n; i++) { cout<<Ingrese el nombre#<<i+1<<:<<endl; cin>>m[i]; } } void Mostrar( char m[][], int n) { int i; cout<<Los nombres:<< endl; for(i=0; i<n; i++) cout<<m[i]<<endl; } void Mayuscula( char m[]) { int i; for(i=0; m[i]!=|0; i++) if (m[i] >=a && m[i]<=z) m[i]=m[i] - 32; } void main() { char nom[max][max]; int n; cout<<Ingrese cantidad de nombres:

cin>>n; cout<<Ingrese los nombres:<<endl; Leer(nom, n); for(i = 0; i<n ; i++) Mayuscula( nom[i]); Mostrar(a[i],n)); }

7.5.1.4.

Puntero como parmetros de una funcin

Los apuntadores y arreglos nos hacen notar que la definicin de los argumentos tipodato s[]; y tipodato *s; son completamente equivalentes cuando se pasa un nombre de un arreglo a una funcin. Ya que al pasar un arreglo como parmetro, lo que en realidad se est pasando es la direccin del comienzo del mismo. En el siguiente ejemplo se lee una frase y muestra la muestra en minscula y en mayscula:

#include <conio.h> #include <iostream.h> #define max 100 void mayuscula( char *m) { for(; *m!=|0; m++) if (*m >=a && *m<=z) *m = *m - 32; } void minuscula( char *m) { for(; *m!=|0; m++) if (*m >=A && *m<=Z) *m = *m + 32; } void main()

char frase [max],*p; p=frase; cout<<Ingrese la frase: gets(p); mayuscula( p); cout<<La frase en mayuscula<<frase<<endl; minuscula( p); cout<<La frase en minuscula<<frase<<endl;

7.6.

Funciones recursivas

Se dice que una funcin es recursiva cuando puede invocarse a s misma. En cada invocacin se crean las variables locales, por lo que es indispensable incluir una condicin de salida, ya que de no hacerlo se agotar la memoria disponible en la pila. El clculo del factorial de un nmero es un problema clsico en la aplicacin de las funciones recursivas. En el listado se presenta un programa en C++ que calcula el factorial de un nmero dado.

#include <iostream.h> #include <conio.h> long int factorial(unsigned short int); void main() { unsigned short int num; long int result; do { cout << "El FACTORIAL del nmero: " ; cin>> num ; } while(num <0 || num> 19 ); result = factorial(num); cout << " es : " << result; }

long int factorial(unsigned short int n) { if(n==0) return 1; else return n*(factorial(n-1)) ; } En el cdigo anterior, si el nmero dado por el usuario es 4, el proceso realizado por el programa se podra representar de la manera siguiente.

Numero de invocacin 1 2 3 4 5

Valor de n 4 3 2 1 0

Resultado 4*(factorial(3)) 3*(factorial(2)) 2*(factorial(1)) 1*(factorial(0)) 1

Figura 7. 1. Tabla de resultado de una funcin recursiva.

Resultados de invocar a la funcin factorial() pasndole como parmetro el nmero 4. En cada invocacin, se crea en la pila una variable cuyo identificador es n y su valor cambiar como se muestra en la tabla (Figura 7.1). Como en las invocaciones 1, 2, 3 y 4 el valor de n es diferente de 0, la funcin vuelve a invocarse a s misma, quedando sin resolver el resultado. Cuando el valor de n es igual a 0 (invocacin 5), la funcin retorna el valor 1 la la invocacin 4, por lo que el resultado en sta se calcula as:

1 * (factorial(0)) = 1 * 1 = 1

La invocacin 4 retorna a la invocacin 3 el valor 1 y el resultado en la invocacin 4 es:

2 * (factorial(1)) = 2 * 1 = 2

A su vez, la invocacin 3 retorna a la invocacin 2 el valor 2. El resultado en la invocacin 2 es:

3 * (factorial(2)) = 3 * 2 = 6

Posteriormente, la invocacin 2 retorna el valor 6 a la invocacin 1. El resultado en la invocacin 1 es:

4 * (factorial(3)) = 4 * 6 = 24

Finalmente, la invocacin 1 retorna el valor 24 a la funcin invocadora main(), la cual asigna a la variable result el valor recibido ( 24 ).

CAPITULO 8
ESTRUCTURAS, CLASES Y OBJETOS

8.1.

Estructuras.

8.1.1. Concepto.

Todas las variables que hemos utilizado hasta ahora permiten almacenar un dato y de un nico tipo, excepto los arreglos que almacenas varios datos pero de un mismo tipo. En ocasiones es necesario contar con tipos de datos que estn compuestos por conjuntos de elementos de diferentes tipos entre s. Por ejemplo si se quiere representar datos de personas esta puede estar asociada a mucha informacin de la persona, es decir cantidades matrices de variables, las cuales para poder dar relacin entre ellas tendramos que hacerlo por su posicin pero aun as siguen siendo datos desasociados. Lo que dificulta su visin y uso. (Figura 8.1)

Nombres Persona0 Persona1 PersonaN { { { Jos Mara Ashlie

Apellidos Vallejo Garca Snchez

Direccin Caracas Maturn Cumana

etc. xxx xxx xxx

Figura 8. 1.Datos de personas sin el uso de estructuras.

Las estructuras se crean con la finalidad de agrupar una o ms variables, generalmente de diferentes tipos, baj un mismo nombre para hacer ms fcil su

manejo y representacin. Las estructuras son tipos derivados definidos por el usuario que representan colecciones de elementos. Ahora sera ms fcil de expresar por ejemplo el conjunto de datos de una persona como una ficha de datos como por ejemplo nombre, apellido, direccin, etc. Donde algunos de estos datos podran a su vez ser representados por estructuras como por ejemplo fechas que estaran compuestos por los datos das, mes, ao. (Figura 8.2)
PersonaN Persona2 Persona1 Persona0 Nombre Apellido Fecha Rosmil Infante 20 02 1985

Figura 8. 2. Datos de personas usando estructuras.

Una estructura es un nuevo tipo de dato compuesto creado por el usuario con el fin de agrupar datos con una relacin en comn, estos grupos de datos sern los conocidos como: datos miembros o campos o registros del nuevo tipo.

8.1.2. Definicin de tipos de estructuras

La palabra struct se utiliza para definir un tipo compuesto o agrupacin de datos (simples y/o compuestos). Para definir una estructura usaremos el siguiente formato:

struct nombre_nuevo_tipo { // Composicin de Campos o registros tipo_dato_1 nombre_campo_1;

tipo_dato_n nombre_campo_n; }; Despus de definir un tipo de estructura, podemos declarar variables de ese tipo as: nombre_nuevo_tipo nombre_variable;

Se podrn declarar variables derivadas o compuestas, arreglos, punteros, referencias, con este nuevo tipo de dato definido. Por ejemplo, si se requiere definir un nuevo tipo llamado persona cuyos elementos sean: cedula nmero entero largo. nombre cadena de caracteres. La estructura a definir seria:

struct persona { long int cedula ; char nombre[50] ; }; En este caso, persona es un nuevo tipo que puede utilizarse para declarar una variable de la estructura como:

persona estudiante ;

8.1.3. Acceso a los miembros de una estructura.

Para acceder a los datos miembros o campos de una estructura utilizaremos el operador de contenido (.), de la forma:

Nombre_variable_estructura.dato_miembro;

Una vez declarada una estructura, operaciones:

las variables permiten las siguientes

Inicializar la variable estructura, ya sea al declararla o despus de ello (mediante una asignacin), como se muestra en:

// inicializacin al declarar estud persona estud={ 11232425, Luisa Pera }; persona estud1; // inicializacin por asignacin despus de la declaracin estud1.cedula = 12185312 ; strcpy(estud1.nombre, Alexander Blanco) ; Obtener su direccin mediante el operador direccin &, como se muestra en:

persona estud, estud1; persona *p_estud = &estud; p_estud = &estud1; Acceder a sus miembros, como se muestra:

long int cedula; persona estud={ 12345678, Armando Paredes }; cedula = estud1.cedula; Asignar una estructura a otra utilizando el operador asignacin:

persona estud_a={ 23456789, Ashlie Dorta }; persona estud_b={ 14000001, Valentina Vallejo }; persona aux;

aux = estud_a; estud_a = estud_b; estud_b = aux;

En el siguiente ejemplo, lee datos de 2 personas y las muestra ordenadas por el dato miembro cedula.

#include <iostream.h> struct persona { long int cedula ; char nombre[50] ; }; void main() { persona per1, per2, aux; //declara las variables estructuras // Lee los datos de personas cout<<Datos primera persona:<<endl; cout<< Nombre:<<endl; gets(per1.nombre); cout<< Cedula:<<endl; cin>>per1.cedula; cout<<Datos segunda persona:<<endl; cout<< Nombre:<<endl; gets(per2.nombre); cout<< Cedula:<<endl; cin>>per2.cedula; cout<<endl; // Ordena los datos de personas por cedula if(per1.cedula > per2.cedula) { aux = estud_a; estud_a = estud_b; estud_b = aux; } // Muestra los datos de personas ordenados por cedula cout<<Datos Ordenados:<<endl; cout<<per1.cedula<< <<per1.nombre<<endl; cout<<per2.cedula<< <<per2.nombre<<endl; } Se muestra en salida al ejecular:

Datos primera persona: Nombre:Maria Lopez Cedula:12924345 Datos primera persona: Nombre:Juana Ruiz Cedula:10988888

Datos Ordenados: 10988888 Juana Ruiz 12924345 Maria Lopez

8.1.4. Arreglos de Estructuras

Los arreglos se expresan como colecciones de variables de un mismo tipo el cual se diferencian cada una de estas variables a travs de un ndice. Las estructuras son variables compuestas, al igual que las variables primitivas, pueden agruparse en arreglos y ser tratados de la misma forma que colecciones primitivas. Despus de definir un tipo de estructura, podemos declarar arreglos de la forma:

nombre_nuevo_tipo nombre_coleccion[Cantidad_elementos];

Para matrices o arreglos bidimensionales:

nombre_nuevo_tipo nombre_matriz[cant_filas][cant_columnas];

Un ejemplo de ello se muestra en el cdigo siguiente de bsqueda binaria de una palabra en ingles para mostrar su expresin en espaol:

#include <iostream.h> #include <string.h> // Define la estructura dicc. struct dicc { char *ingl ; char *espa ; }; // Declaramos un arreglo de estructura dicc tabla[] = { "absolute","absoluto", "append","anexar", "begin","iniciar,principiar,comenzar", "close","cerrar", "do","hacer", "file","archivo", "while","mientras" }; #define NUMESTR (sizeof(tabla)/sizeof(dicc)) int busqbin(char * , dicc * , int) ; void main() { char pal[80]; int nret ; do{ cout << "\n\nPara finalizar, escriba FIN en : \n"; cout << "\n Palabra en ingls : "; cin>> pal; nret = busqbin(pal,tabla,NUMESTR); if(nret == -1) { if(strcmp(strupr(pal),"FIN")==0) cout << "\n\n!! Finalizado !!\n\n"; else cout << "\n\nPalabra no registrada\n\n"; } else cout << "\n" << pal << "=" << tabla[nret].espa ; }while(strcmp(strupr(pal)," FIN")!="0);" } // Busca una palabra en ingles int busqbin(char *pal, dicc *t, int N) { int bajo=0, alto=N-1, medio, cond; while(bajo <=alto)

{ medio=(bajo+ alto) / 2 ; if((cond==strcmp(pal, t[medio].ingl)) < 0) alto=medio-1 ; else if(cond> 0) bajo = medio + 1 ; else return (medio) ; } return(-1) ; }

8.1.5. Apuntadores a estructuras

Al declarar una estructura se le asocia un bloque de memoria. La direccin inicial del bloque puede asignarse a un apuntador, por lo que la estructura puede manejarse a travs de ste. Un apuntador a una estructura se declara de la misma forma en que se declara cualquier apuntador. Para evaluar el contenido de los datos miembros de la direccin de memoria asignada al puntero, es necesario un nuevo operador (->), usado de la forma:

puntero_estructura->dato_miembro;

Por ejemplo, si usamos el tipo dicc definido anteriormente, podemos escribir la lnea:

dicc *apd ;

que declara a apd como un apuntador a objetos de tipo dicc. En este momento, se puede declarar una variable dinmica utilizando el apuntador apd, como se muestra a continuacin:

apd = new dicc;

El acceso a los elementos de la estructura apuntada por apd se logra a travs:

apd->ingl; apd->espa;

En el listado siguiente se muestra el manejo de una lista del tipo de estructura alumnos.

#include <iostream.h> #include <conio.h> void inserta(), elimina(), despliega(); // Define a alumno como un tipo de estructura struct alumno { char nombre[25]; int calif; struct alumno *sig; }; alumno *primero, *actual; void main() { char opcion; primero = actual = NULL ; do { clrscr(); cout << "LISTA :"<<endl; cout << "1.- Ingresar alumno"<<endl; cout << "2.- Mostrar lista alumnos"<<endl; cout << "0.- Salir"<<endl; cout << "Escriba el nmero de su opcin : "; opcion=getche(); switch(opcion) { case '1' : inserta(); break; case '2' : despliega(); break; } } while(opcion !='0'); }

void inserta() { alumno *nuevo; nuevo = new alumno; if(!nuevo) { cout << No hay memoria<<endl; getch(); } else { cout << "Ingrese alumno: "<<endl; cout << "Nombre: "; gets(nuevo->nombre); cout << "Calificacion:"; cin>> nuevo->calif; if(!primero) { nuevo->sig = primero; primero->sig = nuevo; actual = nuevo; } else { nuevo->sig = actual->sig; actual->sig = nuevo ; } } void despliega() { actual=primero; clrscr(); cout<<Listado de estudiantes:<<endl; if(!actual) cout << Lista vacia<<endl; while(actual) { cout << actual->nombre<< " " << actual->calif<<endl; actual = actual->sig; } getch(); }

8.2.

Uniones

Los tipos union comparten muchas de las caractersticas sintcticas y funcionales de los tipos struct, sin embargo existen algunas diferencias; la principal es que la union permite que solamente uno de sus miembros est activo a la vez, mientras que en la estructura todos los miembros estn activos al mismo tiempo. Otra

diferencia es que el tamao de la union es el tamao del miembro ms grande, mientras que en la estructura su tamao es la suma de los tamaos de sus miembros. Las uniones son recomendables cuando se van a manejar variables que pueden compartir espacio en la memoria, debido a que sus valores van a requerirse en momentos diferentes. Por ejemplo, sean tres variables: una de tipo int, otra de tipo float y otra de tipo double. Si no van a manejarse simultneamente, puede definirse un nuevo tipo union que las abarque de la forma:

union nums { int x ; // 2 bytes float y ; // 4 bytes double z ; // 8 bytes }; En este momento se cuenta con un nuevo tipo llamado nums, as que podemos utilizarlo para efectuar la siguiente declaracin:

nums varnums ;

// Se declara la variable varnums // que ocupa 8 bytes de memoria.

Se pueden accesar los miembros de varnums a travs del operador punto, por ejemplo:

varnums.x = 10 ; // Se asigna el valor 10 al miembro // x de la union varnums.

8.3.

Clases y objetos

8.3.1. Definicin de una clase

Una clase es muy parecido a una estructura, ya que la misma es una estructura de tipo especial que permite representar caractersticas reales de los objetos o cosas, que no podemos realizar con las estructura, dando una perspectiva real en un programa. Una clase representa al conjunto de objetos que comparten una estructura y comportamientos comunes. Una clase es un tipo definido por el usuario que describe los atributos y mtodos de los objetos que se crearan a partir de la misma. Los atributos definen el estado de un determinado objeto y los mtodos son las operaciones que definen su comportamiento. La definicin de una clase consta de dos partes: el nombre de la clase precedido por la palabra reservada class, y el cuerpo de la clase encerrado entre llaves y seguido de un punto y coma. Esto es:

class nombre_clase { cuerpo_de_la_clase };

El cuerpo de la clase en general consta de modificadores de acceso (public, protected y private), atributos, mensajes y mtodos. Un mtodo implcitamente define un mensaje (el nombre del mtodo es el mensaje). Un ejemplo de la definicin de una clase, seria la clase punto que puede tomar la siguiente forma:

class punto { prvate: //acceso privado de los datos miembros int x,y ; // Miembros Datos o Atributos public: //acceso publico de los metodos void fun() { return y; } // Funciones Miembros o Metodos };

8.3.1.1.

Atributos.

Son componentes de un objeto que almacenan datos. Tambin se les denomina variables miembro. Estos datos pueden ser de tipo primitivo (int, double, char...) o, a su vez, de otro tipo de objeto (lo que se denomina agregacin o composicin de objetos). La idea es que un atributo representa una propiedad determinada de un objeto. Un atributo es lo mismo que una variable cualquiera, salvo que como los atributos se declaran para pertenecer a una clase especfica, se dice que todos los atributos de dicha clase son miembros de la misma. La declaracin de los atributos es exactamente igual que declarar cualquier otra variable. Aunque con la diferencia de que estos se les adiciona el tipo de acceso, lo cual pueden ser manejados como variables comunes (public) o mediante el uso de mtodos para el caso de las privadas (prvate).

Ejemplo de la clase punto podemos representarlo como un conjunto de datos miembros o atributos visibles y no visibles como lo son x, y, color.

class punto { public: //acceso pblico de los mtodos char color[25]; prvate: //acceso privado de los datos miembros int x,y ; // Miembros Datos o Atributos privados public: //acceso pblico de los mtodos

void fun() { return y; } // Funciones Miembros o Mtodos }; En el ejemplo color representa un dato miembro del objeto que es visible de manera externa, es decir puede ser usada de la forma tradicional. A diferencia de los datos miembro x y y los cuales no podrn ser visibles de forma externa lo cual implicara que no existe para las funciones y deben ser manejadas a travs del uso de funciones miembros o mtodos de la clase.

8.3.1.2.

Mtodos.

Son un componente de un objeto que lleva a cabo una determinada accin o tarea con los atributos. En comparacin con la programacin tradicional, un mtodo es lo mismo que una funcin cualquiera, salvo que como los mtodos se declaran para pertenecer a una clase especfica, se dice que todos los mtodos de dicha clase son miembros de la misma. Por lo dems, la declaracin y definicin de los mtodos es exactamente igual que declarar y definir cualquier otra funcin. Las funciones miembro o mtodos se incluyen en la definicin de una clase, de dos formas: Al definir el mtodo dentro de la definicin de la clase. Por ejemplo:

class punto { int x,y ; public: int dax() { return x ; } // Define el mtodo dentro de la clase };

Declarar el metodo dentro de la definicin de la clase y escribir la definicin de la funcin fuera de la definicin de la clase. Por ejemplo:

class punto { int x,y ; public: int dax() ; // Declaracin del mtodo dentro de la clase }; int punto::dax() // Definicin del mtodo fuera de la clase { return x ; } En la lnea de cabecera de la definicin de la funcin miembro dax() se utiliza el llamado operador de resolucin de mbito (::). Este operador indica que la funcin dax() es una funcin miembro de la clase punto. Varias clases diferentes pueden usar los mismos nombres de funcin. El compilador sabe cul funcin pertenece a cul clase y esto es posible por el operador de resolucin de mbito y el nombre de la clase.

8.3.1.3.

Tipos de acceso.

Una de las caractersticas fundamentales de una clase es ocultar tanta informacin como sea posible. Por consiguiente, es necesario imponer ciertas restricciones en el modo en que se puede manipular una clase y de cmo se puede utilizar los datos y el cdigo dentro de una clase. Las funciones miembros o dato miembro de una clase slo pueden ser llamadas relativas a un objeto especfico. Para llamar a una funcin miembro o dato miembro visible desde alguna parte del programa que se encuentre fuera de la clase, se debe usar el nombre del objeto y el operador de direccionamiento (.) punto.

//Para acceder a un atributo visible de la clase Nombre_objeto.nombre_atributo; //Para acceder a un mtodo visible de la clase Nombre_objeto.nombre_metodo(parmetro_del_metodo); Ejemplo:

#include <iostream.h> // Esto define la clase CRender class CRender { public: char buffer[256]; void m_Renderizar(const char *cadena); }; // implementar m_Renderizar() para la clase void CRender::m_Renderizar(const char *cadena) { strcpy(buffer, cadena); //copia la cadena } void main () { CRender render1, render2; // crear 2 objetos clase render1.m_Renderizar("Inicializando el objeto render1"); render2.m_Renderizar("Inicializando el objeto render2"); cout << "buffer en render1: "; cout << render1.buffer << endl; // tenemos acceso a buffer es pblico cout << "buffer en render2: "; cout << render2.buffer << endl; } Por visibilidad se entiende al acto de acceder a los miembros de una clase. En este sentido, los miembros de una clase pueden ser: pblicos, privados y protegidos. Un miembro pblico significa que el acceso al mismo puede darse dentro del interior de la clase, dentro de una subclase, y desde un objeto instanciado de cualquiera de estas. Por ejemplo, los miembros de la clase CRender son accesibles dentro de la misma y podrn accederse desde cualquier otra clase que se derive de CRender, as como desde cualquier objeto instanciado de estas.

Un miembro privado significa que el acceso al mismo puede darse solamente dentro del interior de la clase que lo posee. Normalmente, el programador creador de una clase declara a los atributos de la clase como privados y a los mtodos como pblicos, esto con la idea de que el usuario de la clase no pueda tener acceso a los atributos sino es a travs de los mtodos definidos para el caso. Un miembro protegido se comporta de manera parecida a un miembro privado, salvo que estos son accesibles dentro de la clase que lo posee y desde las clases derivadas, pero no desde los objetos instanciados a raz de dichas clases. Por defecto al crear miembros de una clase (atributos o mtodos) si no se les indica el tipo de accesibilidad por defecto, sern privados. Son necesarios mtodos pblicos para poder acceder a las variables o mtodos que no sean pblicos.

class Par {

// atributos por defecto privados double a, b; public: // mtodos de visibilidad publica double exta() { return a; } double extb() { return b; }

};

8.3.2. Definicin de Objetos

Un objeto representa alguna entidad de la vida real, es decir, alguno de los objetos que pertenecen a una clasificacin con los que podemos interactuar. A travs del estudio de ellos se adquiere el conocimiento necesario para, mediante la abstraccin y la generalizacin, agruparlos segn sus caractersticas en conjuntos, estos conjuntos determinan las clases de objetos a utilizar. Primero existen los objetos, luego aparecen las clases en funcin de la solucin que estemos buscando. sta es la forma ms comn de adquirir conocimiento aunque no es la nica. En ocasiones el proceso puede ser a la inversa y comenzar el anlisis en una base terica

abstracta, sustentada por el conocimiento previo que da lugar primeramente a clases de objetos que satisfagan las necesidades de la solucin. Los objetos tienen caractersticas fundamentales que nos permiten conocerlos mediante la observacin, identificacin y el estudio posterior de su comportamiento; estas caractersticas son: Identidad. Es la propiedad que permite a un objeto diferenciarse de otros. Comportamiento. El comportamiento de un objeto est directamente relacionado con su funcionalidad y determina las operaciones que este puede realizar o a las que puede responder ante mensajes enviados por otros objetos. Estado. El estado de un objeto se refiere al conjunto de los valores de sus atributos en un instante de tiempo dado.

Se define a un objeto como la instancia de una clase. Una instancia es un elemento tangible (ocupa memoria durante la ejecucin del programa) generado a partir de una definicin de clase. Todos los objetos empleados en un programa han de pertenecer a una clase determinada. De la forma:

class Tipo_clase { };

//atributos //mtodos

Tipo_clase nombre_objeto_Tipo_clase; Ejemplo:

class punto { int x,y ; public: int extx(){ return x ; } int exty(){ return y ; } void asigx() { x = a; }

void asigy() { y = b; } void mostrar(){ cout<<( <<x<< , <<y<< ) ; } }; void main() { punto a; //Objeto a del tipo punto a.asigx(10); a.asigy(15); a.mostrar(); } Salida:

( 10 , 15 )

CAPITULO 9
PASO DE MENSAJES: MTODOS, PASO DE PARMETROS

9.1.

Control de acceso a los miembros de una clase.

El control de acceso se suele llamar tambin ocultacin de la implementacin. Incluir funciones dentro de las estructuras (a menudo llamado encapsulacin) produce tipos de dato con caractersticas y comportamiento, pero el control de acceso pone fronteras en esos tipos. Una clase puede contener partes pblicas y partes privadas. Por defecto, todos los miembros definidos en la clase son privados. Para hacer las partes de una clase pblicas (esto es, accesible desde cualquier parte de su programa) deben declararse despus de la palabra reservada public. Todas las variables o funciones definidas despus de public son accesibles a las restantes funciones del programa. Especialmente, el resto de su programa accede a un objeto a travs de sus funciones y datos pblicos. Dado que una caracterstica clave de la POO es la ocultacin de datos, debe tener presente que aunque puede tener variables pblicas, desde un punto de vista conceptual debe tratar de limitar o eliminar su uso. En su lugar, debe hacer todos los datos privados y controlar el acceso a ellos, a travs de funciones pblicas. El mecanismo para hacer privados datos o funciones es anteponerle la palabra reservada private. Por defecto, una clase es privada, aunque es conveniente especificar la visibilidad expresamente, por legibilidad y por compatibilidad con versiones posteriores que pueden recomendar su uso obligatorio. (Figura 9.1) Existen tres clases de usuarios de una clase:

La propia clase Usuarios genricos Clases derivadas

Cada usuario tiene diferentes privilegios o niveles de acceso. Cada nivel de privilegio de acceso se asocia con una palabra reservada: private. Por defecto todo lo declarado dentro de una clase es privado (private), y slo se puede acceder a ella con las funciones miembros declaradas en el interior de la clase, public. Los miembros que se declaran en la regin pblica (public) se puede acceder a travs de cualquier objeto de la clase de igual modo que se accede a los miembros de una estructura. Protected. Los miembros que se declaran en la regin protegida (protected) slo se pueden acceder por funciones miembros declaradas dentro de la clase, por funciones miembro de clases derivadas de esta clase.

Figura 9. 1. Visibilidad de una clase.

Ejemplo de visibilidad de miembros de una clase:

class punto { int x, y ;

public: int color; void asigx() { x = a; } void asigy() { y = b; } void mostrar2(){ cout<<( <<x<< , <<y<< ) ; } private: void mostrar(){ mostrar2(); } }; void main() { punto a; a.color = 1; a.x = 20; a.asigx(10);

//Objeto a del tipo punto //asignacin del atributo publico //ERROR!!! atributo x de a no es visible //asignacin del atributo x de a // usando un mtodo publico a.mostrar2(); //ERROR!!! mtodo privado de no visible a.mostrar(); //llamada al mtodo privado a travs de uno publico

} Es necesaria la existencia de un mtodo pblico para acceder a atributos y mtodos privados.

9.2.

Mtodos de una clase.

Un mtodo como ya ha visto es una funcin miembro la cual cumple un propsito especifico al igual como una funcin, solo que esta es parte de la clase con el propsito adicional de poder interactuar con los atributos de la clase. Para declarar un mtodo su estructura general consta de dos partes, la declaracin y el cuerpo del mtodo.

Declaracion_ del_ mtodo { Cuerpo_del_metodo }; La Declaracion_del_metodo proporciona informacin sobre su nombre, la accesibilidad del mtodo, el nmero de parmetros que recibe, etc.

El Cuerpo_del_metodo contiene el conjunto de sentencias que manipula los datos de cada objeto.

9.2.1. Pasos de mensajes.

Los mtodos de una clase constituyen la lgica de la clase, es decir, contienen el cdigo que manipula el estado del objeto. Constituyen el mecanismo utilizado para implementar los mensajes entre objetos. Quiere decir, cuando un objeto se comunica con otro por un mensaje lo hace por medio de la invocacin al mtodo correspondiente del objeto. Un paso de mensaje no es ms que el mecanismo de invocara un mtodo por medio de las referencias de la siguiente forma:

referencia.metodo (parametros);

Existen diversos tipos de paso de mensaje segn sea la definicin de sus prototipos y que parmetros recibe.

9.2.1.1.

Paso de Parmetros.

Son los valores paramtricos que se enva a un mtodo en el momento de su invocacin. Estos permiten diferenciar prototipos o funciones que cumplen un mismo propsito pero con la diferencia de los datos enviados en el momento de su invocacin son de tipos diferentes y/o con uno o ms parmetros.

//sin parmetros o defecto referencia.metodo (); //por parmetros referencia.metodo (parmetro_tipo1);

referencia.metodo (parmetro_tipo2); referencia.metodo (parametro1, parametro2,..,parametron);

Al declara mtodos de una clase con un mismo nombre, se diferenciaran los mtodos por los parmetros que recibe. Segn sean sus parmetros los mtodos pueden ser mtodos por defecto aquellos que no reciben datos y mtodos paramtricos los que reciben datos adicionales para su funcionalidad.

9.2.1.2.

El puntero this.

En uno de los puntos anteriores comentbamos que un mtodo perteneciente a una clase tena acceso a los miembros de su propia clase sin necesidad de pasar como parmetro el objeto con el que se estaba trabajando. Esto no es tan sencillo, puesto que es lgico pensar que los atributos (datos) contenidos en la clase son diferentes para cada objeto de la clase, es decir, se reserva memoria para los miembros de datos, pero no es lgico que cada objeto ocupe memoria con una copia de los mtodos, ya que replicaramos mucho cdigo. En realidad, los objetos de una clase tienen un atributo especfico asociado, su direccin. La direccin del objeto nos permitir saber que variables debemos modificar cuando accedemos a un miembro de datos. Esta direccin se pasa como parmetro (implcito) a todas las funciones miembro de la clase y se llama this. Si en alguna funcin miembro queremos utilizar nuestra propia direccin podemos utilizar el puntero como si lo hubiramos recibido como parmetro. Por ejemplo, para retornar el valor de un atributo escribimos:

float empleado::cuanto_cobra () { return sueldo; }

Pero tambin podramos haber hecho lo siguiente:

float empleado::cuanto_cobra () { return this->sueldo; } Utilizar el puntero dentro de una clase suele ser redundante, aunque a veces es til cuando trabajamos con punteros directamente.

9.2.2. Mtodos sobrecargados.

Cada mtodo tiene una forma, que son su nombre, el tipo y nmero de sus parmetros. Existe una caracterstica para tener dos mtodos con el mismo nombre. Esta caracterstica se denomina sobrecarga de mtodos. El concepto de sobrecarga de mtodos se puede aplicar siempre que los parmetros sean diferentes, bien por su tipo, bien porque el nmero de parmetros de un mtodo u otro es diferente. De la forma:

class Nom_clase{ void nom_metodo() { } void nom_metodo( tipoa parametrox) { } void nom_metodo(tipob parametroy) { } void nom_metodo(tipo parmetro1, tipo parametro2) { } . }; Ejempl:

class Articulo { private: float precio; public: void setPrecio() { precio = 3.50;

} void setPrecio(float newPrecio) { precio = nuevoPrecio; } };

Entonces cuando hacemos un llamado a este mtodo, el compilador hace referencia al tipo de parmetro. La sobrecarga seria redefinir cualquiera de estos mtodos utilizando los mismos parmetros pero para un proceso distinto.

9.2.3. Constructores y destructores.

Los constructores y los destructores son un tipo de sobrecarga de funciones miembros especiales. Podemos clasificar los objetos en cuatro tipos diferentes segn la forma en que se crean: Objetos automticos: son los que se crean al encontrar la declaracin del objeto y se destruyen al salir del mbito en que se declaran. Objetos estticos: se crean al empezar la ejecucin del programa y se destruyen al terminar la ejecucin. Objetos dinmicos: son los que se crean empleando el operador new y se destruyen con el operador delete. Objetos miembro: se crean como miembros de otra clase o como un elemento de un arreglo. Los objetos que se crean con el uso explcito del constructor son objetos automticos.

9.2.3.1.

Constructores

Un constructor especifica la manera en que ser creado e inicializado un nuevo objeto de cierta clase. Los constructores en C++ pueden ser definidos por el usuario generados por el lenguaje. El compilador de C++ invoca automticamente al constructor apropiado cada vez que se defina un nuevo objeto. Esto puede ocurrir en una declaracin de datos, cuando se copia un objeto o a travs de la asignacin dinmica de memoria a un nuevo objeto por medio del operador new. Los constructores se pueden considerar como funciones de inicializacin, y como tales pueden tomar cualquier tipo de parmetros, incluso por defecto. Los constructores se pueden sobrecargar, por lo que podemos tener muchos constructores para una misma clase (como ya sabemos, cada constructor debe tomar parmetros distintos). Existe un constructor especial que podemos definir o no definir que tiene una funcin muy especfica: copiar atributos entre objetos de una misma clase. Si no lo definimos se usa uno por defecto que copia todos los atributos de los objetos, pero si lo definimos se usa el nuestro. Este constructor se usa cuando inicializamos un objeto por asignacin de otro objeto. Podemos definir un constructor por defecto de la forma:

class NomClase {

NombClase() // Constructor por defecto { // inicializaciones de atributos }

}; Podemos definir un constructor por argumento paramtricos de la forma:

class NomClase { NombClase(tipo parametrico)// Constructor por parmetros { // inicializaciones por parametros

} }; Para aadir un constructor a la clase punto escribimos:

class punto { int x,y ; public: int dax() { return x ; } int day() { return y ; } punto() // constructor por defecto { x=0; y=0; } punto(int nx, int ny) // constructor por parmetro { x = nx ; y = ny ; } }; En el momento de instanciar o crear un objeto se hace llamado al constructor inicializando al objeto. De la forma:

void main() { punto a; //Inicializacin punto a constructor por defecto punto b(10,10); //Inicializacin punto b con constructor por parmetro }

9.2.3.2.

Destructores

Los destructores destruyen a los objetos creados, liberando la memoria asignada. Pueden ser invocados explcitamente por medio del operador delete.

Podemos definir un destructor mediante el operador (~) de la forma:

usando la negacin implcita del constructor

class NomClase {

~NombClase() // destructor { }

}; Siguiendo con el ejemplo de la clase punto:

class punto { int x,y ; public: int dax() { return x ; } int day() { return y ; } punto(int nx, int nx) ; ~punto() ; // Declaracion del Destructor }; punto::punto(int nx, int nx) { x = nx ; y = ny ; } punto::~punto() // Definicion del Destructor { delete x ; delete y ; }

9.2.4. Mtodos estticos y funciones amigas

Dentro de las peculiaridades de las clases encontramos dos tipos de funciones especiales: los mtodos estticos y las funciones amigas. Los comentamos separados del bloque relativo a clases y miembros por su similitud y por la importancia de las funciones amigas en la sobrecarga de operadores. Su caracterstica comn es que no poseen parmetro implcito this.

9.2.4.1.

Mtodos estticos

Al igual que los atributos estticos mencionados en el punto anterior, las funciones miembro estticas son globales para los miembros de la clase y deben ser definidas fuera del mbito de la declaracin de la clase. Estos mtodos son siempre pblicos, se declaren donde se declaren. Al no tener parmetro this no pueden acceder a los miembros no estticos de la clase (al menos directamente, ya que se le podra pasar un puntero al objeto para que modificara lo que fuera).

9.2.4.2.

Funciones amigas (friend)

Son funciones que tienen acceso a los miembros privados de una clase sin ser miembros de la misma. Se emplean para evitar la ineficiencia que supone el tener que acceder a los miembros privados de una clase a travs de mtodos. Como son funciones independientes de la clase no tienen parmetro this, por lo que el acceso a objetos de una clase se consigue pasndoles como parmetro una referencia al objeto (una referencia como tipo implica pasar el objeto sin copiar, aunque se trata como si fuera el objeto y no un puntero), un puntero o el mismo objeto. Por la misma razn, no tienen limitacin de acceso, ya que se definen fuera de la clase. Para hacer amiga de una clase a una funcin debemos declararla dentro de la declaracin de la clase precedida de la palabra friend, como se muestra en el siguiente cdigo:

class X { private: int i; ... friend int f(X&, int);

// funcin amiga que toma como parmetros una referencia a // un objeto del tipo X y un entero y retorna un entero }; En la definicin de la funcin (que se hace fuera de la clase como las funciones normales) podremos usar y modificar los miembros privados de la clase amiga sin ningn problema:

int f(X& objeto, int i) {

int j = objeto.i; objeto.i = i; return j;

Es importante ver que aunque las funciones amigas no pertenecen a la clase se declaran explcitamente en la misma, por lo que forman parte de la interface de la clase. Una funcin miembro de una clase puede ser amiga de otra:

class X {

... void f(); ...

}; class Y { }; ... friend void X::f();

Si queremos que todas las funciones de una clase sean amigas de una clase podemos poner:

class X { friend class Y;

... }; En el ejemplo todas las funciones de la clase Y son amigas de la clase X, es decir, todos los mtodos de Y tienen acceso a los miembros privados de X.

9.3.

Asignacin de objetos

La forma de inicializar un objeto es mediante el uso del operador de asignacin (=). Por ejemplo:

class punto {

int x,y ; public: int dax() { return x ; } int day() { return y ; } punto() { x = 0 ; y=0; } punto(int nx, int ny) { x = nx ;

y = ny ; }

}; void main() { punto a, b(10,10); a = b; } Cuando se realiza la operacin asignacin, ambos objetos existen. En C++ el operador de asignacin, por omisin de la clase seria:

punto& punto::operator=(const punto& pun) { x = pun.x; y = pun.y; return *this; } 9.4. Ejemplo de Programa usando clases

Programa que suma nmeros complejos:

#include <iostream.h> class NumComp { private: double real; double comp; public: NumComp(); NumComp(double); NumComp(double, double); NumComp* suma(NumComp&); double getReal(); double getComp(); }; NumComp::NumComp() { real = 0; comp = 0; } NumComp::NumComp(double real) { this->real = real; comp = 0; } NumComp::NumComp(double real, double comp) { this->real = real; this->comp = comp; } NumComp* NumComp::suma(NumComp& otro) { return new NumComp(this->real + otro.real, this->comp + otro.comp); } double NumComp::getReal() { return this->real; } double NumComp::getComp() { return this->comp; } void main() { NumComp a(23, 1); NumComp b(-1, 5); NumComp* c = a.suma(b);

cout << "La suma es: " << c->getReal() << "+" << c>getComp() << "i" << endl; delete c; }

CAPITULO 10
HERENCIA

10.1. Herencia.

La herencia es una propiedad esencial de la Programacin Orientada a Objetos que consiste en la creacin de nuevas clases a partir de otras ya existentes. Este trmino ha sido tomado prestado de la herencia biolgica, donde un hijo ciertas facetas fsicas o del comportamiento de sus progenitores. La herencia en C++ es un mecanismo de abstraccin creado para poder facilitar y mejorar el diseo de las clases de un programa. Con ella se pueden crear nuevas clases a partir de clases ya hechas, siempre y cuando tengan un tipo de relacin especial. Las clases que heredan de clases base se denominan derivadas, estas a su vez pueden ser clases bases para otras clases derivadas. Se establece as una clasificacin jerrquica. La herencia es una forma de reutilizacin del software, en la cual se crean clases nuevas a partir de clases existentes, mediante la absorcin de sus atributos y comportamientos, y enriqueciendo stos con las capacidades que las clases nuevas requieren.

10.2. Jerarqua de clases.

Cada nueva clase obtenida mediante herencia se conoce como clase derivada, y las clases a partir de las cuales se deriva, clases base. Adems, cada clase derivada puede usarse como clase base para obtener una nueva clase derivada. Y cada clase

derivada puede serlo de una o ms clases base. En este ltimo caso hablaremos de derivacin mltiple. Esto nos permite crear una jerarqua de clases tan compleja como sea necesario. Ese es el principio de la programacin orientada a objetos. Esta propiedad nos permite encapsular diferentes partes de cualquier objeto real o imaginario, y vincularlo con objetos ms elaborados del mismo tipo bsico, que heredarn todas sus caractersticas. Lo veremos mejor con un ejemplo. Un ejemplo muy socorrido es de las personas. Supongamos que nuestra clase base para clasificar a las personas en funcin de su profesin sea "Persona". Presta especial atencin a la palabra "clasificar", es el punto de partida para buscar la solucin de cualquier problema que se pretenda resolver usando POO. Lo primero que debemos hacer es buscar categoras, propiedades comunes y distintas que nos permitan clasificar los objetos, y crear lo que despus sern las clases de nuestro programa. Es muy importante dedicar el tiempo y atencin necesarios a esta tarea, de ello depender la flexibilidad, reutilizacin y eficacia de nuestro programa. Ten en cuenta que las jerarquas de clases se usan especialmente en la resolucin de problemas complejos, es difcil que tengas que recurrir a ellas para resolver problemas sencillos. Siguiendo con el ejemplo, partiremos de la clase "Persona". (Figura 10.1) Independientemente de la profesin, todas las personas tienen propiedades comunes, nombre, fecha de nacimiento, gnero, estado civil, etc.

Figura 10. 1. Jerarqua de clases para Persona

La siguiente clasificacin debe ser menos general, supongamos que dividimos a todas las personas en dos grandes clases: empleados y estudiantes. Lo importante es decidir qu propiedades que no hemos incluido en la clase "Persona" son exclusivas de los empleados y de los estudiantes. Por ejemplo, los ingresos por nmina son exclusivos de los empleados, la nota media del curso, es exclusiva de los estudiantes. Una vez hecho eso crearemos dos clases derivadas de Persona: "Empleado" y "Estudiante". Haremos una nueva clasificacin, ahora de los empleados. Podemos clasificar a los empleados en ejecutivos y comerciales. De nuevo estableceremos propiedades exclusivas de cada clase y crearemos dos nuevas clases derivadas de "Empleado": "Ejecutivo" y "Comercial". Ahora veremos las ventajas de disponer de una jerarqua completa de clases. Cada vez que creemos un objeto de cualquier tipo derivado, por ejemplo de tipo Comercial, estaremos creando en un slo objeto un Comercial, un Empleado y una Persona. Nuestro programa puede tratar a ese objeto como si fuera cualquiera de esos tres tipos. Es decir, nuestro comercial tendr, adems de sus propiedades, como comercial tambien, su nmina como empleado, y su nombre, edad y gnero como persona. Siempre podremos crear nuevas clases para resolver nuevas situaciones. Consideremos el caso de que en nuestra clasificacin queremos incluir una nueva

clase "Becario", que no es un empleado, ni tampoco un estudiante; la derivaramos de Persona. Tambin podemos considerar que un becario es ambas cosas. Sera un ejemplo de derivacin mltiple, podramos hacer que la clase derivada Becario, lo fuera de Empleado y Estudiante. Podemos aplicar procedimientos genricos a una clase en concreto, por ejemplo, podemos aplicar una subida general del salario a todos los empleados, independientemente de su profesin, si hemos diseado un procedimiento en la clase Empleado para ello.

10.3. Clases bases y derivadas.

Las clases creadas pueden ser reutilizadas en nuevos programas donde sus definiciones requieran las mismas funcionalidades. Una clase utilizada para derivar nuevas clases se denomina clase base (padre, superclase o ascendiente). Una clase creada de otra clase, donde permita utilizar las funciones necesarias de la clase (clase base) se denomina clase derivada o subclase. La terminologa supone una clase base o clase padre, y una clase derivada o clase hija. Esta relacin supone un orden de jerarqua simple. A su vez, una clase derivada puede ser utilizada como una clase base para derivar ms clases. Por consiguiente se puede construir jerarquas de clases, en las que cada clase sirve como padre o raz de una nueva clase. Las clases nuevas se denominan clases derivadas, en donde cada clase derivada se convierte en candidata a clase base para alguna clase futura. Cada clase derivada se debe referir a una clase base declarada anteriormente. La declaracin de una clase derivada tiene la siguiente sintaxis:

Class clase_derivada: <especificadores_de_acceso> clase_base { ... };

El operador (:) nos indica que se herede .Los especificadores de acceso pueden ser: public, protected o private.

10.3.1. Clases de derivacin

Los especificadores de acceso a las clases base definen los posibles tipos de derivacin: public, protected y private. El tipo de acceso a la clase base especfica cmo recibir la clase derivada a los miembros de la clase base. Si no se especifica un acceso a la clase base, C++ supone que su tipo de herencia es privado. Derivacin pblica (public). Todos los miembros public y protected de la clase base son accesibles en la clase derivada, mientras que los miembros private de la clase base son siempre inaccesibles en la clase derivada.

#include <iostream.h> class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void mostrar() { cout << i << " " << j << "\n"; } }; class derivada : public base { int k; public: derivada(int x) { k = x; } void mostrar_k() { cout << k << "\n"; }

}; void main() { derivada obj(3); obj.set(1, 2); // accesar a miembro de base obj.mostrar(); // accesar a miembro de base obj.mostrar_k(); // usa miembro de la clase derivada };

Derivacin privada (private). Todos los miembros de la clase base se comportan como miembros privados de la clase derivada. Esto significa que los miembros public y protected de la clase base no son accesibles ms que por las funciones miembro de la clase derivada. Los miembros privados de la clase siguen siendo inaccesibles desde la clase derivada.

#include <iostream.h> class base { int i, j; public: void set(int a, int b) { i = a; j = b; } void mostrar() { cout << i << " " << j << "\n"; } }; // Miembros pblicos de 'base' son privados en 'derivada' class derivada : privatec base { int k; public: derivada(int x) { k = x; } void mostrar_k() { cout << k << "\n"; } }; void main() { derivada obj(3); obj.set(1, 2); // Error!!!, no se puede acceder a set() obj.mostrar(); // Error!!!, no se puede acceder a set() obj.mostrar_k(); // usa miembro de la clase derivada }; Derivacin protegida (protected). Todos los miembros public y protected de la clase base se comportan como miembros protected de la clase derivada. Estos miembros no son, pues, accesibles al programa exterior, pero las clases que se deriven a continuacin podrn acceder normalmente a estos miembros (datos o funciones).

Usando miembros protegidos:

#include <iostream.h> class base { protected: int i, j; // privados base, pero accesibles a derivada public: void set(int a, int b) { i = a; j = b; } void mostrar() { cout << i << " " << j << "\n"; } }; class derivada : public base { int k; public: // derivada puede accesar en base a 'j' e 'i' void set_k() { k = i * j; } void mostrar_k() { cout << k << "\n"; }

}; void main() { derivada obj(3); obj.set(1, 2); // Ok, conocido por derivada obj.mostrar(); // Ok, conocido por derivada obj.set_k(); obj.mostrar_k(); }; Usando protected para clase base:

#include <iostream.h> class base { int i; protected: int j; public: int k; void seti(int a) { i = a; } int geti() { return i; } }; // Heredar 'base' como protected. class derivada : protected base { public: void setj(int a) { j = a; }; // j es protected aqui. void setk(int a) // k es tambien protected. { k = a; };

int getj() { return j; } int getk() { return k; } }; void main() { derivada obj; /* La proxima linea es ilegal porque seti() es un miembro protegido de derivada, lo cual lo hace inaccesible fuera de derivada. */ // obj.seti(10); // cout << obj.geti(); // ilegal -- geti() es protected. // obj.k = 10; // tambien ilegal porque k es protected. // estas declaraciones son correctas obj.setk(10); cout << obj.getk() << " "; obj.setj(12); cout << obj.getj() << " "; }

10.4. Tipos de herencia.

En C++ existen los tipos de herencia: simple y mltiple.

10.4.1. Herencia simple

La herencia simple es aquella en la que cada clase derivada hereda de una nica clase. Cada clase tiene un solo ascendiente, y puede tener muchos descendientes. En la herencia, las clases derivadas "heredan" los datos y las funciones miembro de las clases base, pudiendo las clases derivadas redefinir estos comportamientos y aadir comportamientos nuevos propios de las clases derivadas. Para no romper el principio de encapsulamiento (ocultar datos cuyo conocimiento no

es necesario para el uso de las clases), se proporciona un nuevo modo de visibilidad de los datos/funciones: "protected". Cualquier cosa que tenga visibilidad protected se comportar como pblica en la clase Base y en las que componen la jerarqua de herencia, y como privada en las clases que no sean de la jerarqua de la herencia. Antes de utilizar la herencia, nos tenemos que hacer una pregunta, y si tiene sentido, podemos intentar usar esta jerarqua: Si la frase <claseB> ES-UN <claseA> tiene sentido, entonces estamos ante un posible caso de herencia donde clase A ser la clase base y clase B la derivada. Ejemplo: clases Barco, Acorazado, Carguero, etc. un Acorazado ES-UN Barco, un Carguero ES-UN Barco, un Trasatlntico ES-UN Barco, etc. En este ejemplo tendramos las cosas generales de un Barco (en C++).

class Barco { protected: char *nombre; float peso; public: //Constructores y dems funciones bsicas de barco }; y ahora las caractersticas de las clases derivadas, podran (a la vez que heredan las de barco) aadir cosas propias del subtipo de barco que vamos a crear, por ejemplo:

class Carguero: public Barco { private: float carga; //El resto de cosas }; class Acorazado: public Barco { private: int numeroArmas;

int Soldados; // El resto de cosas };

Como vimos existen 3 clases de derivacin o herencia que se diferencian en el modo de manejar la visibilidad de los componentes de la clase resultante: Herencia publica (class Derivada: public Base ): Con este tipo de herencia se respetan los comportamientos originales de las visibilidades de la clase Base en la clase Derivada. Herencia privada (clase Derivada: private Base): Con este tipo de herencia todo componente de la clase Base, ser privado en la clase Derivada (las propiedades heredadas sern privadas aunque estas sean pblicas en la clase Base) Herencia protegida (clase Derivada: protected Base): Con este tipo de herencia, todo componente publico y protegido de la clase Base, ser protegido en la clase Derivada, y los componentes privados, siguen siendo privados.

10.4.2. Herencia mltiple.

La herencia mltiple es aquella en la cual una clase derivada tiene ms de una clase base. La herencia mltiple es el mecanismo que permite al programador hacer clases derivadas a partir, no de una sola clase base, sino de varias. Para entender esto mejor, pongamos un ejemplo: Cuando ves a quien te atiende en una tienda, como persona que es, podrs suponer que puede hablar, comer, andar, pero, por otro lado, como empleado que es, tambin podrs suponer que tiene un jefe, que puede cobrarte dinero por la compra, que puede devolverte el cambio, etc. Si esto lo trasladamos a la programacin sera herencia mltiple (clase empleado_tienda):

class Persona { ... Hablar(); Caminar(); ... }; class Empleado { Persona jefe; int sueldo; Cobrar(); ... }; class empleado_tienda: public Persona, Empleado { ... AlmacenarStock(); ComprobarExistencias(); ... }; Por tanto, es posible utilizar ms de una clase para que otra herede sus caractersticas.

class clase_derivada: <especificadores_de_acceso1> clase_base1, <especificadores_de_acceso2> clase_base2, , <especificadores_de_acceson> clase_basen { ... }; Una declaracin multiple seria la clase derivada D:

class B { ... }; class C1 : public B { ... }; class C2 : public B { ... }; class D : public C1, C2 { ... };

Ejemplo Programa banco usando herencia multiple.

#include<iostream.h> #include<cstdlib.h> #include<conio.h> class valor { protected: double cap,cap1,cap2,monto,capital; public: valor(); }; valor::valor() { capital=capital; } class ctacte { protected: string num_cuenta; public: ctacte(); }; ctacte::ctacte() { num_cuenta=num_cuenta; } class accion { protected: char operacion; public: accion(); }; accion::accion() { operacion=operacion; } class propiedad : public valor,ctacte,accion { protected: char rpta; double monto,t,deposito,retiro; public: propiedad(); void calcular(); void mostrar(); };

propiedad::propiedad() { valor::capital=capital; ctacte::num_cuenta=num_cuenta; accion::operacion=operacion; } void propiedad::calcular() { cout<<"nn"; cout<<"ttt INGRESAR NUMERO DE CUENTA: "<<endl; cin>>num_cuenta; system("cls"); cout<<"nn"; cout<<"ttt INGRESAR CAPITAL: "<<endl; cin>>capital; system("cls"); t=capital; deposito=0; retiro=0; do { cout<<"nn" <<"ttt QUE OPERACION DESEA REALIZARn" <<"ttt === ========= ===== ========nnn" <<"t (1) DEPOSITO "<<"nn" <<"t (2) RETIRO "<<"nn"; cin>>operacion; switch(operacion) { case'1': { cout<<"nn"; cout<<"tttINGRESAR DEPOSITO"<<endl; cin>>cap1; deposito=deposito+cap1; monto=capital+cap1; capital=monto; }break; case'2': { cout<<"nn"; cout<<"tttINGRESAR RETIRO"<<endl; cin>>cap2; if (cap2 >capital) cout<<"No puede retirar mas dinero"<< endl; else{ retiro=retiro+cap2;

monto=capital-cap2; capital=monto;} }break; } system("cls"); cout<<"DESEA CONTINUAR S/N : "<<endl; cin>>rpta; }while(rpta=='S'||rpta=='s'); system("cls"); } void propiedad::mostrar() { calcular(); cout<<"nn" <<"tttMOSTRANDO DATOS LA CUENTA BANCARIAn" <<"ttt========= ===== == ====== ========nnn" <<"t Su capital inicial es : $ "<<t<<"nn" <<"t El deposito total es : $ "<<deposito<<"nn" <<"t El retiro total es : $ "<<retiro<<"nn" <<"t Su actual capital es : $ "<<capital<<"nn"; } void main() { propiedad a; a.mostrar(); getch(); }

Anda mungkin juga menyukai