Curso C++ Modulo 1

98
REPUBLICA BOLIVARIANA DE VENEZUELA INTRODUCCION A LA PROGRAMACIÓN EN C++ SINOPSIS DE CONTENIDO Introducción a la programación: Uso del lenguaje de programación Tipos de Datos: Variables, Tipos de datos, expresiones y asignaciones. Estructuras de control: condicionales secuenciales e iterativas. Datos compuestos: arreglos unidimensionales y multidimensionales, cadenas numéricas y de caracteres. Apuntadores y Referencias. Procedimientos y Funciones. Estructuras, Clases y Objetos. Archivos. Un lenguaje de programación es un conjunto de símbolos y reglas sintácticas y semánticas que definen su estructura y el significado de sus elementos y expresiones. Es utilizado para controlar el comportamiento físico y lógico de una máquina. Un lenguaje de programación" es un lenguaje diseñado para describir el conjunto de acciones que un equipo debe ejecutar. Por lo tanto, un lenguaje de programación es un modo práctico para que los seres humanos puedan dar instrucciones a un equipo. El lenguaje utilizado por el procesador se denomina lenguaje máquina. Se trata de datos tal como llegan al procesador, que consisten en una serie de 0 y 1. El lenguaje máquina, por lo tanto, no es comprensible para los seres humanos, razón por la cual se han desarrollado lenguajes intermediarios comprensibles para el hombre. El código escrito en este tipo de lenguaje se transforma en código máquina para que el procesador pueda procesarlo. El ensamblador fue el primer lenguaje de programación utilizado. Es muy similar al lenguaje máquina, pero los

Transcript of Curso C++ Modulo 1

REPUBLICA BOLIVARIANA DE VENEZUELA

INTRODUCCION A LA PROGRAMACIÓN EN C++

SINOPSIS DE CONTENIDO

Introducción a la programación: Uso del lenguaje de programación Tipos de Datos: Variables, Tipos de datos, expresiones y asignaciones. Estructuras de control: condicionales secuenciales e iterativas. Datos compuestos: arreglos unidimensionales y multidimensionales, cadenas numéricas y de caracteres. Apuntadores y Referencias. Procedimientos y Funciones. Estructuras, Clases y Objetos. Archivos.

Un lenguaje de programación es un conjunto de símbolos y reglas sintácticas y semánticas que definen su estructura y el significado de sus elementos y expresiones. Es utilizado para controlar el comportamiento físico y lógico de una máquina.

Un lenguaje de programación" es un lenguaje diseñado para describir el conjunto de acciones que un equipo debe ejecutar. Por lo tanto, un lenguaje de programación es un modo práctico para que los seres humanos puedan dar instrucciones a un equipo.

El lenguaje utilizado por el procesador se denomina lenguaje máquina. Se trata de datos tal como llegan al procesador, que consisten en una serie de 0 y 1. El lenguaje máquina, por lo tanto, no es comprensible para los seres humanos, razón por la cual se han desarrollado lenguajes intermediarios comprensibles para el hombre. El código escrito en este tipo de lenguaje se transforma en código máquina para que el procesador pueda procesarlo.

El ensamblador fue el primer lenguaje de programación utilizado. Es muy similar al lenguaje máquina, pero los desarrolladores pueden comprenderlo. No obstante, este lenguaje se parece tanto al lenguaje máquina que depende estrictamente del tipo de procesador utilizado (cada tipo de procesador puede tener su propio lenguaje máquina). Así, un programa desarrollado para un equipo no puede ser portado a otro tipo de equipo. El término "portabilidad" describe la capacidad de usar un programa de software en diferentes tipos de equipos. Para poder utilizar un programa de software escrito en un código ensamblador en otro tipo de equipo, ¡a veces será necesario volver a escribir todo el programa! Todo programa escrito en otro lenguaje diferente al leguaje de maquina puede ser ejecutado de dos maneras:

o Mediante un programa que va adaptando las instrucciones conforme son encontradas. A este proceso se lo llama interpretar y a los programas que lo hacen se los conoce como intérpretes.

o Traduciendo este programa, al programa equivalente escrito en lenguaje de máquina. A ese proceso se lo llama compilar y al programa traductor se le denomina compilador.

Los lenguajes de programación tienen varias ventajas:o Son mucho más fácil de comprender que un lenguaje máquina.o Permiten mayor portabilidad, es decir que puede adaptarse fácilmente para

ejecutarse en diferentes tipos de equipos.

Un traductor (compilador o intérprete) 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 traducción, el traductor informa a su usuario de la presencia de errores en el programa fuente.

El proceso de traducción se divide en dos fases o etapas:

o Fase de análisis.- La parte del análisis divide al programa fuente en sus elementos componentes y crea una representación intermedia del programa fuente.

o Fase de síntesis.- La parte de la síntesis construye el programa objeto deseado a partir de la representación intermedia.

De las dos partes, la síntesis es la que requiere las técnicas más especializadas.

Además de un traductor, se pueden necesitar otros programas para crear un programa objeto ejecutable. Un programa fuente se puede dividir en módulos almacenados en archivos distintos. La tarea de reunir el programa fuente a menudo se confía a un programa distinto, llamado preprocesador. El preprocesador también puede expandir abreviaturas, llamadas a macros, a proposiciones del lenguaje fuente.

Etapas del proceso

El proceso de traducción se compone internamente de varias etapas o fases, que realizan distintas operaciones lógicas. 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 práctica a menudo se integren juntas.

Fase de análisis

Análisis léxico

El análisis léxico constituye la primera fase, aquí se lee el programa fuente de izquierda a derecha y se agrupa en componentes léxicos (tokens), que son secuencias de caracteres que tienen un significado. Además, todos los espacios en blanco, líneas en blanco, comentarios y demás información innecesaria se elimina del programa fuente. También se comprueba que los símbolos del lenguaje (palabras clave, operadores,...) se han escrito correctamente.

Como la tarea que realiza el analizador léxico es un caso especial de coincidencia de patrones, se necesitan los métodos de especificación y reconocimiento de patrones, y estos métodos son principalmente las expresiones regulares y los autómatas finitos. Sin embargo, un analizador léxico también es la parte del traductor que maneja la entrada del código fuente, y puesto que esta entrada a menudo involucra un importante gasto de tiempo, el analizador léxico debe funcionar de manera tan eficiente como sea posible.

Análisis sintáctico

En esta fase los caracteres o componentes léxicos se agrupan jerárquicamente en frases gramaticales que el compilador utiliza para sintetizar la salida. Se comprueba si lo obtenido de la fase anterior es sintácticamente correcto (obedece a la gramática del lenguaje). Por lo general, las frases gramaticales del programa fuente se representan mediante un árbol de análisis sintáctico.

La estructura jerárquica de un programa normalmente se expresa utilizando reglas recursivas. Por ejemplo, se pueden dar las siguientes reglas como parte de la definición de expresiones:

1. Cualquier identificador es una expresión.2. Cualquier número es una expresión.3. Si expresión1 y expresión2 son expresiones, entonces también lo son:

o expresión1 + expresión2

o expresión1 * expresión2

o ( expresión1 )

Las reglas 1 y 2 son reglas básicas (no recursivas), en tanto que la regla 3 define expresiones en función de operadores aplicados a otras expresiones.

La división entre análisis léxico y análisis sintáctico es algo arbitraria. Un factor para determinar la división es si una construcción del lenguaje fuente es inherentemente recursiva o no. Las construcciones léxicas no requieren recursión, mientras que las construcciones sintácticas suelen requerirla. No se requiere recursión para reconocer los identificadores, que suelen ser cadenas de letras y dígitos que comienzan con una letra. Normalmente, se reconocen los identificadores por el simple examen del flujo de entrada, esperando hasta encontrar un carácter que no sea ni letra ni dígito, y agrupando después todas las letras y dígitos encontrados hasta ese punto en un componente léxico llamado identificador. Por otra parte, esta clase de análisis no es suficientemente poderoso para analizar expresiones o proposiciones. Por ejemplo, no podemos emparejar de manera apropiada los paréntesis de las expresiones, o las palabras begin y

end en proposiciones sin imponer alguna clase de estructura jerárquica o de anidamiento a la entrada.

Análisis semántico

La fase de análisis semántico revisa el programa fuente para tratar de encontrar errores semánticos y reúne la información sobre los tipos para la fase posterior de generación de código. En ella se utiliza la estructura jerárquica determinada por la fase de análisis sintáctico para identificar los operadores y operandos de expresiones y proposiciones.

Un componente importante del análisis semántico es la verificación de tipos. Aquí, el compilador verifica si cada operador tiene operandos permitidos por la especificación del lenguaje fuente. Por ejemplo, las definiciones de muchos lenguajes de programación requieren que el compilador indique un error cada vez que se use un número real como índice de una matriz. Sin embargo, la especificación del lenguaje puede imponer restricciones a los operandos, por ejemplo, cuando un operador aritmético binario se aplica a un número entero y a un número real.

Fase de síntesis

Consiste en generar el código objeto equivalente al programa fuente. Sólo se genera código objeto cuando el programa fuente está libre de errores de análisis, 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 código objeto es código de máquina relocalizable o código ensamblador. Las posiciones de memoria se seleccionan para cada una de las variables usadas por el programa. Después, cada una de las instrucciones intermedias se traduce a una secuencia de instrucciones de máquina que ejecuta la misma tarea. Un aspecto decisivo es la asignación de variables a registros.

Generación de código intermedio

Después de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explícita del programa fuente. Se puede considerar esta representación intermedia como un programa para una máquina abstracta. Esta representación intermedia debe tener dos propiedades importantes; debe ser fácil de producir y fácil de traducir al programa objeto.

La representación intermedia puede tener diversas formas. Existe una forma intermedia llamada "código de tres direcciones" que es como el lenguaje ensamblador de una máquina en la que cada posición de memoria puede actuar como un registro. El código de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como máximo tres operandos. Esta representación intermedia tiene varias propiedades:

o Primera .- Cada instrucción de tres direcciones tiene a lo sumo un operador, además de la asignación, por tanto, cuando se generan estas instrucciones, el traductor tiene que decidir el orden en que deben efectuarse las operaciones.

o Segunda .- El traductor debe generar un nombre temporal para guardar los valores calculados por cada instrucción.

o Tercera .- Algunas instrucciones de "tres direcciones" tienen menos de tres operandos, por ejemplo, la asignación.

Optimización de código

La fase de optimización de código consiste en mejorar el código intermedio, de modo que resulte un código máquina más rápido de ejecutar. Esta fase de la etapa de síntesis es posible sobre todo si el traductor es un compilador (difícilmente un interprete puede optimizar el código objeto). Hay mucha variación en la cantidad de optimización de código que ejecutan los distintos compiladores. En los que hacen mucha optimización, 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 ejecución del programa objeto sin retardar demasiado la compilación.

Intérprete

Un intérprete es un programa informático capaz de analizar y ejecutar otros programas, escritos en un lenguaje de alto nivel. Los intérpretes se diferencian de los compiladores en que mientras estos traducen un programa desde su descripción en un lenguaje de programación al código máquina del sistema destino, los primeros (los interpretes) sólo realizan la traducción a medida que sea necesario, típicamente, instrucción por instrucción, y normalmente no guardan el resultado de dicha traducción.

Los programas interpretados suelen ser más lentos que los compilados debido a la necesidad de traducir el programa mientras se ejecuta, pero a cambio son más flexibles como entornos de programación y depuración (lo que se traduce, por ejemplo, en una mayor facilidad para reemplazar partes enteras del programa o añadir módulos completamente nuevos), y permiten ofrecer al programa interpretado un entorno no dependiente de la máquina donde se ejecuta el intérprete, sino del propio intérprete (lo que se conoce comúnmente como máquina virtual).

Comparando su actuación 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 intérprete corresponde al intérprete humano, que traduce de viva voz las palabras que oye, sin dejar constancia por escrito.

En la actualidad, uno de los entornos más comunes de uso de los intérpretes informáticos es Internet, debido a la posibilidad que estos tienen de ejecutarse independientemente de la plataforma.

Compilador

Un compilador es un programa informático que traduce un programa escrito en un lenguaje de programación a otro lenguaje de programación, generando un programa equivalente que la máquina será capaz de interpretar. Usualmente el segundo lenguaje es código máquina, pero también puede ser simplemente texto. Este proceso de traducción se conoce como compilación.

Un compilador es un programa que permite traducir el código fuente de un programa en lenguaje de alto nivel, a otro lenguaje de nivel inferior (típicamente lenguaje máquina). De esta manera un programador puede diseñar un programa en un lenguaje mucho más cercano a como piensa un ser humano, para luego compilarlo a un programa más manejable por una computadora.

Partes de un compilador

Normalmente los compiladores están divididos en dos partes:

o Front End: es la parte que analiza el código fuente, comprueba su validez, genera el árbol de derivación y rellena los valores de la tabla de símbolos. Esta parte suele ser independiente de la plataforma o sistema para el cual se vaya a compilar.

o Back End: es la parte que genera el código máquina, específico de una plataforma, a partir de los resultados de la fase de análisis, realizada por el Front End.

Esta división permite que el mismo Back End se utilice para generar el código máquina de varios lenguajes de programación distintos y que el mismo Front End que sirve para analizar el código fuente de un lenguaje de programación concreto sirva para generar código máquina en varias plataformas distintas.

El código que genera el Back End normalmente no se puede ejecutar directamente, sino que necesita ser enlazado por un programa enlazador (linker)

Introducción a la programación:

Desde principios de la era computacional se crearon diversas técnicas de programación que a medida han evolucionado para poder adaptarse a nuevos retos y poder crear soluciones más realistas que se amolden a el entorno real.

Podemos notar que a inicios la programación era no estructurada. Este estilo de Programación No Estructurada, consistía 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 técnica de programación 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 técnicas como lo son la programación procedimental y modular, conduciéndonos a un estilo de programación estructurada.

La Programación Estructurada es un método de programación basado sobre el concepto de la unidad y del alcance. La programación estructurada ofrece muchas ventajas sobre la programación secuencial, es más fácil de leer y más conservable; siendo muy flexible, facilitando el buen diseño de programas.

La programación estructurada, es un estilo de programación con el cual el programador elabora programas, cuya estructura es la más clara posible, mediante el uso de tres estructuras básicas de control lógico: secuencia, selección e iteración.

Los programas son más fáciles de entender. Un programa estructurado puede ser leído en secuencia, de arriba hacia abajo, sin necesidad de estar saltando de un sitio a otro en la lógica, lo cual es típico de otros estilos de programación. La estructura del programa es más clara puesto que las instrucciones están más ligadas o relacionadas entre si, por lo que es más fácil comprender lo que hace cada función. Reducción del esfuerzo en las pruebas. El programa se puede tener listo para producción normal en un tiempo menor del tradicional; por otro lado, el seguimiento de las fallas o depuración se facilita debido a la lógica más visible, de tal forma que los errores se pueden detectar y corregir más fácilmente. Los programas quedan mejor documentados internamente.

A pesar de las múltiples ventajas que ofrecen la programación estructurada, surge necesidades y problemas complejos los cuales necesitan recrear o representar mundos reales, lo cual, se dificulta con la técnicas de programación estructurada.

La Programación Orientada a Objetos (POO) aporta un nuevo enfoque a los retos que se plantean en la programación estructurada cuando los problemas a resolver son complejos. Al contrario que la programación 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 diseñar formatos de datos que se correspondan con las características esenciales de un problema. Los lenguajes orientados combinan en una única unidad o módulo, 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 función puede acceder a los datos. Esto simplifica la escritura, depuración y mantenimiento del programa.

La tecnología orientada a objetos se define como una metodología de diseño de software que modela las características de objetos reales o abstractos por medio del uso de clases y objetos. Hoy en día, la orientación a objetos es fundamental en el desarrollo de software, sin embargo, esta tecnología no es nueva, sus orígenes se remontan a la década de los años sesenta (Simula, uno de los lenguajes de programación orientados a objetos más antiguos, fue desarrollado en 1967).LLa Programación Orientada a Objetos, la podemos definir como una técnica o estilo de programación que utiliza objetos como bloque esencial de construcción. AROS ASCUIEl objeto, es el concepto principal sobre el cual se fundamenta la programación orientada a objetos, el cual puede ser visto como una entidad que posee atributos y efectúa acciones. En el mundo real podemos encontrar cientos de ejemplos que cumplen con ésta definición, algunos de ellos son: una bicicleta, un automóvil, 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.

 Un programa orientado a objetos es una colección de clases.

Necesita de una función principal que cree objetos y comience la ejecución mediante la invocación de sus funciones o métodos.

En primer lugar, se crean los objetos. Segundo, los mensajes se envían 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 también se les conoce como instancias de clase. A los elementos de un objeto se les conoce como miembros (datos miembros y funciones miembro).

Características de la POO

Las características más importantes que debe soportar un lenguaje que lo definen como "orientado a objetos", son:

o Abstracción: Denota las características 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 cómo se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos y cuando lo están, una variedad de técnicas son requeridas para ampliar una abstracción.

Ejemplo: un automóvil. Características: Color, año de fabricación, modelo, etc. Métodos o Funciones: Frenar, encender, etc.

o Encapsulamiento: Significa reunir a todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión de los componentes del sistema.

La encapsulación es un mecanismo que consiste en organizar datos y métodos 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 encapsulación 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 automóvil, un mecánico debe saber como trabaja el motor, la transmisión, etc., pero un conductor, puede usar estos componentes sin preocuparse por estos detalles, el automóvil 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.

o Principio de ocultación: Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una interfaz a otros objetos que específica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas, solamente los propios métodos 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 abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos.

El usuario de una clase en particular no necesita saber cómo están estructurados los datos dentro de ese objeto, es decir, un usuario no necesita conocer la implementación Al evitar que el usuario modifique los atributos directamente y forzándolo 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 encapsulación define los niveles de acceso para elementos de esa clase. Estos niveles de acceso definen los derechos de acceso para los datos, permitiéndonos el acceso a datos a través de un método de esa clase en particular, desde una clase heredada o incluso desde cualquier otra clase. Existen tres niveles de acceso:

público: funciones de toda clase pueden acceder a los datos o métodos de una clase que se define con el nivel de acceso público. Este es el nivel de protección de datos más bajo

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

privado: el acceso a los datos está restringido a los métodos de esa clase en particular. Este es nivel más alto de protección de datos

o 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 invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta última característica se llama asignación tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos (en "tiempo de compilación") 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 función "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 varían de acuerdo a los parámetros 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 operación entre dos números enteros (suma) o bien cuando se encuentra entre dos cadenas de caracteres (concatenación).

Polimorfismo paramétrico (también llamado polimorfismo de plantillas). El polimorfismo paramétrico es la capacidad para definir varias funciones utilizando el mismo nombre, pero usando parámetros diferentes (nombre y/o

tipo). El polimorfismo paramétrico selecciona automáticamente el método correcto a aplicar en función del tipo de datos pasados en el parámetro. Por lo tanto, podemos por ejemplo, definir varios métodos homónimos de addition() efectuando una suma de valores.

El método int addition(int, int) devolvería la suma de dos enteros. float addition(float, float) devolvería la suma de dos flotantes. char addition(char, char) daría por resultado la suma de dos caracteres.

Polimorfismo de inclusión (también llamado redefinición o subtipado). La habilidad para redefinir un método en clases que se hereda de una clase base se llama especialización. Por lo tanto, se puede llamar un método de objeto sin tener que conocer su tipo intrínseco: esto es polimorfismo de subtipado. Permite no tomar en cuenta detalles de las clases especializadas de una familia de objetos, enmascarándolos con una interfaz común (siendo esta la clase básica). Imagine un juego de ajedrez con los objetos rey, reina, alfil, caballo, torre y peón, cada uno heredando el objeto pieza. El método movimiento podría, 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.

o Herencia: Por herencia se entiende la capacidad de poder crear nuevas clases a partir de alguna anterior, de forma que las nuevas "heredan" las características de sus ancestros (propiedades y métodos).  Se trata por tanto de la capacidad de crear nuevos tipos de datos a partir de los anteriores.  Una característica especial de la herencia es que si se cambia el comportamiento de la clase antecesora (también llamada  padre, base o super), también cambiará el comportamiento de las clases derivadas de ella (descendientes). Como puede deducirse fácilmente, la herencia establece lo que se llama una jerarquía de clases del mismo aspecto que el árbol genealógico de una familia.  Se entiende también que estos conceptos representan niveles de abstracción que permiten acercar la programación a la realidad del mundo físico tal como lo concebimos.  Por ejemplo, todas las guitarras, ya sean Eléctricas, ElectroAcústicas o normales, cumplen con características similares como número de cuerdas (6), método de afinación, cambio de tono, cambio de postura y rasgueo entre otras. Si no se siguiera con una metodología de herencia, por cada clase (Guitarra Electrica y ElectroAcústica) se tendría que repetir la definición de todos los atributos y métodos que pertenecen a la clase padre Guitarra, que corresponde a la abstracción más amplia del concepto "Guitarra". Mediante el uso de la herencia, se puede definir una clase "Guitarra" que cumpla con todas las características generales del concepto guitarra y sus evoluciones, con el fin de acotar el número de especificaciones de las clases "GuitarraElectrica" y "ElectroAcústica", y permitir la herencia a éstas últimas clases con las características del objeto padre.

o Recolección de basura: la Recolección de basura o Garbage Collection es la técnica por la cual el ambiente de Objetos se encarga de destruir automáticamente, 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 asignación o liberación de memoria, ya que el entorno la asignará al crear un nuevo Objeto y la liberará cuando nadie lo esté usando. En la mayoría de los lenguajes híbridos que se extendieron para soportar el Paradigma de Programación Orientada a Objetos como C++ u Object Pascal, esta característica no existe y la memoria debe desasignarse manualmente.

Uso de los lenguajes de POO

Actualmente una de las áreas más candentes en la industria y en el ámbito académico es la orientación a objetos. La orientación a objetos promete mejoras de amplio alcance en la forma de diseño, desarrollo y mantenimiento del software ofreciendo una solución a largo plazo a los problemas y preocupaciones que han existido desde el comienzo en el desarrollo de software: la falta de portabilidad del código y reusabilidad, código que es difícil de modificar, ciclos de desarrollo largos y técnicas de codificación no intuitivas.

La introducción de tecnología de objetos como una herramienta concepual para analizar, diseñar e implementar aplicaciones permite obtener aplicaciones más modificables, fácilmente extendibles y a partir de componentes reusables. Esta reusabilidad del código disminuye el tiempo que se utiliza en el desarrollo y hace que el desarrollo del software sea mas intuitivo porque se piensa naturalmente en términos de objetos más que en términos de algoritmos de software.

La Programación Orientada a Objetos ofrece algunas de ventajas respecto a otros paradigmas de la programación:

o Fomenta la reutilización y extensión del código.o Facilita el mantenimiento del software.o Permite crear sistemas más complejos.o Agiliza el desarrollo de software.o Facilita la creación de programas visuales.o Facilita el trabajo en equipo relacionar el sistema al mundo real.

Estructura de un programa orientado a objetos.

La programación orientada a objetos (POO) es una de las técnicas más 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 aplicación. Por eso, donde la POO toma verdadera ventaja es en poder compartir y reutilizar el código. Existen varios lenguajes que permiten escribir un programa orientado a objetos y entre ellos se encuentra C++. Se trata de un lenguaje de programación basado en el lenguaje C, estandarizado, ampliamente difundido, y con una biblioteca estándar C++ que lo ha convertido en un lenguaje universal, de propósito general, y ampliamente utilizado tanto en el ámbito profesional como en el educativo. C++ es un lenguaje de programación diseñado a mediados de los años 1980 por Bjarne Stroustrup. La intención de su creación fue el extender al exitoso lenguaje de

programación C con mecanismos que permitan la manipulación de objetos. En ese sentido, desde el punto de vista de los lenguajes orientados a objetos, el C++ es un lenguaje híbrido. Posteriormente se añadieron facilidades de programación genérica, que se sumó a los otros dos paradigmas que ya estaban admitidos (programación estructurada y la programación orientada a objetos). Por esto se suele decir que el C++ es un lenguaje de programación 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á diseñado para ayudarle todo lo posible, y al mismo tiempo dificultarle lo menos posible con reglas arbitrarias o algún requisito que use un conjunto particular de características. C++ está diseñado para ser práctico; las decisiones de diseño del lenguaje C++ estaban basadas en proveer los beneficios máximos al programador.

Estructura de un programa en C ++

Un programa en el lenguaje C++ estará compuesto por:

Comentarios: Muestra información en cuanto a que realiza el programa, la utilidad de las funciones, variables y objetos, estos no serán procesados por el compilador.

Encabezados: se realizan las llamadas y accesos a archivos de Biblioteca de funciones estándar y diseñadas por los usuarios.

Declaración de prototipos: se definen las estructuras de nuevos tipos de datos como lo son las clases, estructuras, etc., además se declaran las existencias de funciones si no han sido implementadas.

Declaraciones globales: Se declaran 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 información entre funciones sin necesidad de utilizar argumentos

Declaración de la función principal Main( ): La función main es imprescindible en cualquier programa C/C++ representa el punto de inicio de su ejecución. Es la función de control principal de un programa, reflejándose como el cuerpo del mismo programa.

Implementación y cuerpo de funciones: Se define la forma o cuerpo de una función para resolver determinada tarea.

Ejemplo:

#include <iostream.h> // Esta biblioteca permite el uso de cout y de cin

class Punto { // Declara un nuevo tipo de dato Punto

public:// Coordenadas del puntoint x;int y;

public:// ConstructorPunto(int x, int y) {x=0; y=0;} // Inicializar las variables // funciones miembrosint extraer_x( )

{ return x; } int extraer_y( )

{ return y; } };

void main( ) //Funcion de control principal{ Punto punto; // creamos un objeto de la clase Punto llamado punto cout << "Coordenada X:" << punto.extraer_x( ) << endl; // mostramos el valor x cout << "Coordenada Y:" << punto.extraer_y( )<< endl; // mostramos el valor y } 

 Un programa será una secuencia de líneas que contendrán sentencias, directivas de compilación y comentarios. Las sentencias simples se separan por punto y coma y las compuestas se agrupan en bloques mediante llaves. Cada sentencia compuesta se encierra con un par de llaves, {.....}. Las llaves pueden contener combinaciones de sentencias elementales (denominadas sentencias de expresión) y otras sentencias compuestas. Así las sentencias compuestas pueden estar anidadas, una dentro de otra. Cada sentencia de expresión debe acabar en punto y coma (;).

Las directivas serán instrucciones que le daremos al compilador para indicarle que realice alguna operación antes de compilar nuestro programa, las directivas comienzan con el símbolo # y no llevan punto y coma.

Los comentarios se introducirán en el programa separados por /* y */ o comenzándolos con //. Los comentarios entre /* y */ pueden tener la longitud que queramos, pero no se anidan, es decir, si escribimos /* hola /* amigo */ mío */, el compilador interpretará que el comentario termina antes de mío, y dará un error. Los comentarios que comienzan por // sólo son válidos hasta el final de la línea en la que aparecen.

Un programa simple puede ser el siguiente:/*Este es un programa mínimo en C++, escribe una fraseen la pantalla*/#include <iostream.h>int main( ){cout << "Hola mundo\n"; // imprime en la pantalla la frase "hola mundo"

}

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 más comprensibles. La línea 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 declaración de main() hemos incluido la palabra int, que indica que la función devuelve un entero. Este valor se le entrega al sistema operativo al terminar el programa. Si no se devuelve ningún valor el sistema recibe un valor aleatorio.La sentencia separada ente llaves indica que se escriba la frase "Hola mundo". El operador <<("poner en") escribe el segundo argumento en el primero. En este caso la cadena "Hola mundo\n" se escribe en la salida estándar (cout). El carácter \ seguido de otro carácter indica un solo carácter especial, en este caso el salto de línea (\n).

Por último señalar que debemos seguir ciertas reglas al nombrar tipos de datos, variables, funciones, etc. Los identificadores válidos del C++ son los formados a partir de los caracteres del alfabeto (el inglés, no podemos usar ni la ñ ni palabras acentuadas), los dígitos (0..9) y el subrayado ( _ ), la única restricción es que no podemos comenzar un identificador con un dígito (es así porque se podrían confundir con literales numéricos). Hay que señalar que el C++ distingue entre mayúsculas y minúsculas, por lo que Hola y hola representan dos cosas diferentes. Hay que evitar el uso de identificadores que sólo difieran en letras mayúsculas y minúsculas, porque inducen a error.

Las palabras reservadas 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 acción. Las variables que se declaren a lo largo de todo el programa, así como las funciones y demás 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 producirían errores, por lo que es importante tener una buena familiarización con las mismas, a fin de no cometer errores. La lista de algunas palabras reservadazas a continuación: asm auto bool break casecatch char class const continuedefault delete do double elseenum explicit extern false floatfor friend goto if inlineint long   mutable namespace newoperator private protected public registerreturn short signed sizeof staticstruct switch template this throwtrue try typedef typename unionunsigned using virtual void volatilewhile

asm. Medio definido por la puesta en práctica de utilización de lenguaje de ensamblaje a lo largo de C++ .break. La declaración de pausa o descanso manda pasar el argumento al partidario de la declaración, 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. Envío de los pasos a seguir sin detenerse como es caso siguiente.catch. Maneja una excepción 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 dinámicamente un objeto de memoria libre. Determina automáticamente el tamaño del objeto.friend. Declara una función 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 “homónimo”.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; tambièn 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 función.template. Declara como construir una clase o una función, usando una variedad de tipos. this. Un apuntador declarado en forma implícita en toda función de miembro no static de una clase. Señales al objeto al cual esta función miembro ha sido invocada.throw. Transfiere control a un manejador de excepción o termina la ejecución del programa si no puede ser localizado un manejador apropiado.virtual. Declara una función virtual.

Tipos de datos.

C++ no soporta un gran número 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 típicas de un computador y a las distintas maneras de utilizarlos. Todos los tipos de datos simples o básicos de C/C++ son, esencialmente, números. Los tres tipos de datos básicos son:

o Enteros: int, long into Números flotantes (reales): float, doubleo Caracteres: char

Los tipos simples de datos admitidos son los siguientes:

Denominación Tipo de datos Tamaño en bits Rango de valoreschar Carácter 8 de 0 a 255

int Número entero 16 de –32768 a 32767

float Número real de precisión simple 32 de 3.4 x 10-38 a 3.4 x 1038

double Número real de precisión doble 64 de 1.7 x 10-308 a 1.7 x 10308

void Tipo vacío 0 sin valor

Los tamaños en bits pueden variar dependiendo del compilador empleado. Por ejemplo, gcc intepreta que el entero es de 32 bits, y para usar enteros de 16 bits hay que indicarlo expresamente. Por tanto, no debe usted presuponer ningún tamaño concreto para los tipos si quiere escribir programas portables.

El tipo char se usa normalmente para variables que guardan un único carácter, aunque lo que en realidad guardan es un código ASCII, es decir, un número 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 código 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 números enteros, mientras que los tipos float y double sirven para números reales. El segundo permite representar números mayores, a costa de consumir más espacio en memoria.

Un tipo especial del C++ es el denominado void (vacío). Este tipo tiene características muy peculiares, ya que es sintácticamente igual a los tipos elementales pero sólo se emplea junto a los derivados, es decir, no hay objetos del tipo void. Se emplea para especificar que una función no devuelve nada, para declarar funciones sin argumentos; o como base para punteros a objetos de tipo desconocido. Por ejemplo:

void BorraPantalla (void);indica que la función BorraPantalla no tiene parámetros y no retorna nada.

Modificadores de tipo

Existen, además, unos modificadores de tipo que pueden preceder a los tipos de datos char e int. Dichos modificadores son:

o signed: obliga a que los datos se almacenen con signoo unsigned: los datos se almacenan sin signoo long: los datos ocuparán el doble de espacio en bits del habitual, y, por lo tanto,

aumentará su rango de valoreso short: los datos ocuparán 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:

o unsigned int: Número entero de 16 bits sin signo. Rango: de 0 a 65535.o signed int: Número entero de 16 bits con signo. No tiene sentido, porque el tipo

int ya es con signo por definición, pero es sintácticamente correcto.o signed char: Carácter (8 bits) con signo. Rango: de –128 a 127o long int: Número entero de 32 bits. Rango: de –2147483648 a 2147483647

Incluso podemos encontrar combinaciones de varios modificadores. Por ejemplo:

o unsigned long int: Número entero de 32 bits sin signo. Rango: de 0 a 4294967295

Tipos enumerados

Un tipo especial de tipos enteros son los tipos enumerados. Estos tipos sirven para definir un tipo que sólo 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 número 0, la constante TRUE con 1, y si hubiera más constantes seguiríamos con 2, 3, etc. Si por alguna razón nos interesa dar un número concreto a cada valor podemos hacerlo en la declaración:

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

El azul tomará el valor 5 (4+1), ya que no hemos puesto nada. También se pueden usar números 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.

Tipos derivados

De los tipos fundamentales podemos derivar otros mediante el uso de los siguientes operadores de declaración:

o Puntero: Para cualquier tipo T, el puntero a ese tipo es T*. Una variable de tipo T* contendrá la dirección de un valor de tipo T.

o & 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.

o [] 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.

o () Función: La declaración de una función nos da el nombre de la función, el tipo del valor que retorna y el número y tipo de parámetros que deben pasársele.

Ejemplos:int *n; // puntero a un enteroint v[20]; // arreglo de 20 enterosint *c[20]; // arreglo de 20 punteros a enterovoid f(int j); // función con un parámetro entero

.Tipos compuestos

Los tipos de datos compuestos en C++ son:

o 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 después de cerrar la llave ponemos una lista de variables las declaramos a la vez que definimos la estructura.

o Uniones. Las uniones son idénticas a las estructuras en su declaración, con la particularidad de que todos sus campos comparten la misma memoria (el tamaño de la unión será el del campo con un tipo mayor).

o Clases. Las clases son estructuras con una serie de características especiales.

Variables y constantes.

En C/C++ una variable es una posición 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: Cadenas, números y estructuras. Una constante, por el contrario, es una variable cuyo valor no puede ser modificado.

Declaración de las variables   

Una variable típicamente tiene un nombre (un identificador) que describe su propósito. Toda variable utilizada en un programa debe ser declarada previamente. La definición utilizada en un programa en cualquier parte del programa. Una definición 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 declaración de variables puede considerarse como una sentencia. Desde este punto de vista, la declaración terminará con un ";".

Sintaxis de declaración:

tipodato nombrevariable;

Ejemplo: int a; float d,

char e;

tipodato nomvar1, nomvar2, …, nomvarn-1, nomvarn;

Ejemplo: int a, b, c;

También es posible inicializar las variables dentro de la misma declaración.

tipodato nombrevariable = inicialización;

Ejemplo: int a = 5;

tipodato nomvar1= inicial1, nomvar2 = inicial2, …, nomvarn = inicialn;

Ejemplo: int a = 2, b = 4, c = 6;

Las variables no inicializadas tienen un valor indeterminado, contienen lo que normalmente se denomina "basura".

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, dígitos y el guión bajo ó subguión (_).

Los nombres de variables no pueden llevar caracteres especiales, ejemplo: caracteres acentuados, ñ, *, /, -, etc. Deben comenzar por un carácter (letra no numero) o también pueden comenzar con un guión bajo (_), ejemplo: _costo.

Ámbito de las variables  

Dependiendo de dónde se declaren las variables, podrán o no ser accesibles desde distintas partes del programa. Las variables declaradas dentro de un bucle, serán accesibles sólo desde el propio bucle, serán de ámbito local del bucle.

Las variables declaradas dentro de una función, sólo serán accesibles desde esa función. Esas variables son variables locales o de ámbito local de esa función.

Las variables declaradas fuera de las funciones, normalmente antes de definir las funciones, en la zona donde se declaran los prototipos, serán accesibles desde todas las funciones. Estas variables serán globales o de ámbito global. Variables Locales

Las variables locales son aquellas definidas en el interior de una función y son visibles sólo en esta función específica. Las reglas por las que se rigen las variables locales son:

o En el interior de una función, una variable local no puede ser modificada por ninguna sentencia externa a la función.

o Los nombres de las variables locales no han de ser únicos. Dos, tres o más funciones - por ejemplo: pueden definir variables de nombre Interruptor. Cada variable es distinta y pertenece a la función en que está declarada.

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

#include <iostream.h>#include <conio.h>void main(){ //declaración de variables locales de la función main() int x, y; //variables locales x, y

}

void suma(){ //declaración de variables locales de la función suma() int a, b; //variable locales a, b

}

 Variables Globales

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

#include <iostream.h>#include <conio.h>int a, c, b, x; //declaración de variables globalesmain(){  //declaración de variables locales}

Tipos de Almacenamientos

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

o Static

    Una variable estática existe desde que el programa comienza su ejecución y dura hasta que el programa termina. Esta característica permite retener el valor de una variable incluso aunque la ejecución del programa salga fuera del ámbito en el que ha sido declarada. Se declara anteponiendo la palabra reservada static a la declaración de la variable. Considere el siguiente fragmento de código:

ejemplo( ){

static int x=0;x++;

...}

En este caso, static modifica la declaración de la variable x, que por defecto es local a la función, de manera que si bien el ámbito de x sigue siendo la función (no se puede utilizar fuera de ella), ésta no se destruye una vez ejecutada la función, sino que sigue en memoria conservando su valor, y si la función 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.

o Extern

    La palabra reservada extern sirve para declarar un nombre de función o variable como externa, y permite referencia una declaración que se encuentra en otro archivo. Esta característica fue diseñada originalmente para facilitar la compilación separada de archivos, en este curso, no la utilizaremos de momento.

o Auto

    Es la declaración de una variable local. Se usa para definir el ámbito temporal de una variable local, es utilizada por defecto en las funciones.

o Register

   Cuando a la declaración 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 función. La razón de utilizar variables register reside en que las operaciones sobre los valores situadas en los registros son normalmente más rápidas que las realizadas sobre valores situados en memoria, por lo que se aumente la eficacia y velocidad del programa.

Una aplicación típica 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++)    {...}

Conversión explícita de tipos de datos

En C++ está permitida una conversión explícita del tipo de una expresión mediante una construcción que tiene la forma nombre_del_tipo (expresión). La expresión es convertida al tipo especificado. Por ejemplo la función raíz 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 explícitamente a otro tipo.

Constantes

Las constantes son tipos de datos (con valores numéricos 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.

Por ejemplo: El valor de pi = 3.141592

Constantes definidas.

Las constantes pueden recibir nombres simbólicos 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 dígito numérico, etc.).

Ejemplo: #include <stdio.h> #define PI 3.1415926 int main() { 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 también se puede utilizar para definir expresiones más elaboradas con operadores (suma, resta, multiplicación, etc.) y otras constantes que hayan sido definidas previamente, por ejemplo:

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

Ejemplo de uso de las constantes definidas:

#include <stdio.h>

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

Constantes de enumeración.

Se caracterizan por poder adoptar valores entre una selección de constantes enteras denominadas enumeradores; estos valores son establecidos en el momento de la declaración del nuevo tipo. Como se ha señalado, 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 numérico) y 5.

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, señalado 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 idénticas propiedades que el original pero que no puede ser cambiado después de su inicialización (se trata pues de un verdadero especificador de tipo).

Cuando se utiliza en la definición de parámetros 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 asignación posterior a un identificador especificado como const, esta debe hacerse inevitablemente en el momento de la declaración, a menos que se trate de una declaración extern.

Las constantes se pueden utilizar para sustituir a #define. Ejemplo

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

Operadores y operaciones aritméticas, relacionales, lógicas, asignaciones, condicionales e incrementales.

Un operador es un carácter o grupo de caracteres que actúa sobre una, dos o mas variables para realizar una determinada operación con un determinado resultado. Ejemplo típicos de operadores son la suma (+), la diferencia (-), el producto (*), etc. Los operadores pueden ser unarios, binarios y terciarios, según actúen sobre uno, dos o tres operandos, respectivamente. Hay varios tipos de operadores, clasificados según el tipo de objetos sobre los que actúan.

Operadores aritméticos   

Son usados para crear expresiones matemáticas. Existen dos operadores aritméticos unitarios, '+' y '-' que tienen la siguiente sintaxis:

+ <expresión>- <expresión>

Asignan valores positivos o negativos a la expresión a la que se aplican.

En cuanto a los operadores binarios existen varios. '+', '-', '*' y '/', tienen un comportamiento análogo, en cuanto a los operandos, ya que admiten enteros y de coma flotante. Se trata de las conocidísimas operaciones aritméticas de suma, resta, multiplicación y división. Sintaxis:

<expresión> + <expresión><expresión> - <expresión><expresión> * <expresión><expresión> / <expresión><expresión> % <expresión>

El operador de módulo '%', devuelve el resto de la división entera del primer operando entre el segundo. Por esta razón no puede ser aplicado a operandos en coma flotante.

Cuando las expresiones que intervienen en una de estas operaciones sean enteras, el resultado también será entero. Por otro lado si las expresiones son en punto flotantes, con decimales, el resultado será en punto flotante.

Operadores incrementales

Son dos operadores unitarios, se trata de operadores un tanto especiales, ya que sólo pueden trabajar sobre variables, pues implican una asignación. 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> ++ (post-incremento)++ <variable> (pre-incremento)<variable>-- (post-decremento)-- <variable> (pre-decremento)

En su forma de prefijo, el operador es aplicado antes de que se evalúe el resto de la expresión; en la forma de sufijo, se aplica después de que se evalúe el resto de la expresión. 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 continuación se evalúa la expresión "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 avalúa la expresión "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 evalúan después de que se han evaluado el resto de las expresiones. En el primer ejemplo primero se evalúa ++b, después a+b y finalmente c =<resultado>. En el segundo ejemplo, primero se evalúa a+b, después c = <resultado> y finalmente b++.

Operadores de asignación   

Los operadores de asignación atribuyen a una variable, es decir, depositan en la zona de memoria correspondiente a dicha variable, el resultado de una expresión o valor de otra variable.

Existen varios operadores de asignación, el más evidente y el más usado es el "=", pero no es el único.

Entre los operadores de asignación tenemos: "=", "*=", "/=", "%=", "+=", "-=". Y la sintaxis es:

<variable> <operador de asignación> <expresión>

En general, para todos los operadores mixtos la expresión

Expresion1 op= Expresion2

Tiene el mismo efecto que la expresión

Expresion1 = Expresion1 op Expresion2

El funcionamiento es siempre el mismo, primero se evalúa la expresión de la derecha, se aplica el operador mixto, si existe y se asigna el valor obtenido a la variable de la izquierda.

Tabla de Equivalencia de Operadores de Asignación

OperadorSentencia Abreviada

Sentencia no Abreviada

+ = m = + n m = m + n;

- = m - = n m = m - n;

* = m * = n m = m * n;

/ = m / = n m = m / n;

% = m = % n m = m % n

Operador coma   

La coma tiene una doble función, por una parte separa elementos de una lista de argumentos de una función. Por otra, puede ser usado como separador en expresiones "de coma". Ambas funciones pueden ser mezcladas, pero hay que añadir paréntesis para resolver las ambigüedades. Sintaxis:

E1, E2, ..., En

En una expresión "de coma", cada operando es evaluado como una expresión, 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 función con tres argumentos: (i, 5, k). La expresión de coma (j = 1, j+4), se evalúa de izquierda a derecha, y el resultado se pasará como argumento a la función.

Operadores relacionales   

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

<expresión1> > <expresión2><expresión1> < <expresión2><expresión1> <= <expresión2><expresión1> >= <expresión2><expresión1> == <expresión2><expresión1> != <expresión2>

El resultado de cualquier evaluación 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:

Expresión1 op Expresión2

Operadores lógicos   

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

<expresión1> && <expresión2><expresión1> || <expresión2>!<expresión>

El operador "&&" equivale al "AND" o "Y"; devuelve "true" sólo si las dos expresiones evaluadas son "true" o distintas de cero, en caso contrario devuelve "false" o cero. Si la primera expresión evaluada es "false", la segunda no se evalúa.

Generalizando, con expresiones AND con más de dos expresiones, la primera expresión falsa interrumpe el proceso e impide que se continúe la evaluación del resto de las expresiones. Esto es lo que se conoce como "cortocircuito", y es muy importante. A continuación se muestra la tabla de verdad del operador &&:

Expresión1 Expresión2 Expresión1 && Expresión2

false ignorada false

true false false

true true true

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 expresión evaluada es "true", la segunda no se evalúa.

Expresión1 Expresión2 Expresión1 || Expresión2

false false false

false true true

true ignorada true

El operador "!" es equivalente al "NOT", o "NO", y devuelve "true" sólo si la expresión evaluada es "false" o cero, en caso contrario devuelve "false". La expresión "!E" es equivalente a (0 == E).

Expresión !Expresión

false true

true false

Operador "sizeof"   Este operador tiene dos usos diferentes. Sintaxis:

sizeof (<expresión>)sizeof (nombre_de_tipo)

En ambos casos el resultado es una constante entera que da el tamaño 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 expresión, 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 función, sino un OPERADOR.

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 número 42, que tiene el siguiente patrón de bits 00101010 se convierte en 11010101 después 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 (representación en byte del numero 42)& 00001111 (representación en byte del numero 15)

= 00001010 (representación 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 (representación en byte del numero 42)| 00001111 (representación en byte del numero 15)= 00101111 (representación 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 (representación en byte del numero 42)^ 00001111 (representación en byte del numero 15)= 00100101 (representación en byte del numero 37)

La tabla siguiente muestra cómo actúa cada operador a nivel de bit sobre cada combinación de bits de operando.

A B OR AND XOR NOT

0 0 0 0 0 1

1 0 1 0 1 1

0 1 1 0 1 1

1 1 1 1 0 0

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

int a = 35;a = a >> 2;

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 (representación en byte del numero 35)>> 2

= 00001000 (representación en byte del numero 8)

Operador condicional ternario ?:

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

( (condición) ? proceso1 : proceso2 )

En donde, condición es la expresión que se evalúa, proceso1 es la tarea a realizar en el caso de que la evaluación resulte verdadera, y proceso2 es la tarea a realizar en el caso de que la evaluación resulte falsa.

Ejemplo 1:

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

Expresiones.

Una expresión es una combinación de operadores y operandos de cuya evaluación 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 más simples. La evaluación de una expresión da lugar a un valor de algún tipo, una expresión 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 evalúan de acuerdo con la precedencia de los operadores. Ante una secuencia de operadores de igual precedencia, la evaluación se realiza según el orden de escritura, de izquierda a derecha. El orden de evaluación puede modificarse usando operadores que denoten precedencia como los paréntesis.

Reglas de precedencias

El resultado de una expresión depende del orden en que se ejecutan las operaciones. Por ejemplo considere la siguiente expresión: 3 + 4 * 2. Si se resuelve primero la suma y

luego la multiplicación el resultado será 14. Pero si se realiza primero la multiplicación y luego la suma el resultado es 11. Con el objeto de que el resultado de una expresión sea claro e inequívoco, es necesario crear reglas que definan el orden de ejecución. La interpretación de cualquier expresión en C++ está determinada por la precedencia y asociatividad de los operadores en dicha expresión. Cada operador tiene una precedencia, y los operadores en una expresión se evalúan en orden de mayor a menor precedencia. La evaluación de operadores con la misma precedencia viene determinada por su asociatividad. Los paréntesis 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 más arriba tienen mayor prioridad). Los operadores en la misma línea horizontal tienen la misma precedencia.

Operador Propósito Asociatividad( ) Denota precedencia en una expresión De izquierda a derecha

sizeof Tamaño de un objeto De derecha a izquierda

++ -- Incremento y decremento prefijo De derecha a izquierda

! ~ + - Operadores Unario De derecha a izquierda

* / % Operaciones aritméticas multiplicación, división y modulo

De izquierda a derecha

+ - Operaciones aritméticas adicción y sustracción

De izquierda a derecha

<< >> Desplazamiento binario De izquierda a derecha

< > <= >= Operadores de relación De izquierda a derecha

== != Operadores de igualdad De izquierda a derecha

& Y binario De izquierda a derecha

^ O exclusivo binario De izquierda a derecha

| O inclusivo binario De izquierda a derecha

&& Y lógico De izquierda a derecha

|| O lógico De izquierda a derecha

?: Operador condicional De izquierda a derecha

= *= /= += -=

&= ^= |= %= <<=

Operadores de asignación De derecha a izquierda

++ -- Incremento y decremento sufijo De derecha a izquierda

, Separador coma De izquierda a derecha

Ejemplos de expresiones:

Ejemplo 1:

Se tiene la siguiente expresión y=2*5*5+3*5+7, se desea evaluarla y encontrar el resultado.

Solución:

Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad.

y = 2 * 5 * 5 + 3 * 5 + 7;2 * 5 = 10 (multiplicación más a la izquierda primero)

y = 10 * 5 + 3 * 5 + 7;10 * 5 = 50 (Multiplicación más a la izquierda)

y = 50 + 3 * 5 + 7;3 * 5 = 15 (Multiplicación antes de la suma)

y = 50 + 15 + 7;50 + 15 = 65 (Suma más a la izquierda)

y = 65 + 7;65 + 7 = 72 (Se resuelve la ultima operación aritmética)

y = 72 (por ultimo se realiza la asignación a la variable y)

Ejemplo 2:

Dados a=1, b=2 y c=3 efectúe la siguiente expresión: d = 10 * a > c * 10 + b

Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad.

d = 10 * 1 > 3 * 10 + 2(Se realiza primero la operación aritmética de mayor precedencia más a la izquierda 10*1 y luego 3*10)

d = 10 > 30 + 2(Se realiza primero la operación aritmética 30 + 2)

d = 10 > 32(Se resuelve la operación relacional 10>32 dando como resultado un valor falso. Todo valor falso es igual a 0)

d = 0 (por ultimo se realiza la asignación a la variable d)

Ejemplo 3:

Efectúe la siguiente expresión: d = 10 > 5 && 3 * 10

Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. A pesar de que el operador lógico && tiene menor prioridad obliga a resolver la expresión mas a la izquierda 10 > 5, aunque el operador aritmético * tenga mayor prioridad.

d = 10 > 5 && 3 * 10(Se separa la expresión debido a la presencia del operador lógico y se resuelve la primera expresión 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 expresión se resuelve la siguiente 3 * 10, de haber resultado falso toda la expresión seria falsa y no realizaría dicha operación. Al resolver la operación 3 * 10 el resultado es 30, donde todo valor diferente a cero es un valor verdadero.)

d = 1 && 1(El resultado final de la expresión será un valor verdadero)

d = 1 (por ultimo se realiza la asignación a la variable d)

Ejemplo 4:

Dado a = 1, b = 2 efectúe la siguiente expresión: d = a++ > 5 / 2 || 3 * --b < ( 3 + a)

Se resuelve tomando encuentra la precedencia de los operadores y su asociatividad. A pesar de que el operador lógico || tiene menor prioridad obliga a resolver la expresión mas a la izquierda a++ > 5 / 2, aunque el las operación decremento prefijo tenga mayor prioridad.

d = a++ > 5 / 2 || 3 * --b < (3 + a)(Resolvemos la expresión a++ > 5 / 2)a++ > 5 / 2

(La operación incremento sufijo por tener menor prioridad se resuelve después de todas las operaciones siendo resuelta después de finalizar toda la expresión a++ > 5 / 2, se asigna el valor de la variable a)

1 > 5 / 2 (se resulte la operación aritmética de mayor precedencia 5 / 2 y luego la operación relacional 1 > 2, siendo falsa)

d = 0 || 3 * --b < (3 + a)(Antes de resolver la próxima expresión primero se realiza el incremento de sufijo, dando como resultado el valor a en 2)(Resolvemos la expresión a++ > 5 / 2)3 * --b < (3 + a)

(El paréntesis denota prioridad en la expresión por lo cual se deberá resolver la operación 3 + a antes, sustituyendo la variable por su valor 2 el resultado es 5)

3 * --b < 5(Se resuelve la operación de mayor prioridad –b el cual decrementará en memoria inmediatamente el valor de la variable b)

3 * 1 < 5

(Resolvemos la operación aritmética y luego la operación relacional dando como resultado un valor verdadero)

d = 0 || 1(El resultado final de la expresión será un valor verdadero)

d = 1 (por ultimo se realiza la asignación a la variable d)

Sentencias

Las sentencias son unidades completas, ejecutables en si mismas. Existen muchos tipos de sentencias que incorporan expresiones aritmeticas, logicas 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.

Sentencias Simple

Una sentencia simple es una expresion de algun tipo terminada por un carácter (;). Por ejemplo las declaraciones o las sentencias aritmeticas.

flota real;area = base * altura;

Sentencia vacía 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 carácter (;). Por ejemplo:

;

Sentencia compuesta

Es un conjunto de declaraciones y de sentencias agrupadas dentro de llaves {…}. Tambien 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;}

Operaciones de entrada y salida estándar.

Cuando nos referimos a entrada/salida estándar (E/S estándar) queremos decir que los datos o bien se están leyendo del teclado, ó bien se están 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.

En el lenguaje c++ tenemos varias alternativas para ingresar y/o mostrar datos, dependiendo de la librería que vamos a utilizar para desarrollar el programa, entre estas están: iostream.h, stdio.h, conio.h.

< IOSTREAM.H>

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 estándar de C++. Ellas se incluyen en los archivos de cabecera iostream.h por lo que siempre que queramos utilizarlas deberemos introducir la línea de código: #include <iostream.h>

   Esta biblioteca es una implementación 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.

 Los objetos de flujo que vienen predefinidos serán:cin, que toma caracteres de la entrada estándar (teclado); cout, pone caracteres en la salida estándar (pantalla); cerr y clog, ponen mensajes de error en la salida estándar.

Estos objetos se utilizan mediante los operadores << y >>.

Salida estandar (cout)

La salida estandar en C++ es la pantalla de nuestro ordenador. El objeto asociado con dicha salida estandar es cout.

El objeto cout emplea al operador de inserción "<<" y apunta al objeto donde tiene que enviar la información. 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 linea podemos emplear el código de escape '\n' o bien el manipulador "endl".

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

Entrada estadar (cin)

El dispositivo de entrada estandar como podemos suponer es el teclado de nuestro ordenador. Para extraer datos desde el teclado empleamos el objeto "cin", que se utiliza en conjunción con el operador de extracción representado como ">>", lee información del flujo cin (a la izquierda del operador) y las almacena en las variables indicadas a la derecha). La sintaxis sería la siguiente:

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

       Un ejemplo de código utilizando ambos objetos podría ser el siguiente:

#include <iostream.h>...main ()

{    int i;    cout<<"Introduce un número";    cin>>i;    ...}...

Muestra por pantalla la frase "Introduce un número" y posteriormente almacenaría el valor introducido por teclado en la variable i.

<STDIO.H> Esta librería incorpora las sentencias de entrada y salida basicas como son la sentencia scanf y la sentencia printf, denominadas sentencias de entra y salida con formato.

Salida estandar (printf)

La rutina printf permite la aparición de valores numéricos, 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, también 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 carácter % seguido por un carácter de conversión indica de que tipo de dato se trata.

Ejemplo:

printf("Color %s, num1 %d, num2 %5d, real %5.2f.\n", "rojo", 123, 89, 3.14);

Imprimirá la siguiente línea (incluyendo el caracter de nueva línea \n):

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

 Las letras de control de formato mas usadas son:

‘c’Esto imprime un número como un carácter ASCII. Por lo que, `printf "%c", 65' imprimiría la letra ‘A’. La salida para un valor cadena es el primer carácter de la cadena.

‘d’ Esto imprime un entero decimal.

‘i’ Esto también imprime un entero decimal.

‘e’

Esto imprime un número en notación científica (exponencial). Por ejemplo, printf "%4.3e", 1950imprime ‘1.950e+03’, con un total de 4 cifras significativas de las cuales 3 siguen al punto decimal. Los modificadores ‘4.3’ son descritos más abajo.

‘f’ Esto imprime un número en notación punto flotante.

‘g’Esto imprime en notación científica o en notación punto flotante, la que quiera que sea más corta.

‘o’ Esto imprime un entero octal sin signo.

‘s’ Esto imprime una cadena.

‘x’ Esto imprime un entero hexadecimal sin signo.

‘X’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 minúsculas.

‘%’

Esta no es realmente una letra de control de formato. Pero tiene un significado especial cuando se usa después de un ‘%’: la secuencia ‘%%’ imprime el carácter ‘%’. No consume ni necesita ningún item o argumento correspondiente.

El formato completo de los modificadores es el siguiente:

% [signo][longitud][.][precisión] carácter de conversión.

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 máxima del valor que aparece en por pantalla. Si la longitud máxima del valor que aparece por pantalla. Si la longitud es menos que el número de dígitos del valor, este aparecerán ajustado a la izquierda.Precisión: Indicamos el numero máximo de decimales que tendrá el valor.

La sentencia printf puede incluir caracteres especiales o secuencias de escape que permitan modificar la impresión de los datos.

Caracteres especiales más utilizados:

\n // salto de línea\t // tabulador horizontal\v // tabulador vertical\b // retroceso\r // retorno de carro\f // salto de página\a // alerta (campana)\\ // carácter \\? // interrogante\' // comilla simple\" // comilla doble\ooo // carácter ASCII dado por tres dígitos octales (ooo serán dígitos)\xhh // carácter ASCII dado por dos dígitos hexadecimales (hh serán dígitos)\0 // carácter nulo

 Los argumentos de la sentncia de entrada pueden estar representados por operaciones o sentencias. La sentencia printf resulte estas operaciones antes de ejecutar la etapa de control. Se resolveran los argumentos de derecha a izquierda unas vez finalizados se resuelve la etapa de control de izquierda a derecha.

int edad = 5;printf ("edad 2: %d, edad 1: %d, edad inicial: %d", edad, ++edad, edad++);

Muestra por salida:

edad 2: 7, edad 1: 7, edad inicial: 5

Entrada estadar (scanf)

La rutina scanf permite entrar datos en la memoria del ordenador a través 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 harán referencia al tipo de dato de los argumentos. Al igual que en la sentencia printf los modificadores, estarán formado por el carácter % seguido de un carácter de conversión. Los argumentos indicados serán, nuevamente las variables. La principal característica de la sentencia scanf es que necesita saber la posición de la memoria del ordenador en que se encuentra la variable para poder almacenar la información obtenida, para indicarle está posición utilizamos el símbolo ampersand (&), aunque colocaremos delante del nombre de cada variable (esto no es necesario en las cadenas de caracteres o punteros).

Ejemplo:

include<stdio.h>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

<CONIO.H>

Esta librería incorpora las sentencias de entrada y salida simples como lo son: getch, getche, getchar, gets, putchar, puts.

Sentencias de salida

puts

Esta sentencia muestra por la salida estandar una cadena de caracteres y salta a la proxima linea, su sintaxis:

char cadena[25]=”Casa”; // se declara una cadena de caracteres {‘C’,’a’,’s’,’a’,’\0’}puts(cadena); // Muestra los caracteres de cadena hasta encontra el fin de cadenaputs(100); // Muestra los caracteres desde la posición de memoria 100 hasta // encontrar el carácter de fin de cadenaputs(“cadena”); // Muestra la palabra: cadena por pantalla

putchar

Esta sentencia muestra por la salida estandar un caracteres, su sintaxis:

char car = ‘65’; putchar (car); // Muestra por pantalla el carácter ‘A’putchar (65); // Muestra por pantalla el carácter ‘A’

Sentencias de Entrada

gets

Esta sentencia lee y guarda una cadena introducida por la entrada estandar, su sintaxis: char cadena[25

puts(“Ingrese un nombre:”); gets(cadena); // Envia los caracteres a partir de la posición de memoria de la cadena // y transforma el carácter intro en un carácter fin de cadena

puts(cadena); // Muestra lo que se ingreso por la entrada en pantalla

getchar

Esta sentencia lee y retorna cuando se presione la tecla intro, un único caracter introducido mediante el teclado y salta a la proxima linea. Muestra el caracter por la pantalla. Su sintaxis:

char letra;letra=getchar( ); // atrapa un carácter y lo retorna después desl carácter intro

getch

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

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

getche

Esta sentencia lee y retorna un único caracter introducido mediante el teclado por el usuario al igual que la sentencia getch pero a diferencia esta si muesta el carácter por pantalla. Su sintaxis:

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

Tipos de estructuras de control

El C++, como todo lenguaje de programación basado en la algorítmica, posee una serie de estructuras de control para gobernar el flujo de los programas.

Debemos recordar que la evaluación de una condición producirá como resultado un cero si es falsa y un número cualquiera distinto de cero si es cierta, este hecho es importante a la hora de leer los programas, ya que una operación matemática, por ejemplo, es una condición válida en una estructura de control.

Las estructuras de control basicas las podemos dividir en: sentencias de control selectivas y las sentencias de control iterativo o ciclos.

Estructuras de control selectivas: if, if-else, switch

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 esta asociada a una condicion, se decide que camino tomar dependiendo siempre del resultado de la condicion siendo esta falsa o verdadera. Cuando se termina de ejecutar este bloque de instrucciones se reanuda la ejecución en la instrucción siguiente a la de la condicional.

Dentro de las estructuras de selección encontramos en el C++, las de condición simple (sentencia if y sentencia if-else) y las de condición múltiple (switch).

La sentencia if o condicional simple

Es una sentencia condicional simplea cuya traducción es: si la expresion a evaluar es verdadera realiza las instrucciones que controle dicha sentencia. Si el resultado de la expresión es falso el flujo del programa continuará con las sentencias debajo del if. Su sintaxis es:

      if(expresión)    {     //sentencias    }

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

if(expresión)    sentencia_unica;

Podemos representar esta sentencia con el siguiente diagrama,

donde se muestra que solo se realizara la sentenca 1 si el resultado logico de la expresion es verdadera de no serlo continua el flujo del progama.

Ejemplo 1:

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

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

Ejemplo 2: Determine si un numero es igual mayor o menor que cero

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

int numero;cout<<"Ingrese un numero:";cin>>numero;if(numero == 0) //La condicion indica que tiene que ser igual a Cero { cout<<"El Numero Ingresado es Igual a Cero"; }if(numero > 0) // la condicion 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"; }

}

La sentencia if…else o bicondiciona

Esta estructura cumple las mismas caracterisiticas de la sentencia if, cuando la condicion es verdadera realizara una sentencia o conjuto de sentencias, pero si esta es falsa realizara realizaracondicion o condicones.

    if (expresión)   {      //sentencias    }   else   {     // sentencias   }

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

if(expresión)    sentencia_unica1; else

sentencia_unica2;

Podemos representar esta sentencia con el siguiente diagrama,

donde se muestra que solo se realizara la sentenca 1 si el resultado logico de la expresion es verdadera, pero si esta no se cumple realiza la sentencia 2, una vez realice alguna de las sentencias dado el resultado de la expresion de no serlo continúa el flujo del progama.

De esta manera podemos mostrar el siguiente ejemplo: 

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

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

Las sentencias pueden controlar otras sentencias de control secuencial permitiendo evaluar los procesos solo cuando sean necesarios. Por ejemplo si queremos deteminar si un número 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) //La condicion indica que tiene que ser igual a Cero { cout<<"El Numero Ingresado es Igual a Cero"; } else if(numero > 0) // la condicion indica que tiene que ser mayor a Cero

{ cout<<"El Numero Ingresado es Mayor a Cero";}else // la condicion indica que sino es igual o mayor tiene que ser menor { cout<<"El Numero Ingresado es Menor a Cero"; }

}

La sentencia switch

Sirve para seleccionar una de entre múltiples alternativas de acuerdo al valor de una expresión. La sentencia switch es especificamente útil cuando la selección se basa en el valor de una variable simple o de una expresión simple denominada expresión de control o selector. Su sintaxis:

swicth (expresion){   

case valor_expresion_1: //sentencias 1break;

case valor_expresion_2: //sentencias 2break;

....case valor_expresion_n:

//sentencias nbreak;

default: //sentencias x

}

Podemos representar esta sentencia mediante el diagrama siguiente,

donde dado el valor de la expresion realizara las operaciones y continuara con el flujo del programa.

Esta sentencia la podemos representar usando sentencias anidadas if…else, si la sentencia break no fuese utilizada entonces se representaria por un conjunto de sentencias if una tras otra.

 Como verán 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;break;

}

Como x es igual a 3 el case efectuará la operación 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 academico del alumno.

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

char letra;cout<<"Ingrese la Calificación 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 condición. 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é función se ejecuta dependiendo del valor de c.

Si se pulsa Se ejecuta las funciones

1 Funcion2() y Funcion3()2 Funcion2() y Funcion3()3 Funcion3()4 Funcion4_1() y Funcion4_2()5 Funcion5() y FuncionX()Otra cosa FuncionX()

Estructuras de control iterativas: for, while, do-while.

Las Sentencias de Iteración o Ciclos son estructuras de control que repiten la ejecución de un grupo de instrucciones. Básicamente, una sentencia de iteración es una estructura de control condicional, ya que dentro de la misma se repite la ejecución de una o más instrucciones mientras o hasta que una a condición especifica se cumpla. Muchas veces tenemos que repetir un número 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 número de veces que una o más sentencias han de repetirse. Por otro lado, la sentencia while es útil en aquellos casos en donde no se conoce de antemano el número de veces que una o más sentencias se tienen que repetir.

Sentencia for

Es un bucle o sentencia repetitiva que:i. Ejecuta la sentencia de inicio

ii. Verifica la expresión booleana de condicion término.

a. si es cierta, ejecuta la sentencia entre llaves y la sentencia de iteración para volver a verificar la expresión booleana de condicion de término

b. si es falsa, sale del bucle.

Podemos representar el flujo de la sentencia en el siguiente diagrama:

Sintaxis:

for (inicio; condicion; iteracion)sentencia;

o si se desean repetir varias sentencias:

for (inicio; condicion; iteracion) {

sentencia_1;sentencia_2;sentencia_n;

}

Vemos que la sentencia for tiene tres secciones: inicio, en dónde se da un valor inicial a una variable o variables de control del bucle; condición, que es una expresión que devuelve un valor verdadero o falso, y hace que el bucle se repita mientras sea cierta y salga de este solo cuando la condicion sea falsa; e iteracion, en dónde se determina el cantidad del incremento o decremento de la variable o variables de control. Las tres secciones están 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 sólo son necesarias si se quieren repetir varias sentencias, aunque se recomienda su uso porque facilita la lectura del código fuente y ayuda a evitar errores al modificarlo.

Habitualmente, en la expresión lógica de condicion de término 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 pantallalos números del 1 al 10 y sus cuadrados.

int i;......for (i = 1; i <= 10; i++) {

printf ("\nValor de i: %d", i);printf ("\nValor de i2: %d", i * i);

}

En estasecuencia, se muestran en pantalla las letras mayúsculas 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 números pares comprendidos entre 1 y 100, descendentemente:

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

Es posible tener más de una variable de control del bucle:

En el bucle for las secciones de inicialización 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 números 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++) {

...for (j = 0; j <= 100; j++) {

cuerpo_del_bucle;}...

}

La condición 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 números 1, 2,... hasta que se teclee el carácter s.

El bucle for puede no tener cuerpo. Esta característica permite crear retardos en un programa.

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

El bucle provoca un retardo de 100 ciclos, saldra del bucle cuando la variable sea mayor o igual a100.

El bucle for puede tener vacía cualquier sección: 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; ) { /* Falta la 3ª sección (incremento) */

scanf ("%d", &i);printf ("\n%d", i);

}

que va mostrando en pantalla los valores que se tecleen, finalizando al teclear el número 10 (que también se visualiza).

También es correcto 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 número: ");scanf ("%d", &n);if (!n) break;printf ("\nEl cuadrado es %d", n * n);

}}

Sentencia while

La sentencia while tiene una condición del bucle (una expresión lógica) que controla la secuencia de repetición. La sentencia evalua la condición antes de que se ejecute el cuerpo del bucle si se cumple la condicion realiza los procesos que controla la sentencia sino sale y continua con el flujo del programa.

El cuerpo del bucle no se ejecutará nunca si la primera vez no se cumple la condición. El bucle puede ser infinito si no se modifican adecuadamente las variables de la condición dentro del bucle.

Sintaxis:

while ( condición ) {

sentencias .......... ; }

Veamos algunos ejemplos.

En esta sentencia se solicita un carácter del teclado mientras no se teclee el carácter n ni el carácter 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 mantendra en el ciclo hasta que se teclea el carácter s.

while (getch () !=’s’);

El siguiente programa utiliza un bucle while para solicitar del usuario que adivine un número.

Realizar un programa que muestre los numero del 1 al 100.

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

clrscr(); //limpia la pantalla int contador=0;while ( contador < 100 ) {

contador++;cout<<"\t "<<contador;

}cout<<"Presione Enter para salir";getch();// espera una tecla para continuar con la siguiente linea

}

Las sentencias for y while son equivalentes:

Equivalente a la sentencia while:for ( ; condicion ; ) {

sentencias; }

Equivalente a la sentencia for:

inicio;while ( condición ) {

sentencias;iteraciones;

}

Ejemplo 1: Determine si un numero es capicuo (se lee igual en ambos sentidos).

Usando la sentencia while Usando la sentencia for#include <conio.h>#include <iostream.h>main(){ clrscr(); //limpia la pantalla int num, inv, aux; cout<<”Ingrese un numero:”; cin>>num; aux = num; inv = 0; while ( aux > 0 ) { / / se separan los digitos y se invierten

inv = inv * 10 + aux % 10; aux = aux / 10;

} if(num == inv) cout<<"El numero es capicuo”; else cout<<"El numero no es capicuo”; getch();}

#include <conio.h>#include <iostream.h>main(){ clrscr(); //limpia la pantalla int num, inv, aux; cout<<”Ingrese un numero:”; cin>>num; for(aux=num, inv=0; aux>0; aux=aux/10) { / / se separan los digitos y se invierten

inv = inv * 10 + aux % 10; } if(num == inv) cout<<"El numero es capicuo”; else cout<<"El numero no es capicuo”; getch();}

Ejemplo 2: Muestre un cuadro usando el carácter ’x’ y una dimension n. Sera necesario usar sentencia anidadas para dezplar el cursor de manera horizontal y vertical.

Usando la sentencia while Usando la sentencia for#include <conio.h>#include <iostream.h>main(){ clrscr(); int i, j, n; cout<<”Ingrese la dimension:”; 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<<” ”;

#include <conio.h>#include <iostream.h>main(){ clrscr(); //limpia la pantalla int i, j, n; cout<<”Ingrese la dimension:”; cin>>num; for(i = 0; i < n ; i++) { / / recorre las filas for(j = 0; j < n; j++) { / / recorre las columnas if(i==0 || i==n-1|| j==0|| j==n-1) cout<<"x”; else cout<<” ”; }

j++; } cout<<endl; i++; } getch();}

cout<<endl; } getch();}

Sentencia do-while

La sentencia do - while se utiliza para especificar un bucle condicional que se ejecuta al menos una vez. Esta situación se suele dar en algunas circunstancias en las que se ha de tener la seguridad de que una determina acción se ejecutara una o varias veces, pero al menos un vez.

El flujo de ejecución es el siguiente:

En esta sentencia a diferencia de la sentencia for y while, primero realizara las sentencias que controle una vez realizada evaluara la condicion, si esta es verdadera volvera a realizar las sentencias hasta que la condicion en algun momento sea falsa.Las sentencias se ejecuta al menos una vez, incluso aunque expresión se evalúe como falsa, puesto que la evaluación se hace al final, a diferencia de la sentencia while y for, en el que la evaluación de la condicion se hace al principio.

Sintaxis:

do{ sentencias; }while(condición);

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>main()

{ clrscr(); int nota1, nota2; do{

cout << "Ingrese las Notas: "; cin>>nota1>> nota2; }while(((nota1<=20)&&(nota1>=0))&&((nota2<=20)&&(nota2>=0))); cout<<"El promedio de las nontas es:"<<(nota1+nota2)/2; getch();}

En el siguiente ejemplo se solicita un carácter 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');}

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 más interno. A todos los efectos la sentencia break actúa como un salto a la instrucción siguiente al bucle en el que se ejecuta.

La sentencia continue

La sentencia continue, no abandona el bucle si no hace que se ejecute la siguiente iteración. En el bucle while la ejecución del continue hace que el flujo del programa salte a la condición. En el bucle for la ejecución del continue hace que la expresión de incremento, para después continuar normalmente con la condición. Es decir, la ejecución 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, saltándose cualquier sentencia posterior. Por ejemplo, el bucle

int i, n;......for (i = 1; i <= 100; i++) { n = i / 2;

if (i == 2 * n) continue; printf ("\n%d", i);}

muestra en pantalla sólo los números impares, puesto que para los números pares la expresión i == 2 * n se evalúa como cierta, ejecutándose la sentencia continue que fuerza de inmediato un nuevo ciclo del bucle.

Arreglos: definición, clasificación.

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 manipulación de dichos datos, ya que los datos en memoria pueden ser modificados, clasificados, marcados para su eliminacion, etc. para luego ser reescritos al disco.

Un arreglo (array) es una colección de datos del mismo tipo, que se almacenan en posiciones consecutivas de memoria y reciben un nombre común. Para diferenciar cada elemento de un arreglo se utiliza un indice, que especifique su posición relativa en el arreglo.

Los índices son números que se utilizan para identificar a cada uno de los componentes de un arreglo. Por ejemplo podemos pensar en los casilleros, asi que si deseamos guardar o retirar un paquete nos dirijimos al casillero el cual sería el arreglo; y dado el número específico el cual representa el índice para identificar el lugar del casillero en donde quedó guardado el paquete.

Un arreglo es una colección finita, homogénea y ordenada de elementos.

- Finita: Todo arreglo tiene un límite; es decir, debe determinarse cuál será el número máximo de elementos que podrán formar parte del arreglo.

- Homogénea: Todos los elementos del arreglo deben ser del mismo tipo. - Ordenada: Se puede determinar cuál es el primer elemento, el segundo, el tercero,....

y el n-ésimo elmento.

Declaración de arreglos

Para declarar un arreglo se emplea la sintaxis:

tipo identificador[ [tamaño] ] [ = { lista de inicialización } ] ;

donde,

- tipo se refiere al tipo de datos que contendrá el arreglo. El tipo puede ser cualquiera de los tipos estándar (char, int, float, etc.) o un tipo definido por el usuario. Es más, el tipo del arreglo puede ser de una estructura creada con: struct, class.

- identificador se refiere al nombre que le daremos al arreglo.- tamaño es opcional e indica el número de elementos que contendrá el arreglo. Si un

arreglo se declara sin tamaño, el mismo no podrá contener elemento alguno a menos que en la declaración se emplee una lista de inicialización.

- lista de inicialización es opcional y se usa para establecer valores para cada uno de los componentes del arreglo. Si el arreglo es declarado con un tamaño especifíco el número de valores inicializados no podrá ser mayor a dicho tamaño.

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}};

Clasificacion de los arreglos

Los arreglos los podemos clasifican de acuerdo con el número de dimensiones que tienen. Así se tienen los:o Unidimensionales (vectores): representados por una colección de elementos con un

mismo nombre y diferenciados por un indice.o Multidimensionales: Bidimensionales (tablas o matrices) y Tidimensionales.

Representados por colecciones de arreglos unidimensionales (matrices) o multiples matrices.

Arreglos unidimensionales, multidimensionales.

Arreglos unidimensionales

Los arreglos unidimensionales pueden ser apreciados en la vida cotidiana como por ejemplo un armario el cual esta dividido por gavetas, una cola de personas que realizan un mismo proceso como la compra de un mismo articulo, etc.

Los arreglos unidimensionales son una colección de variables del mismo tipo, con un mismo nombre y diferenciadas a traves de un indice.

El formato para declarar un arreglo unidimensional es:

tipo nomb_arr [tamaño] [ = { lista de inicialización } ]; //La lista es opcional

donde, el tamaño representa la dimension o cantidad de elementos o variables del mismo tipo que componen al arreglo.

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 utilizadas referenciando su indice. 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 atraves de este, es decir si se quiere realizar alguna operación sobre el arreglo es necesario utilizar sentencias iterativas que permitan recorrer el arreglo desde una posición a otra.

Sea la declaracion 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 desplarzarnos por cada una de las variables desde la posición 0 hasta la posición 9.

// leer los 10 elementos del arreglo Aint i;for (i = 0; i < 10; i++){ cout<<”Ingrese el elemento A[”<<i<<”]:”; cin>>A[i];}

// asignar a los 10 elementos del arreglo B el mismo valor del arreglo Aint 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 posición correspondiente, en la siguiente sentencia se utilizara el metodo de la burbuja el cual conciste en comparar un elemento con el siguiente y dependiendo del criterio de comparación y valor de peso este sera cambiado o no.

int i, cambio, aux, n=10;do{ // la sentencia do nos indica la cantidad de veces necesarias para ordenar

cambio = 0; //si su valor se mantiene en cero el arreglo estara ordenadofor (i = 0; i < n-1; i++) // el ultimo elemento no sera 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);

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 numeros enteros.

#include <conio.h>#include <iostream.h>#define max 100main(){ clrscr(); //limpia la pantalla 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 numeros { cout<<”Ingrese el numero[”<<i+1<<”]:”; cin>>num[i]; } for(i = 1, mayor= num[0], menor=num[0]; i < n; i++) { // compara los numeros y los guarda sea el resultado if(mayor < num[i]) mayor = num[i]; if(menor > num[i]) menor = num[i];

} cout<<"El numero mayor: ”<<mayor<<” y el menor: ”<<menor<<endl; getch();}

Arreglos multidimensionales

Se podran definir arreglos de mayor dimension, arreglos bidimensionales y declaración tridimensionales como sigue:

tipo_de_dato identificador[tamaño1][tamaño2]…;

dónde:

tipo_de_dato: Es el tipo de datos que contendrá la matriz. Hasta ahora sólo conocemos los tipos básicos de datos; int, float, double, char. Posteriormente veremos como definir nuestros propios tipos de datos.

identificador: Es el nombre que le damos a la variable matriz y po el cual la referenciaremos en nuestro programa.

[tamaño] : Indica el número de elementos de tipo tipo_de_datos contendrá la matriz identificador. Si se definen 2 dimensiones (arreglo bidimensional), la cantidad total sera igual al producto de ambas dimensiones.

Arreglo bi-dimensional

Una arreglo bi-dimensional 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 también con el nombre de matrices. Conceptualmente, podemos pensar en un arreglo bidimensional como en una lista compuesta de filas y columnas, en donde para referinos a una de ellas emplearemos un número para indicar la posición de fila y otro número para indicar la posición de la columna del componente deseado.

Se le conocen comúnmente como matrices o tablas. La primera dimensión establece la cantidad de filas. La segunda dimensión establece la cantidad de columnas. Al igual que en los arreglos de una dimensión, todos los datos seran del mismo tipo y nombre y diferenciada por dos indices.

Arreglo tri-dimensional

Los arreglos tridimensionales estan compuestos por tres dimensiones donde la primera dimension representa la cantidad de arreglos bidimensionales, la segunda dimension representa la cantidad de arreglos unidimensionales y la tercera dimension representa la cantidad de elementos que contiene cada arreglo unidimensional. Permite realizar representaciones en tres planos.

Para declarar un arreglo bidimensional, matriz o tabla:

tipo_de_dato nomb_matriz[fila][columnas];

Para declarar un arreglo trididimensional:

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

Ejemplo: Algunas declaraciones de matrices y arreglos tridimensionales serían:

/* Matriz de números reales de 10x10 */float matriz[10][10];

/* Matriz tridimensional de números enteros 20x20x10 */int Tridimensional[20][20][10];

Como ya se supondrá el acceso a cada elemento de la matriz se realiza especificando su posición, pero ésta comienza a contarse desde el valor 0, es decir, la primera

matriz que hemos definido (matriz) tendrá elementos desde el [0][0] al [9][9]. Esto puede causar algunos mal entendidos cuando se trabaja con matrices estáticas. Por ejemplo:

a = matriz [2][1];

/* A toma el valor del elemeto (2,1) comenzando a contar desde 0 o del (3,2) si consideramos que el primer valor de la matriz es el (1,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 declaración, ayudándose de las llaves ({}) para la inclusión de inicializaciones múltiples.

int matriz[2][3] = { { 1,2,3 }, { 4,5,6 } };

Estas líneas nos declararían una matriz llamada "matriz" de 2x3 elementos inicializada con los valores indicados. Las matrices son extremadamente útiles para trabajar con multitud de problemas matemáticos 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 rápida.

A igual que los arreglos unidimensionales, los arreglos multidimensionales utilizaran sentencias iteractivas anidadas para cada una de las dimensiones.

Ejemplo: Realice un programa que lea una matriz de n * n elementos enteros y muestre cuantos de estos elementos son primos.

#include <conio.h>#include <iostream.h>#define max 100main(){ clrscr(); //limpia la pantalla int num[max][max]; int i, j, n, div, contprimos; do { cout<<”Ingrese la cantidad de numeros 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++) // recorre las columnas

{ for(div=2;div<num[i][j] && num[i][j]%div!=0; div++); if(div==num[i][j]) contprimos++; }

cout<<"En la matriz hay : ”<<contprimos<<” numeros primos”<<endl; getch();}

Se permite la inicialización de arreglos, debiendo seguir el siguiente formato:

tipo nombre_arr[ tam1 ][ tam2 ] ... [ tamN] = {lista-valores};

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}}};

Cadenas de caracteres.

Una cadena es un conjunto de caracteres, o valores de tipo "char", terminados con el carácter nulo, es decir el valor numérico 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 de caracteres cualesquiera, es que la cadena de caracteres tiene como último carácter al carácter nulo \0.

La manera de definir una cadena es la siguiente:

char <identificador> [<longitud máxima>];

Por ejemplo, si se declara el arreglo:

char cadena[8];

podemos 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 carácter nulo, el arreglo cadena será reconocido por las funciones y objetos diseñados para manipular cadenas de caracteres.

Para manejar y realizar operaciones con las cadenas de caracteres es necesario realizar sentencias de recorido hasta encontrar el carácter fin de cadena. Lo que lo diferencia de los arreglos numericos que es necesario conocer la cantidad de elementos a evaluar.

Un arreglo es necesario lee y mostrar cada elemento uno a uno en el caso de las cadenas solo es necesario usar una funcion que atrape cadenas de caracteres, ejemplo:

char cadena[10];get ( cadena); // Lee una cadena de caracteres cin>>cadena; // Lee una cadena y tranforma el carácter espacio en’\0’scanf(”%s”, cadena); // Lee una cadena y tranforma el carácter espacio en’\0’cout<<cadena; // muestra todos los caracteres hasta el carácter final

Realice un programa que lea una frase y cambie un carácter de la frase por un nuevo carácter.

#include <conio.h>#include <iostream.h>#define max 100main(){ clrscr(); char frase[max]; char carV, carN; cout<<”Ingrese una frase:” gets(frase); cout<<”Ingrese el carácter a modificar:” carV = getch(); cout<<”Ingrese el nuevo nuevo caracter:” carN = getch(); for(i = 0; frase[i] !=’\0’ ; i++) if( frase[i] ==carV) frase[i] = carN ; cout<<"La nueva frase es : ”<<frase<<endl; getch();}

Para manejar un arreglo de cadenas de caracteres se debe declarar como un arreglo bidimensional de elementos de tipo char, como por ejemplo: #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 mas un caracter para el nulo.

clrscr(); for( int x=0 ; x < 10 ; x++) { gotoxy(10,x+1); // posicionan el cursor en la posicion (x, y) cout << "NOMBRE [" << x << "] = " ; cin >> nombre[x]; gotoxy(45,x+1); cout << "CALIFICACION [" << x << "] = " ; cin >> calif[x]; } }

Cuando se tiene un arreglo de cadenas de caracteres, se puede utilizar para asignar valores en la declaracions constantes de cadena.

Por Ejemplo:

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

es equivalente a:

char nombres[3][5];

nombres[0] = "HUGO" ; nombres[1] = "PACO" ; nombres[2] = "LUIS" ;

Esto también 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 dimensión de los arreglos cuando, en su declaración, 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 sólo agregarlas a la lista o eliminarlas de ella.

Además de las funciones gets() y puts(), existe otro grupo de funciones para el manejo de cadenas de caracteres, como strlen() y strupr(). Los rototipos de estas funciones se encuentran declarados en el archivo STRING.H En la tabla 5.1 se describen brevemente algunas de las funciones para el manejo de cadenas de caracteres en el C++ de Borland, cuyos prototipos se encuentran declarados en el archivo STRING.H .

FUNCION DESCRIPCION

stpcpy Copia una cadena de caracteres en otra.Se detiene cuando encuentra el terminador nulo.

strcat Añade una cadena de caracteres a otra.

strchr Busca, en una cadena, un caracter dado.

strcmp Compara dos cadenas.

strcmpi Macro que compara dos cadenas sin distinguir entre mayúsculas y minúsculas.

strcpy Copia una cadena.

strcspn Busca segmentos que no contienen un subconjunto de un conjunto especificado de caracteres.

strdup Copia una cadena a una nueva localidad.

_strerror Genera un mensaje de error definido por el programador.

strerror Retorna el apuntador al mensaje asociado con el valor del error.

stricmp Compara dos cadenas sin diferenciar entre mayúsculas y minúsculas

strlen Determina la longitud de una cadena.

strlwr Convierte las mayúsculas de una cadena en minúsculas.

strncat Añade el contenido de una cadena al final de otra.

strncmp Compara parte de una cadena con parte de otra.

strncmpi Compara parte de una cadena con parte de otra, sin distinguir entre mayúsculas y minúsculas.

strncpy Copia un un número de bytes dados, desde una cadena hacia otra.

strnicmp Compara parte de una cadena con parte de otra, sin distinguir entre mayúsculas y minúsculas.

strnset Hace que un grupo de elementos de una cadena tengan un valor dado.

strpbrk Busca la primera aparición, en una cadena, de cualquier caracter de un conjunto dado.

strrchr Busca la última aparición de un caracter en una cadena.

strrev Invierte el orden de los caracteres de una cadena.

strset Hace que los elementos de una cadena tengan un valor dado.

strspn Busca en una cadena el primer segmento que es un subconjunto de un conjunto de caracteres dado.

strstr Busca en una cadena la aparición de una subcadena dada.

_strtime Convierte la hora actual a una cadena.

strtod Convierte una cadena a un valor double ó long double.

strtol Convierte una cadena a un valor long.

strtoul Convierte una cadena a un valor unsigned long.

strupr Convierte las minúsculas de una cadena a mayúsculas.

Funciones para el manejo de cadenas de caracteres.

Referencias de memoria.

Las referencias.

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 características de los punteros pero tratándolos como variables ordinarias. Podéis imaginaros una referencia como un "alias" de una variable o, mejor dicho, como la misma variable disponible pero con un nombre distinto. ¿Vaya lío no? ;).Pasemos a explicar cómo se utilizan las referencias para no armarnos tanto "bollo" en nuestra cabeza "programadora"...La inicialización de una referencia es bien fácil ya que sólo tendremos que asociar la referencia que deseemos a otra variable que ya esté creada por nosotros. Una vez que hemos realizado tal inicialización, la referencia va a estar continuamente asociada con su variable correspondiente. Cabe añadir que, si quisiéramos hacer que nuestra referencia fuese el "alias" de otra variable o lo que es lo mismo que referenciase a otra variable no podríamos, tendríamos un error de compilación.

La declaración de una referencia es bien sencilla:// dato es una variable definida por// nosotros y es de tipo entero.int dato;

// referenciaDato es la referencia que hemos creado.int& referenciaDato = dato; Como podéis observar para crear una referencia no necesitamos más 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 símbolo &. De este modo, referenciaDato es la referencia o alias de la variable dato.

Una vez hechas las dos operaciones anteriores cualquier cambio que hagamos sobre dato se verá reflejado en referenciaDato y viceversa, es decir, si realizamos una modificación en referenciaDato, esta también se va a ver reflejada en la variable dato.¡Pongamos un ejemplo de todo esto!.#include <iostream.h>

void main(){ int dato = 50; int& refDato = dato;

cout << ‘\n’;

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 la// referenicia, ahora refDato = 101;refDato ++;

cout << "La variable dato vale " << dato << ’\n’;

cout << "La variable refDato vale " << refDato;

}

Si ejecutáis este programita veréis que la salida que se obtiene sería:

5050

100100

101101

Con lo que deducimos que los cambios efectuados en dato y refDato se ven involucrados. Debéis de saber que tanto dato como refDato comparten la misma dirección de memoria y por eso, cualquier cambio que efectuemos sobre dato afectará a refDato del mismo modo que si lo hiciéramos al revés.

Para cercioraros de que tanto la variable como la referencia poseen la misma dirección tan sólo tenéis que ejecutar este listado que os muestro a continuación y comprobar que la dirección de dato y refDato es la misma.

void main(){ int dato = 50; int& refDato = dato;

cout << ‘\n’ << "La dirección de la variable dato es " << &dato << ‘/n’;

cout << ‘\n’ << "La dirección de la referencia refDato es " << &refDato << ‘\n’;

}

Si lo ejecutáis veréis que salen los mismos valores. Una de las cosas que tenemos que tener bien claro es la utilización del operador unario & con una variable y con una referencia. Cuando declaramos una referencia estamos definiendo un tipo de datos que es exclusivo del C++, en este caso, el operador & va junto al tipo de datos que estamos definiendo como referencia así, si nosotros queremos crear una referencia que va a referenciar a una variable de tipo entero pondremos algo como int& referencia. Otro uso bien distinto es cuando lo que queremos obtener es la dirección en memoria de cierta variable o dato. En este caso tanto en C como en C++ el operador unario & se comporta de igual modo dándonos la dirección en memoria de tal variable o dato. Tan sólo tenéis que ejecutar el último de los listados expuestos el cual nos mostrará, por pantalla, la dirección en memoria de una variable de tipo entero y la de una referencia que tiene con alias precisamente tal variable de tipo entero.