INSTITUTO SUPERIOR TECNOLÓGICO “DAVID AUSUBEL” SEMIPRESENCIAL TECNOLOGÍA EN INFORMÁTICA GUÍA DIDÁCTICA ALGORITMOS COMPILADO POR: NIVEL Ing. FRANCISCO PUA BENAVIDES PRIMERO QUITO - ECUADOR 1 ÍNDICE UNIDAD 1: CONCEPTOS BÁSICOS 1.1 Visión histórica. 1.2 Planteamientos de problemas. 1.3 ¿Qué es un algoritmo? 1.4 Pensamiento algorítmico. 1.5 Representación de algoritmos. 1.6 Simbología de los diagramas de flujo. UNIDAD 2: FUNDAMENTOS DE PROGRAMACIÓN 2.1 Comentarios. 2.2 Identificadores. 2.3 Variables. 2.4 Constantes. 2.5 Contadores. 2.6 Acumuladores. 2.7 Palabras reservadas (primitivas). 2.8 Funciones matemáticas. 2.9 Tipos de datos. 2.10 Operadores. 2.11 Expresiones. 2.12 Procesos. 2.13 Interactividad. 2.14 Procedimientos. UNIDAD 3: ESTRUCTURAS BÁSICAS 3.1 Estructura secuencial. 3.2 Estructura iterativa (repetición). 3.3 Estructura condicional. UNIDAD 4: LENGUAJE C 4.1 Características del lenguaje C. 4.2 Estructura de un programa en C. 4.3 Tipos de datos. 4.4 Operadores aritméticos y de asignación. 4.5 Salida / entrada. 4.6 Operadores relacionales. 4.7 Sentencias condicionales. 4.8 Operadores lógicos. 4.9 Bucles. 4.10 Funciones. 4.11 Arrays. 4.12 Ejercicios. 2 UNIDAD 1 CONCEPTOS BÁSICOS 1.1 VISIÓN HISTÓRICA La palabra algoritmo se deriva de la traducción al latín de la palabra árabe alkhowarizmi, nombre de un matemático y astrónomo árabe que escribió un tratado sobre manipulación de números y ecuaciones en el siglo IX. 1.2 PLANTEAMIENTOS DE PROBLEMAS Lo que pretende un algoritmo es sintetizar de alguna forma una tarea, cálculo o mecanismo. Luego de analizar detalladamente un problema hasta entenderlo completamente, se procede a diseñar un algoritmo (trazar un plan) que lo resuelva por medio de pasos sucesivos y organizados en secuencia lógica. El concepto intuitivo de algoritmo (procedimientos y reglas) se puede encontrar en procesos naturales de los cuales muchas veces no se es consciente. Por ejemplo, el proceso digestivo es un concepto intuitivo de algoritmo con el que se convive a diario sin que haga falta una definición “matemática” del mismo. La familiaridad de lo cotidiano impide a las personas ver muchos algoritmos que se suceden a su alrededor. La rama del saber que mayor utilización ha hecho del enfoque algorítmico es las matemáticas. Durante miles de años el ser humano se ha esforzado por abstraer la estructura de la solución de problemas con el fin de determinar claramente cuál es el camino seguro, preciso y rápido que lleva a esas soluciones. Son abundantes los ejemplos: máximo común divisor, teorema de Pitágoras, áreas de figuras geométricas, división, suma de números fraccionarios, etc. Todos estos algoritmos matemáticos independizan los datos iniciales del problema de la estructura de su solución, lo que permite su aplicación con diferentes conjuntos de datos iniciales (variables). 1.3 ¿QUÉ ES UN ALGORITMO? En el ámbito de la computación, los Algoritmos son una herramienta que permite describir claramente un conjunto finito de instrucciones, ordenadas secuencialmente y libres de ambigüedad, que debe llevar a cabo un computador para lograr un resultado previsible. Vale la pena recordar que un programa de computador consiste de una serie de instrucciones muy precisas y escritas en un lenguaje de programación que el computador entiende (Java, C, C++, etc.). En resumen, un Algoritmo es una secuencia ordenada de instrucciones, pasos o procesos que llevan a la solución de un determinado problema. Los hay tan sencillos y cotidianos como seguir la receta del médico, abrir una puerta, lavarse las manos, etc.; hasta los que conducen a la solución de problemas muy complejos. 3 Ejemplo 1.1: Un procedimiento que se realiza varias veces al día consiste en lavarse los dientes. La siguiente sería la forma de expresar este procedimiento como un algoritmo: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. Tomar la crema dental. Destapar la crema dental. Tomar el cepillo de dientes. Aplicar crema dental al cepillo. Tapar la crema dental. Abrir la llave del lavamanos. Remojar el cepillo con la crema dental. Cerrar la llave del lavamanos. Frotar los dientes con el cepillo. Abrir la llave del lavamanos. Enjuagarse la boca. Enjuagar el cepillo. Cerrar la llave del lavamanos. Secarse la cara y las manos con una toalla. Fin. Ejemplo 1.2: El ejemplo de cambiar una bombilla (foco) fundida es uno de los más utilizados por su sencillez para mostrar los pasos de un algoritmo: 1. 2. 3. 4. 5. 6. 7. Ubicar una escalera debajo de la bombilla fundida. Tomar una bombilla nueva. Subir por la escalera. Girar la bombilla fundida hacia la izquierda hasta soltarla. Enroscar la bombilla nueva en el plafón hasta apretarla. Bajar de la escalera. Fin. En términos generales, un Algoritmo debe ser: Realizable: El proceso algorítmico debe terminar después de una cantidad finita de pasos. Se dice que un algoritmo es inaplicable cuando se ejecuta con un conjunto de datos iniciales y el proceso resulta infinito o durante la ejecución se encuentra con un obstáculo insuperable sin arrojar un resultado. Comprensible: Debe ser claro lo que hace, de forma que quien ejecute los pasos (ser humano o máquina) sepa qué, cómo y cuándo hacerlo. Debe existir un procedimiento que determine el proceso de ejecución. Preciso: El orden de ejecución de las instrucciones debe estar perfectamente indicado. Cuando se ejecuta varias veces, con los mismos datos iniciales, el resultado debe ser el mismo siempre. La precisión implica determinismo. Un aspecto muy importante sobre el cual las personas deben reflexionar es la ambigüedad del lenguaje natural que se utiliza para comunicarse diariamente con sus semejantes. Los algoritmos no admiten ningún tipo de ambigüedad ya que los lenguajes de programación tienen un vocabulario restringido y preciso. Esto exige la utilización de un conjunto determinado de palabras, mandos o primitivas en cualquiera de los procedimientos que se elaboren. 4 Actividad 1.1: Discutir en grupo el ejemplo de la bombilla y proponer algunas mejoras. Luego, un voluntario debe pasar al tablero para escribir el algoritmo con participación de toda la clase. 1.4 PENSAMIENTO ALGORÍTMICO El pensamiento Algorítmico incluye elementos tales como: “descomposición funcional, repetición (iteración y/o recursión), organización de datos (registro, campo, arreglo, lista, etc.), generalización y parametrización, diseño por descomposición de un problema en partes más pequeñas y manejables (top-down) y refinamiento”.1 Una diferencia notoria entre un algoritmo y un programa es que el algoritmo incorpora las características estructurales básicas de la computación, independientemente de los detalles de su implementación; mientras que un programa tiene un conjunto específico de detalles para resolver un problema. Se puede observar que una técnica de solución (correspondiente al algoritmo) se puede utilizar en diferentes situaciones problemáticas (correspondiente a los programas). 1.5 REPRESENTACIÓN DE ALGORITMOS Los Algoritmos se pueden expresar de muchas maneras, pero se puede decir que las dos formas más importantes son: Seudocódigo y Diagrama de Flujo. En Seudocódigo la secuencia de instrucciones se representa por medio de frases o proposiciones, mientras que en un Diagrama de Flujo se representa por medio de gráficos. Ejemplo 1.3: Elaborar un Algoritmo para calcular el área de cualquier triángulo rectángulo y presentar el resultado en pantalla. Seudocódigo: 1. 2. 3. 4. 5. 6. 7. 8. 1 Inicio Asignar el número 2 a la constante "Div" Conocer la base del triángulo y guardarla en la variable "Base" Conocer la altura del triángulo y guardarla en la variable "Altura" Guardar en la variable "Area" el valor de multiplicar "Base" por "Altura" Guardar en la variable "Area" el valor de dividir "Area" entre "Div" Reportar el valor de la variable "Area" Final National Research Council (NRC). “Being Fluent with Information Technology”, 2004. 5 Diagrama de flujo Inicio DIV=2 Almacena el valor 2 en la constante DIV Pide al usuario que digite el valor de la BASE BASE ALTURA AREA = BASE * ALTURA AREA = AREA / DIV AREA Pide al usuario que digite el valor de la ALTURA Almacena en AREA el valor de multiplicar BASE por ALTURA Almacena en AREA el valor que ya había almacenado en esta variable dividido por DIV Muestra en pantalla el valor de la variable AREA Final Fig. 1.1 Algoritmo para calcular el área de cualquier triángulo rectángulo. El seudocódigo está compuesto por proposiciones informales (en este caso en español) que permiten expresar detalladamente las instrucciones que llevan desde un estado inicial (problema) hasta un resultado deseado (solución). Por lo regular, los algoritmos se escriben por refinamiento: se escribe una primera versión que luego se descompone en varios subproblemas (el número depende de la complejidad del problema) independientes entre sí. Si es necesario se va refinando cada vez las instrucciones hasta que las proposiciones generales en español como las del ejemplo anterior se puedan codificar en el lenguaje seleccionado para hacer la programación. Utilizar Diagramas de Flujo para representar un algoritmo tiene claras ventajas. Numerosas investigaciones han mostrado que el Aprendizaje Visual es uno de los mejores métodos para enseñar habilidades del pensamiento. La utilización de Diagramas ayuda a: Clarificar el pensamiento: Se puede ver cómo se conectan los procesos y se puede dar cuenta de cómo estos se pueden organizar o agrupar para darles el orden lógico correcto. Identificar pasos erróneos: Sobre un diagrama es más fácil identificar los cambios que se requieren para el correcto funcionamiento de un programa de computador que hacerlo sobre el código. 6 Los Diagramas de Flujo son una de las técnicas más utilizadas para representar gráficamente la secuencia de instrucciones de un Algoritmo. Estas instrucciones están compuestas por operaciones, decisiones lógicas y ciclos repetitivos, entre otros. La solución de un problema puede contener varios conjuntos de instrucciones (procedimientos o métodos) que tienen como finalidad ejecutar cada uno de los procesos necesarios para llegar a la solución de un problema a partir de los datos disponibles (estado inicial). “Las ventajas de diseñar un Diagrama de Flujo antes de empezar a generar el código de un programa” 2 son, entre otras: Forzar la identificación de todos los pasos de una solución de forma clara y lógica. Establecer una visión amplia y objetiva de la solución. Verificar si se han tenido en cuenta todas las posibilidades. Comprobar si hay procedimientos duplicados. Representar gráficamente una solución (es más simple hacerlo con gráficas que mediante palabras). Facilitar a otras personas la comprensión de la secuencia lógica de la solución planteada. Posibilitar acuerdos con base en la aproximación común a una solución de un problema, resolver ambigüedades o realizar mejoras. Establecer posibles modificaciones (resulta más fácil depurar un programa con el diagrama que con el listado del código). Agilizar la codificación (traducción) del algoritmo en un lenguaje de programación. Servir como elemento de documentación de la solución del problema. Actividad 1.2: Elaborar un algoritmo en seudocódigo para cada uno de los siguientes problemas. 1. Hallar el perímetro de un cuadrado cuyo lado mide 5 cm. 2. Hallar el área de un cuadrado cuyo lado mide 5 cm. 3. Hallar uno de los lados de un rectángulo cuya área es de 15 cm2 y uno de sus lados mide 3 cm. 4. Hallar el área y el perímetro de un círculo cuyo radio mide 2 cm. 1.6 SIMBOLOGÍA DE LOS DIAGRAMAS DE FLUJO La estandarización de los símbolos para la elaboración de Diagramas de Flujo tardó varios años. Con el fin de evitar la utilización de símbolos diferentes para representar procesos iguales, la Organización Internacional para la Estandarización (ISO, por su sigla en inglés) y el Instituto Nacional Americano de Estandarización (ANSI, por su sigla en inglés), estandarizaron los símbolos que mayor aceptación tenían en 1985. Los siguientes son los principales símbolos para elaborar Diagramas de Flujo: 2 Rojas & Ñacato. 1980. 7 Inicio/Final Se utiliza para indicar el inicio y el final de un diagrama; del Inicio sólo puede salir una línea de flujo y al Final sólo debe llegar una línea. Decisión Indica la comparación de dos datos y dependiendo del resultado lógico (falso o verdadero) se toma la decisión de seguir un camino del diagrama u otro. Entrada General Entrada/Salida de datos en General. Iteración Indica que una instrucción o grupo de instrucciones deben ejecutarse varias veces. Entrada por teclado Instrucción de entrada de datos por teclado. Indica que el computador debe esperar a que el usuario teclee un dato que se guardará en una variable o constante. Salida Impresa Indica la presentación de uno o varios resultados en forma impresa. Llamada a subrutina Indica la llamada a una subrutina o procedimiento determinado. Salida en Pantalla Instrucción de presentación de mensajes o resultados en pantalla. Acción/Proceso General Indica una acción o instrucción general que debe realizar el computador (cambios de valores de variables, asignaciones, operaciones aritméticas, etc.). Conector Indica el enlace de dos partes de un diagrama dentro de la misma página. Flujo Indica el seguimiento lógico del diagrama. También indica el sentido de ejecución de las operaciones. Conector Indica el enlace de dos partes de un diagrama en páginas diferentes. 8 El Diagrama de Flujo es una herramienta gráfica valiosa para la representación esquemática de la secuencia de instrucciones de un algoritmo o de los pasos de un proceso. Reglas para la elaboración de diagramas de flujo Cuando el algoritmo se desea expresar en forma de diagrama de flujo, se deben tener en cuenta algunas “reglas o principios básicos para su elaboración”.3 Poner un encabezado que incluya un título que identifique la función del algoritmo; el nombre del autor; y la fecha de elaboración. Sólo se pueden utilizar símbolos estándar (ISO 5807). Los diagramas se deben dibujar de arriba hacia abajo y de izquierda a derecha. La ejecución del programa siempre empieza en la parte superior del diagrama. Los símbolos de “Inicio” y “Final” deben aparecer solo una vez. La dirección del flujo se debe representar por medio de flechas (líneas de flujo). Todas las líneas de flujo deben llegar a un símbolo o a otra línea. Una línea de flujo recta nunca debe cruzar a otra. Cuando dos líneas de flujo se crucen, una de ellas debe incluir una línea arqueada en el sitio donde cruza a la otra (Figura 1.2). Se deben inicializar las variables que se utilicen o permitir la asignación de valores mediante consulta al usuario. Las bifurcaciones y ciclos se deben dibujar procurando una cierta simetría. Cada rombo de decisión debe tener al menos dos líneas de salida (una para SI y otra para NO). Las acciones y decisiones se deben describir utilizando el menor número de palabras posible; sin que resulten confusas o poco claras. Si el Diagrama se vuelve complejo y confuso, es mejor utilizar símbolos conectores para reducir las líneas de flujo. Todo el Diagrama debe ser claro, ordenado y fácil de recorrer. El Diagrama se debe probar recorriéndolo con datos iniciales simples (prueba de escritorio). Fig. 1.2 Cruce de líneas de flujo4 Actividad 1.3: Basándose en la actividad anterior, convertir los algoritmos elaborados en seudocódigo en diagramas de flujo: 3 4 Rojas & Ñacato. 1980. Lopez García, Juan Carlos. Algoritmos y programación, 2009. 9 UNIDAD 2 FUNDAMENTOS DE PROGRAMACIÓN 2.1 COMENTARIOS Los comentarios no tienen ningún efecto en la ejecución del algoritmo. Se utilizan para aclarar instrucciones que puedan prestarse a confusión o como ayuda a otras personas que deben leerlo y entenderlo. La mayoría de los lenguajes de programación ofrecen la posibilidad de comentar el código de los programas. 2.2 IDENTIFICADORES Los identificadores son nombres que se dan a los elementos utilizados para resolver un problema y poder diferenciar unos de otros. Al asignar nombres (identificadores) a variables, constantes y procedimientos se deben tener en cuenta algunas reglas: Los nombres pueden estar formados por una combinación de letras y números (saldoMes, salario, fecha2, baseTriángulo, etc.). El primer carácter de un nombre debe ser una letra. La mayoría de los lenguajes de programación diferencian las mayúsculas de las minúsculas. Los nombres deben ser nemotécnicos, con solo leerlos se puede entender lo que contienen. Deben ser muy descriptivos; no utilizar abreviaturas, a menos que se justifique plenamente. Es conveniente utilizar una sola palabra para nombrar páginas, controles, variables, etc. No utilizar caracteres reservados (%, +, /, >, etc.). Se debe tener en cuenta que algunos lenguajes de programación no admiten las tildes. No utilizar palabras reservadas por los lenguajes de programación. Para cumplir con convenciones ampliamente utilizadas, los nombres de procedimientos, variables y constantes deben empezar con minúscula. Ejemplo, fecha, suma, etc. Si es un nombre compuesto por varias palabras, cada una de las palabras (con excepción de la primera) deben empezar con mayúscula. Ejemplo: fechaInicial, baseTriángulo, etc. 2.3 VARIABLES Para poder utilizar algoritmos con diferentes conjuntos de datos iniciales, se debe establecer una independencia clara entre los datos iniciales de un problema y la estructura de su solución. Esto se logra mediante la utilización de Variables (cantidades que se suelen denotar con letras -identificadores- y que pueden tomar cualquier valor de un intervalo de valores posibles). 10 En programación, las Variables son espacios de trabajo (contenedores) reservados para guardar datos (valores). El valor de una Variable puede cambiar en algún paso del Algoritmo o permanecer invariable; por lo tanto, el valor que contiene una variable es el del último dato asignado a esta. En la mayoría de los lenguajes de programación se utiliza la forma nombreVariable=Valor. 2.4 CONSTANTES Las Constantes se crean de la misma forma que las variables y consisten en datos que, luego de ser asignados, no cambian en ninguna instrucción del Algoritmo. Pueden contener constantes matemáticas (pi) o generadas para guardar valores fijos (3.8, "Jorge", etc.). 2.5 CONTADORES Los contadores se implementan como una estructura de programación que consistente en almacenar en una variable el valor de ella misma más un valor constante. Es muy útil para controlar el número de veces que debe ejecutarse un grupo de instrucciones. 2.6 ACUMULADORES Estructura muy utilizada en programación y que consiste en almacenar en una variable el valor de ella misma más otro valor variable. Es muy útil para calcular sumatorias. 2.7 PALABRAS RESERVADAS (PRIMITIVAS) Todos los lenguajes de programación definen unas palabras para nombrar sus comandos, instrucciones y funciones. Un identificador definido por el usuario no puede tener el nombre de una palabra reservada. 2.8 FUNCIONES MATEMÁTICAS Cada lenguaje de programación tiene su conjunto de funciones matemáticas predefinidas. Estas se ejecutan haciendo referencia a su nombre. Algunas necesitan, para arrojar un resultado, que se suministre información adicional (parámetros o argumentos). Actividad 2.1: Investigar cuales son las funciones matemáticas que proporciona el lenguaje de programación C. 11 2.9 TIPOS DE DATOS La mayoría de los lenguajes de programación disponen de una amplia variedad de tipos de datos. Números: se utilizan como entradas en las operaciones matemáticas. Cuando se utilizan los signos positivo (+) o negativo (-), estos deben estar pegados al número. Palabras: Las palabras están formadas por letras y/o números. Una palabra está delimitada por espacios en blanco; sin embargo, si se quiere tener un texto conformado por dos o más palabras, algunos lenguajes de programación permiten encerrar el texto entre comillas o barras. 2.10 OPERADORES Son símbolos que sirven para manipular datos. Los operadores y las operaciones que se pueden realizar con ellos se clasifican en: Aritméticos: Posibilitan las operaciones entre datos de tipo numérico y dan como resultado otro valor de tipo numérico. Ejemplo: potencia; producto; división; suma; resta. Alfanuméricos: Permiten operar con datos de tipo carácter o cadenas. La mayoría de los lenguajes de programación admiten el operador + para realizar la concatenación (unión) de caracteres o cadenas. Relaciónales: Permiten la comparación entre datos del mismo tipo y dan como resultado dos valores posibles: Verdadero o Falso. Ejemplo: igual a; menor que; mayor que. Lógicos: Posibilitan la evaluación lógica de dos expresiones de tipo lógico. Dan como resultado uno de dos valores posibles: Verdadero o Falso. Ejemplo: negación (no); conjunción (y); disyunción (o). Orden de evaluación de los operadores Los computadores ejecutan los operadores en un orden predeterminado. El siguiente es el orden (jerarquía) para ejecutar operadores: 1. 2. 3. 4. 5. 6. 7. 8. 9. Paréntesis (se ejecutan primero los más internos) Potencias y Raíces. Productos y Divisiones. Sumas y Restas. Concatenación. Relacionales. Negación. Conjunción. Disyunción. 12 2.11 EXPRESIONES Una Expresión está compuesta por valores, funciones, primitivas, constantes y/o variables, o por una combinación de los anteriores mediante operadores. Son Expresiones: Un valor (ejemplos: 1.3, “Jorge”) Una Constante o una Variable (ejemplos: divide, base, área) Una función (ejemplos: cos 60, arctan 1) Una combinación de valores, constantes, variables, funciones y operadores que siguen reglas de construcción y orden de evaluación de los operadores. Las Expresiones pueden ser: Aritméticas: Dan como resultado un valor numérico. Contienen únicamente operadores aritméticos y datos numéricos (ejemplo: pi * 20) Alfanuméricas: Dan como resultado una serie de cadena de caracteres. Lógicas: Dan como resultado un valor "Verdadero" o "Falso". Contienen variables y/o constantes enlazadas con operadores lógicos (ejemplo: A>0 y B<=5). De Asignación: Estas Expresiones asignan el resultado de una Expresión a una Variable o a una Constante. 2.12 PROCESOS Se llama procesos a todas las instrucciones contenidas en un algoritmo para: Asignar valores iniciales a variables y constantes Leer datos que suministra el usuario por medio del teclado o del ratón (mouse). Realizar operaciones matemáticas (aplicar fórmulas). Reportar o mostrar contenidos de variables y constantes. Mostrar en pantalla resultados de procedimientos activados por el programa. 2.13 INTERACTIVIDAD La interactividad entre el usuario y el programa es un recurso muy valioso en programación y se logra permitiendo la comunicación con el programa mediante la utilización del teclado y/o el ratón (mouse). 2.14 PROCEDIMIENTOS Los procedimientos son módulos con instrucciones que el computador ejecuta automáticamente, una tras otra, hasta encontrar el final. Todo procedimiento debe tener un nombre que lo identifique y que sirve para ejecutarlo cuando se ejecuta dicho nombre. 13 Todo procedimiento debe tener una línea de título que incluye un nombre; el cual, al invocarlo, ejecuta en orden, una a una, las líneas de instrucciones que contiene hasta que llega al final. Para escribir procedimientos se deben tener en cuenta las siguientes recomendaciones: El título está compuesto por: el nombre del procedimiento y los parámetros (opcional). El nombre del procedimiento debe ser una palabra. Cuando se deben utilizar varias palabras para nombrar un procedimiento, se escriben sin dejar espacio entre ellas y con mayúscula la primera letra de la segunda palabra y de las subsiguientes palabras (ejemplo: valorMasAlto). Cada instrucción completa debe ocupar una línea de código. Puede contener líneas en blanco. Desde un procedimiento se pueden invocar otros procedimientos. Ejemplo 2.1: Escribir y diseñar un procedimiento que se llame triangulo para hallar el área de un triángulo rectángulo cuya Base mide 3 cm, la Altura 4 cm y la Hipotenusa 5 cm. Análisis del problema Formular el problema: Ya se encuentra claramente planteado. Resultados esperados: El área de un triángulo rectángulo. Datos disponibles: Base, Altura, Hipotenusa, tipo de triángulo. La incógnita es el área y todos los valores son constantes. El valor de la hipotenusa se puede omitir. Restricciones: Utilizar las medidas dadas. Procesos necesarios: Guardar en dos variables (BASE y ALTURA) los valores de Base y Altura; Guardar en una constante (DIV) el divisor 2; aplicar la fórmula BASE*ALTURA/DIV y guardar el resultado en la variable AREA; comunicar el resultado (AREA). Diseño del algoritmo Inicio DIV=2 BASE=3 ALTURA=4 AREA = BASE * ALTURA /DIV AREA Almacena valores a las constantes DIV, BASE y ALTURA Calcula el área y la almacena en la variable AREA Imprime el valor almacenado en la variable AREA Final 14 UNIDAD 3 ESTRUCTURAS BÁSICAS Un Algoritmo está compuesto por instrucciones de diferentes tipos, organizadas secuencialmente, en forma de estructuras de control. De estas estructuras, las más comunes son las siguientes: Secuencial. Iterativa (repetición). Condicional (decisión, selección). Una estructura de control se define como “un esquema que permite representar ideas de manera simplificada y que bajo condiciones normales, es constante”.5 “El uso del diseño descendente en los programas, la ejecución de operaciones secuenciales, la utilización de ciclos repetitivos y, la toma de decisiones y alternativas de proceso, ofrecen amplias posibilidades para resolver problemas mediante la construcción de procedimientos”. 6 Actualmente, la programación orientada a objetos (POO) busca reducir al máximo la cantidad de estructuras de control mediante el uso de polimorfismo; pero aún así, todavía se vale de estas estructuras para construir métodos. Es fundamental que se preste atención especial a las estructuras que se utilizan para resolver problemas y reconocerlas para lograr mayor control sobre la solución planteada. De esta manera, la programación de computadores ayuda a planear conscientemente las secuencias de acciones que resuelven un problema planteado y las estructuras involucradas en una solución dada. 3.1 ESTRUCTURA SECUENCIAL La estructura de control secuencial es la más sencilla. También se la conoce como estructura lineal. Se compone de instrucciones que deben ejecutarse en forma consecutiva, una tras otra, siguiendo una línea de flujo. Solamente los problemas muy sencillos pueden resolverse haciendo uso únicamente de esta estructura. Normalmente, la estructura secuencial hace parte de soluciones a problemas complejos en las que se la utiliza mezclada con estructuras iterativas (repetir varias veces un conjunto de instrucciones) y condicionales (tomar decisiones). 5 6 Trejos. 1999. Castellanos & Ferreyra. 2000. 15 Inicio Leer datos Procesos Reportar resultados Final Fig 3.1. Modelo de estructura secuencial. Una estructura de control secuencial puede contener cualquiera de las siguientes instrucciones: Declaración de variables. Asignación de valores. Entrada de datos. Procesamiento de datos (operaciones). Reporte de resultados. Ejemplo 3.1: Escribir un procedimiento para calcular el área de cualquier triángulo rectángulo. En él se debe pedir al usuario que ingrese los valores de la Altura y la Base del triángulo. Análisis del problema Formular el problema: Ya está claramente planteado. Resultados esperados: Un procedimiento que permita calcular el área de cualquier triángulo rectángulo. Datos disponibles: Base y Altura del triángulo (se deben solicitar al usuario. Restricciones: Los valores de base y altura son variables y se deben solicitar al usuario. Procesos necesarios: definir variables; asignar el valor 2 a la constante div; solicitar al usuario el valor de la altura del triángulo; solicitar al usuario el valor de la base; aplicar la fórmula de área; mostrar el resultado. Diseño del algoritmo 16 Inicio declarar div, base, altura y area div = 2 altura, base area = base * altura / div area Final Ejemplo3.2: Escribir un procedimiento que muestre 3 veces en pantalla la frase “David Ausubel”. Análisis del problema Formular el problema: Ya se encuentra claramente formulado. Resultados esperados: Que aparezca tres veces en pantalla la frase “David Ausubel”. Datos disponibles: La frase dada. Restricciones: Ninguna. Procesos necesarios: Ninguno. Diseño del algoritmo Inicio “David Ausubel” “David Ausubel” “David Ausubel” Final Actividad 3.1: Diseñar un algoritmo que pida al usuario dos números y calcule la suma, la resta, la multiplicación y la división del primero por el segundo. 3.2 ESTRUCTURA ITERATIVA (REPETICIÓN) 17 La estructura iterativa o de repetición permite ejecutar una o varias instrucciones, un número determinado de veces o, indefinidamente, mientras se cumpla una condición. Esta estructura ayuda a simplificar los algoritmos, ahorrando tiempo valioso a quien resuelve problemas con ayuda del computador. En programación existen al menos dos tipos de estructuras repetitivas, las cuales a su vez tienen variantes en los diferentes lenguajes de programación. La característica común es que ambos tipos permiten ejecutar una o varias instrucciones: Un número determinado de veces. Mientras se cumpla una condición. Fig. 3.2 Modelo de estructura iterativa.7 Ejemplo3.3: Escribir un procedimiento que muestre 100 veces en pantalla la frase “David Ausubel”. Análisis del problema Formular el problema: Ya se encuentra claramente formulado. Resultados esperados: Que aparezca 100 veces en pantalla la frase “David Ausubel”. Datos disponibles: La frase dada. Restricciones: Ninguna. Procesos necesarios: Mostrar la frase mencionada 100 veces. Diseño del algoritmo Inicio repite 1, 100 “David Ausubel” Final 7 Lopez García, Juan Carlos. Algoritmos y programación, 2009. 18 Ejemplo 3.4: Calcular el valor de la sumatoria: 1 + 2 + 3 + 4 +5 + … + 100. Análisis del problema Formular el problema: Ya se encuentra claramente formulado. Resultados esperados: El resultado de la suma de los números entre 1 y 100. Datos disponibles: El rango de números dado. Restricciones: Ninguna. Procesos necesarios: guardar el número 0 en una variable e incrementarla en 1 cada vez que se ejecute el ciclo repetitivo. Guardar 0 en otra variable e ir acumulando en ella su propio valor más el valor de la primera variable. Diseño del algoritmo Inicio Suma100 contador = 0 sumatoria = 0 repite 1, 100 contador = contador + 1 sumatoria = sumatoria + contador contador sumatoria [El valor de la suma 1 + 2 + 3 + … + 100 es] sumatoria Final Este algoritmo utiliza una operación muy útil en programación: sumatoria = sumatoria + contador Consiste en almacenar en una variable sumatoria el valor de ella misma (sumatoria) más otro valor variable (contador). Es muy utilizada para acumular valores. 19 Ejemplo 3.5: Elaborar un procedimiento para calcular las tablas de multiplicar. El usuario debe ingresar qué tabla de multiplicar desea. Análisis del problema Formular el problema: Ya se encuentra claramente formulado. Resultados esperados: La tabla de multiplicar que el usuario indique. Datos disponibles: El número de la tabla (indicada por el usuario). Restricciones: Ninguna. Procesos necesarios: Pedir al usuario que ingrese la tabla de multiplicar que desea. Guardar ese valor en una variable (tabla). Multiplicar cada uno de los valores entre 0 y 9 por la variable tabla. Mostrar el resultado de cada multiplicación. Diseño del algoritmo Inicio tablaMultiplicar tabla cumpleveces [multiplicando 10] rsultado = multiplicando * tabla tabla “x” multiplicando “=” resultado Final 3.3 ESTRUCTURA CONDICIONAL La estructura condicional se utiliza para indicarle al computador que debe evaluar una condición y, a partir del resultado, ejecutar el bloque de instrucciones correspondiente. La forma más común está compuesta por una proposición (condición) que se evalúa y dos bloques de instrucciones que se ejecutan, uno cuando la condición es verdadera (selección simple y doble) y otro cuando ésta es falsa (únicamente en la selección doble). Para que una proposición (frase declarativa) sea válida, debe poder afirmarse que es verdadera o falsa. 20 En programación, se utilizan operadores relacionales (<, =, >) para establecer la relación que existe entre dos elementos de la proposición. Adicionalmente, las proposiciones pueden ser sencillas o compuestas. Las proposiciones compuestas se forman con dos o más proposiciones sencillas unidas por operadores lógicos (y, o, no). Cuando se unen dos proposiciones por medio del operador lógico “y”, significa que ambas proposiciones deben ser verdaderas (conjunción). Cuando se unen dos proposiciones por medio del operador lógico “o”, significa que por lo menos una de las dos proposiciones debe ser verdadera (disyunción). Por su parte, un bloque de instrucciones puede contener una o varias instrucciones que se ejecutan una detrás de otra. La estructura condicional tiene tres variantes: Selección simple. Selección doble. Selección múltiple. Las estructuras condicionales simple y doble evalúan una proposición (condición) que devuelve como resultado únicamente dos valores posibles y excluyentes: verdadero o falso. En cambio, la estructura condicional de selección múltiple permite que la condición devuelva más de un valor posible y que para cada uno de esos valores se ejecute el bloque de instrucciones correspondiente. Selección simple La estructura condicional de selección simple ejecuta un bloque de instrucciones cuando la proposición (condición) es verdadera; si esta es falsa, no hace nada. Fig 3.3 Modelo de estructura condicional simple.8 Selección doble La estructura condicional de selección doble ejecuta un bloque de instrucciones (A) cuando la proposición (condición) es verdadera y un bloque diferente (B) cuando esta es falsa. 8 Lopez García, Juan Carlos. Algoritmos y programación, 2009. 21 Fig 3.4 Modelo de estructura condicional doble.9 Ejemplo 3.6: Un estudiante aprueba un examen cuando obtiene una calificación mayor o igual a siete. Elaborar un procedimiento que pida al usuario una calificación, aplique el criterio de aprobación e imprima “Aprobado” o “Reprobado”, según sea el caso. Análisis del problema Formular el problema: Es un problema sencillo de selección doble. Resultados esperados: Un aviso que reporte si el estudiante “Aprobó” o “Reprobó” el examen. Datos disponibles: La calificación ingresada por el usuario. Para aprobar, la nota debe ser mayor o igual a 7.0. Restricciones: Aplicar el criterio de aprobación. Procesos necesarios: Solicitar al usuario que ingrese la calificación. Evaluar si la calificación es igual o superior a 7.0; en caso de ser verdadero, reportar “Aprobado”; en caso contrario, reportar “Reprobado”. Diseño del algoritmo Inicio calificacion VERDAD calificacion >= 7.0 Aprobado FALSO Reprobado Final 9 Lopez García, Juan Carlos. Algoritmos y programación, 2009. 22 Ejemplo 3.7: Supongamos que Mónica quiere ir a comer helado y su padre le propone: “Como hoy entregan tus calificaciones del segundo período, si has obtenido en matemáticas más de 8.0, vamos a comer helado el próximo sábado, de lo contrario no vamos”. La situación “comer helado” está sujeta a la condición “obtener más de 8.0 en matemáticas para el segundo período”. Análisis del problema Formular el problema: Es un problema sencillo de selección doble. Resultados esperados: Un aviso que indique si el estudiante puede ir a comer helado el próximo sábado o no. Datos disponibles: La calificación de matemáticas ingresada por el usuario. La regla dice: para ir a comer helado, la nota debe ser mayor que 8.0. Restricciones: Aplicar la regla dada. Procesos necesarios: Solicitar al usuario que ingrese la calificación de matemáticas. Evaluar si la calificación es igual o inferior a 8.0; en caso de ser verdadero, reportar “NO come helado”; en caso contrario, reportar “SI come helado”. Diseño del algoritmo Inicio matematicas VERDAD matematicas <= 8.0 No come helado FALSO SI come helado Final Ejemplo 3.8: Una profesora necesita calcular la nota definitiva para cada uno de los 22 alumnos que asisten a su curso de geometría, con el fin de saber quiénes aprobaron y quiénes reprobaron (para aprobar hay que obtener una nota igual o superior a 6.5), la profesora realizó a todos sus estudiantes, en el primer periodo del año lectivo, dos exámenes y asignó un trabajo de investigación. ¿Cómo se le puede ayudar? Análisis del problema Formular el problema: Se requiere calcular un promedio de tres notas para cada uno de los 22 alumnos. Resultados esperados: La nota definitiva de cada uno de los 22 alumnos y un aviso que indique si aprobó o no. Datos disponibles: El número de alumnos: 22. Las notas de cada alumno las debe digitar la profesora. Restricciones: Cada una de las tres notas tiene el mismo porcentaje en la nota definitiva. Tres notas por alumno y 22 alumnos. Todas las notas deben ser mayores o iguales a 1 y menores o iguales a 10. Para aprobar hay que tener un promedio igual o superior a 6.5. Procesos necesarios: Para cada uno de los 22 alumnos: Leer las tres notas, verificar que estén en el rango permitido (entre 1 y 10), sumarlas, calcular el promedio, verificar si aprobó o no. Mostrar el promedio y un aviso que informe si aprobó o no. 23 Diseño del algoritmo Inicio notas Cumpleveces [estudiante 22] examenUno, examenDos, trabajo Verdad examenUno < 0 ó examenUno > 10 ó examenDos < 0 ó examenDos > 10 ó trabajo <0 ó trabajo > 10 Falso sumatoria = examenUno + examenDos + trabajo datos no válidos promedio = sumatoria / 3 Verdad promedio < 6.5 aprobar = “NO” Falso aprobar = “SI” promedio, aprobar Final Ejemplo 3.9: Escribir un procedimiento para leer los valores de dos de los tres ángulos internos de un triángulo y mostrar en pantalla “Es un Triángulo Rectángulo” si efectivamente es un triángulo de este tipo o, en caso contrario, mostrar “No es un Triángulo Rectángulo”. Análisis del problema Formular el problema: Se requiere determinar si un triángulo es o no es un triangulo rectángulo en base a los valores de sus ángulos. Resultados esperados: Un aviso que indique si es o no un triángulo rectángulo. Datos disponibles: El valor de dos de los tres ángulos. Estos valores deben ser ingresados por el usuario. Restricciones: Ninguna. Procesos necesarios: Leer el valor de dos ángulos. Calcular el valor del tercer ángulo. Verificar si es un triángulo rectángulo. Mostrar un aviso que informe si es o no un triángulo rectángulo. 24 Diseño del algoritmo Inicio declarar: ANGULO1, ANGULO2, ANGULO3, esRectangulo ANGULO1, ANGULO2 ANGULO3 = 180 – ANGULO1 – ANGULO2 esRectangulo = NO Verdad ANGULO1 = 90 esRectangulo = SI Verdad ANGULO2 = 90 esRectangulo = SI Verdad ANGULO3 = 90 esRectangulo = SI Verdad esRectangulo = SI SI es un Triángulo Rectángulo Falso NO es un Triángulo Rectángulo Final Actividad 3.2: Escribir un procedimiento para leer los valores de dos de los tres ángulos internos de un triángulo y mostrar en pantalla “Es un Triángulo Rectángulo” si efectivamente es un triángulo de este tipo o, en caso contrario, mostrar “No es un Triángulo Rectángulo”. Utilizar operadores lógicos en la solución. Actividad 3.3: Tomando como base el ejemplo anterior, realizar las modificaciones necesarias para que adicionalmente, el programa muestre en pantalla “No es un Triángulo” en caso de que cualquiera de los ángulos sea menor o igual a cero. 25 Estructuras condicionales anidadas Hay situaciones que requieren el uso de estructuras condicionales anidadas. En estas, el resultado de la primera proposición implica evaluar a continuación una segunda proposición y esta a su vez requiere que se evalúe una tercera proposición, y así sucesivamente, hasta agotar todas las condiciones. Plantear estructuras algorítmicas anidables (iterativa y condicional) requiere procesos de pensamiento asociados con el sistema operatorio de clasificación o inclusión. El siguiente caso ilustra muy bien este punto: "Se requiere elaborar un procedimiento que permita determinar para un grupo de 10 personas si tienen derecho o no a jubilarse a partir de los datos género, edad y años de aportes; y las siguientes condiciones: si es hombre debe tener más de 65 años de edad y más de 60 años si es mujer, pero en todo caso se deben haber realizado aportes por más de 20 años". Actividad 3.4: Escribir un procedimiento para dar solución al problema planteado en el párrafo anterior. . 26 UNIDAD 4 LENGUAJE C 4.1 CARACTERÍSTICAS DEL LENGUAJE C El lenguaje C se conoce como un lenguaje compilado. Este tipo de lenguajes convierten el código fuente en un fichero objeto y éste en un fichero ejecutable. Este es el caso del lenguaje C. El lenguaje C es un lenguaje de nivel medio, ya que combina elementos de lenguaje de alto nivel con la funcionalidad del lenguaje ensamblador. Es un lenguaje estructurado, ya que permite crear procedimientos en bloques dentro de otros procedimientos. Hay que destacar que el C es un lenguaje portable, ya que permite utilizar el mismo código en diferentes equipos y sistemas informáticos: el lenguaje es independiente de la arquitectura de cualquier máquina en particular. Por último se puede decir que el C es un lenguaje relativamente pequeño; se puede describir en poco espacio y aprender rápidamente. 4.2 ESTRUCTURA DE UN PROGRAMA EN C Todo programa en C consta de una o más funciones, una de las cuales se llama main (principal). El programa comienza en la función main, desde la cual es posible llamar a otras funciones. Cada función estará formada por la cabecera de la función, compuesta por el nombre de la misma y la lista de argumentos (si los hubiese), la declaración de las variables a utilizar y la secuencia de sentencias a ejecutar. Ejemplo: declaraciones globales; main( ) { variables locales; instrucción(es), } funcion1( ) { variables locales; instrucción(es); } COMENTARIOS Para poner comentarios en un programa escrito en C se utiliza los símbolos /* y */: 27 /* Este es un ejemplo de comentario */ /* Un comentario también puede estar escrito en varias líneas */ El símbolo /* se coloca al principio del comentario y el símbolo */ al final. El comentario, contenido entre estos dos símbolos, no será tenido en cuenta por el compilador. PALABRAS CLAVE Existen una serie de indicadores reservados, con una finalidad determinada, que no se puede utilizar como identificadores. A continuación se observan algunas de estas palabras clave: char else short continue int do long float while extern break double for static register if switch default sizeof IDENTIFICADORES El primer caracter de un identificador no puede ser un número, es decir que debe ser una letra o el símbolo _. Se diferencian las mayúsculas de las minúsculas, así num, Num y nuM son distintos identificadores. A continuación se observan algunos ejemplos de identificadores válidos y no válidos: Válidos No válidos _num var1 fecha_nac 1num número2 año_nac 4.3 TIPOS DE DATOS En 'C' existen básicamente cuatro tipos de datos, aunque también se puede definir tipos de datos propios a partir de los tipos originales. A continuación se detalla su nombre, el tamaño que ocupa en memoria y el rango de sus posibles valores. Tipo Tamaño Rango de valores char int float double 1 2 4 8 -128 a 127 -32768 a 32767 3'4 E-38 a 3'4 E+38 1'7 E-308 a 1'7 E+308 byte bytes bytes bytes 28 CALIFICADORES DE TIPO Los calificadores de tipo tienen la misión de modificar el rango de valores de un determinado tipo de variable. Estos calificadores son cuatro: signed Le indica a la variable que va a llevar signo. Es el utilizado por defecto. signed char signed int tamaño rango de valores 1 byte 2 bytes -128 a 127 -32768 a 32767 unsigned Le indica a la variable que no va a llevar signo (valor absoluto). tamaño unsigned char unsigned int 0 a 255 0 a 65535 short Rango de valores en formato corto (limitado). Es el utilizado por defecto. short char short int rango de valores 1 byte 2 bytes tamaño rango de valores 1 byte 2 bytes -128 a 127 -32768 a 32767 long Rango de valores en formato largo (ampliado). long int long double tamaño rango de valores 4 bytes 10 bytes -2.147.483.648 a 2.147.483.647 -3'36 E-4932 a 1'18 E+4932 También es posible combinar calificadores entre sí: LAS VARIABLES Una variable sólo puede pertenecer a un tipo de dato. Para poder utilizar una variable, primero tiene que ser declarada: [calificador] <tipo> <nombre> Es posible inicializar y declarar más de una variable del mismo tipo en la misma sentencia: [calificador] <tipo> <nombre1>,<nombre2>=<valor>,<nombre3>=<valor>,<nombre4> Ejemplo: int num1=4,num2,num3=6; 29 ¿Dónde se declaran? Las variables pueden ser de dos tipos según el lugar en que las declaremos: globales o locales. La variable global se declara antes de la función main( ). Puede ser utilizada en cualquier parte del programa y se destruye al finalizar éste. La variable local se declara después de la main( ), en la función en que vaya a ser utilizada. Sólo existe dentro de la función en que se declara y se destruye al finalizar dicha función. Ejemplo: /* Declaración de variables */ #include <stdio.h> int a; main() /* Muestra dos valores */ { int b=4; printf("b es local y vale %d",b); a=5; printf("\na es global y vale %d",a); } CONSTANTES Para indicar al compilador que se trata de una constante, se utiliza la directiva #define: #define <identificador> <valor> Observe que no se indica el punto y coma de final de sentencia ni tampoco el tipo de dato. Ejemplo: /* Uso de las constantes */ #include <stdio.h> #define pi 3.1416 #define escribe printf main() /* Calcula el perímetro */ { int r; escribe("Introduce el radio: "); scanf("%d",&r); escribe("El perímetro es: %f",2*pi*r); } SECUENCIAS DE ESCAPE Ciertos caracteres no representados gráficamente se pueden representar mediante lo que se conoce como secuencia de escape. A continuación se observa una tabla de las más significativas: 30 \n \b \t \v \\ \f \' \" \0 Ejemplo: salto de línea retroceso tabulación horizontal tabulación vertical contrabarra salto de página apóstrofe comillas dobles fin de una cadena de caracteres /* Uso de las secuencias de escape */ #include <stdio.h> main() /* Escribe diversas sec. de escape */ { printf("Me llamo \"Nemo\" el grande"); printf("\nDirección: C\\ Mayor 25"); printf("\nHa salido la letra \'L\'"); printf("\nRetroceso\b"); printf("\n\tEsto ha sido todo"); } INCLUSIÓN DE FICHEROS En la programación en C es posible utilizar funciones que no esten incluídas en el propio programa. Para ello se utiliza la directiva #include, que permite añadir a un programa librerías o funciones que se encuentran en otros ficheros. Para indicar al compilador que se va a incluir ficheros externos se tiene dos maneras (siempre antes de las declaraciones). 1. Indicándole al compilador la ruta donde se encuentra el fichero. #include "misfunc.h" #include "c:\includes\misfunc.h" 2. Indicando que se encuentran en el directorio por defecto del compilador. #include <misfunc.h> 4.4 OPERADORES ARITMÉTICOS Y DE ASIGNACIÓN Operadores aritméticos Existen dos tipos de operadores aritméticos: 31 Los binarios: + * / % Suma Resta Multiplicación División Módulo (resto) y los unarios: ++ -- Incremento (suma 1) Decremento (resta 1) Cambio de signo Su sintaxis es: binarios: <variable1><operador><variable2> unarios: <variable><operador> Ejemplo: y al revés, <operador><variable>. /* Uso de los operadores aritméticos */ #include <stdio.h> main() /* Realiza varias operaciones */ { int a=1,b=2,c=3,r; r=a+b; printf("%d + %d = %d\n",a,b,r); r=c-a; printf("%d - %d = %d\n",c,a,r); b++; printf("b + 1 = %d",b); } OPERADORES DE ASIGNACIÓN La mayoría de los operadores aritméticos binarios tienen su correspondiente operador de asignación: = += -= *= /= %= Asignación simple Suma Resta Multiplicación División Módulo (resto) 32 Con estos operadores se pueden escribir, de forma más breve, expresiones del tipo: n=n+3 se puede escribir n+=3 k=k*(x-2) lo podemos sustituir Ejemplo: por k*=x-2 /* Uso de los operadores de asignación */ #include <stdio.h> main() /* Realiza varias operaciones */ { int a=1,b=2,c=3,r; a+=5; printf("a + 5 = %d\n",a); c-=1; printf("c - 1 = %d\n",c); b*=3; printf("b * 3 = %d",b); } JERARQUÍA DE LOS OPERADORES Será importante tener en cuenta la precedencia (de mayor a menor) de los operadores a la hora de trabajar con ellos: ( ) ++, - *, /, % +, - Las operaciones con mayor precedencia se realizan antes que las de menor precedencia. 4.5 SALIDA / ENTRADA Sentencia 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 se indica la forma en que se mostrarán los argumentos posteriores. También se puede introducir una cadena de texto (sin necesidad de argumentos), o combinar ambas posibilidades, así como secuencias de escape. En el caso de que se utilice argumentos se debe indicar en la cadena de control tantos modificadores como argumentos se vaya a presentar. 33 El modificador está compuesto por el caracter % seguido por un caracter de conversión, que indica de qué tipo de dato se trata. Ejemplo: /* Uso de la sentencia printf() 1. */ #include <stdio.h> main() /* Saca por pantalla una suma */ { int a=20,b=10; printf("El valor de a es %d\n",a); printf("El valor de b es %d\n",b); printf("Por tanto %d+%d=%d",a,b,a+b); } Los modificadores más utilizados son: %c %d %u %o %x %e %f %s %p Ejemplo: Un único carácter. Un entero con signo, en base decimal. Un entero sin signo, en base decimal. Un entero en base octal. Un entero en base hexadecimal. Un número real en coma flotante, con exponente. Un número real en coma flotante, sin exponente. Una cadena de caracteres. Un puntero o dirección de memoria. /* Uso de la sentencia printf() 2. */ #include <stdio.h> main() /* Modificadores 1 */ { char cad[]="El valor de"; int a=-15; unsigned int b=3; float c=932.5; printf("%s a es %d\n",cad,a); printf("%s b es %u\n",cad,b); printf("%s c es %e o %f",cad,c,c); } Sentencia 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...); 34 En la cadena de control se indicará, 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 formados por el caracter % seguido de un caracter 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 esta posición utilizaremos el símbolo ampersand (&), que se coloca delante del nombre de cada variable. (Esto no será necesario en los arrays ). /* Uso de la sentencia scanf(). */ Ejemplo: #include <stdio.h> main() /* Solicita dos datos */ { char nombre[10]; int edad; printf("Introduce tu nombre: "); scanf("%s",nombre); printf("Introduce tu edad: "); scanf("%d",&edad); } 4.6 OPERADORES RELACIONALES En C existen seis operadores relacionales básicos: > < >= <= == != Mayor que Menor que Mayor o igual que Menor o igual que Igual que Distinto que El resultado que devuelven estos operadores es 1 para Verdadero y 0 para Falso. Si hay más de un operador se evalúan de izquierda a derecha. Además los operadores == y != están por debajo del resto en cuanto al orden de precedencia. Ejemplo: /* Uso de los operadores relacionales. */ #include <stdio.h> main() /* Compara dos números entre ellos */ { int a,b; printf("Introduce el valor de A: "); scanf("%d",&a); 35 printf("Introduce el valor de B: "); scanf("%d",&b); if(a>b) printf("A es mayor que B"); else if(a<b) printf("B es mayor que A"); } 4.7 SENTENCIAS CONDICIONALES Estructura IF...ELSE if (condición) sentencia; Sintaxis: La sentencia solo se ejecuta si se cumple la condición. En caso contrario el programa sigue su curso sin ejecutar la sentencia. Otro formato: if (condición) sentencia1; else sentencia2; Si se cumple la condición ejecutará la sentencia1, si no ejecutará la sentencia2. En cualquier caso, el programa continuará a partir de la sentencia2. Ejemplo: /* Uso de la sentencia condicional IF. */ #include <stdio.h> main() /* Simula una clave de acceso */ { int usuario,clave=18276; printf("Introduce tu clave: "); scanf("%d",&usuario); if(usuario==clave) printf("Acceso permitido"); else printf("Acceso denegado"); } Otro formato: if (condición) sentencia1; else if (condición) sentencia2; else if (condición) sentencia3; else sentencia4; Con este formato el flujo del programa únicamente entra en una de las condiciones. Si una de ellas se cumple, se ejecuta la sentencia correspondiente y salta hasta el final de la estructura para continuar con el programa. Existe la posibilidad de utilizar llaves para ejecutar más de una sentencia dentro de la misma condición. 36 Ejemplo: /* Uso de la sentencia condicional ELSE...IF. */ #include <stdio.h> main() /* Escribe bebé, niño o adulto */ { int edad; printf("Introduce tu edad: "); scanf("%d",&edad); if (edad<1) printf("Lo siento, te has equivocado."); else if (edad<3) printf("Eres un bebé"); else if (edad<13) printf("Eres un niño"); else printf("Eres adulto"); } Estructura SWITCH Esta estructura se suele utilizar en los menús, de manera que según la opción seleccionada se ejecuten una serie de sentencias. switch (variable){ case contenido_variable1: sentencias; break; case contenido_variable2: sentencias; break; default: sentencias; Su sintaxis es: } Cada case puede incluir una o más sentencias sin necesidad de ir entre llaves, ya que se ejecutan todas hasta que se encuentra la sentencia break. La variable evaluada sólo puede ser de tipo entero o caracter. default ejecutará las sentencias que incluya, en caso de que la opción escogida no exista. Ejemplo: /* Uso de la sentencia condicional SWITCH. */ #include <stdio.h> main() /* Escribe el día de la semana */ { int dia; printf("Introduce el día: "); scanf("%d",&dia); switch(dia){ case 1: printf("Lunes"); break; case 2: printf("Martes"); break; case 3: printf("Miércoles"); break; case 4: printf("Jueves"); break; case 5: printf("Viernes"); break; case 6: printf("Sábado"); break; 37 case 7: printf("Domingo"); break; } } 4.8 OPERADORES LÓGICOS Los operadores lógicos básicos son tres: && || ! AND OR NOT (El valor contrario) Estos operadores actúan sobre expresiones lógicas. Permiten unir expresiones lógicas simples formando otras más complejas. Ejemplo: /* Uso de los op. lógicos AND,OR,NOT. */ #include <stdio.h> main() /* Compara un número introducido */ { int numero; printf("Introduce un número: "); scanf("%d",&numero); if(!(numero>=0)) printf("El número es negativo"); else if((numero<=100)&&(numero>=25)) printf("El número está entre 25 y 100"); else if((numero<25)||(numero>100)) printf("El número no está entre 25 y 100"); } 4.9 BUCLES Sentencia WHILE Su sintaxis es: while (condición) sentencia; Con esta sentencia se controla la condición antes de entrar en el bucle. Si ésta no se cumple, el programa no entrará en el bucle. Naturalmente, si en el interior del bucle hay más de una sentencia, éstas deberán ir entre llaves para que se ejecuten como un bloque. Ejemplo: /* Uso de la sentencia WHILE. */ #include <stdio.h> main() /* Escribe los números del 1 al 10 */ { int numero=1; 38 while(numero<=10) { printf("%d\n",numero); numero++; } } Sentencia DO...WHILE do{ Su sintaxis es: sentencia1; sentencia2; }while (condición); Con esta sentencia se controla la condición al final del bucle. Si ésta se cumple, el programa vuelve a ejecutar las sentencias del bucle. La única diferencia entre las sentencias while y do...while es que con la segunda el cuerpo del bucle se ejecutará por lo menos una vez. Ejemplo: /* Uso de la sentencia DO...WHILE. */ #include <stdio.h> main() /* Muestra un menú si no se pulsa 4 */ { char seleccion; do{ printf("1.- Comenzar\n"); printf("2.- Abrir\n"); printf("3.- Grabar\n"); printf("4.- Salir\n"); printf("Escoge una opción: "); seleccion=getchar(); switch(seleccion){ case '1':printf("Opción 1"); break; case '2':printf("Opción 2"); break; case '3':printf("Opción 3"); } }while(seleccion!='4'); } Sentencia FOR Su sintaxis es: for (inicialización;condición;incremento){ sentencia1; sentencia2; } La inicialización indica una variable (variable de control) que condiciona la repetición del bucle. Si hay más, van separadas por comas: 39 for (a=1,b=100;a!=b;a++,b- -){ El flujo del bucle FOR transcurre de la siguiente forma: Fig. 4.1 Flujo del bucle FOR10 Ejemplo: /* Uso de la sentencia FOR. */ #include <stdio.h> main() /* Escribe la tabla de multiplicar */ { int num,x,result; printf("Introduce un número: "); scanf("%d",&num); for (x=0;x<=10;x++){ result=num*x; printf("\n%d por %d = %d\n",num,x,result); } } Sentencia BREAK Esta sentencia se utiliza para terminar la ejecución de un bucle o salir de una sentencia switch. Sentencia CONTINUE Se utiliza dentro de un bucle. Cuando el programa llega a una sentencia CONTINUE no ejecuta las líneas de código que hay a continuación y salta a la siguiente iteración del bucle. Ejemplo: /* Uso de la sentencia CONTINUE. */ #include <stdio.h> main() /* Escribe del 1 al 100 menos el 25 */ { int numero=1; while(numero<=100) { if (numero==25) { numero++; continue; } 10 Lopez García, Juan Carlos. Algoritmos y programación, 2009. 40 printf("%d\n",numero); numero++; } } 4.10 FUNCIONES Las funciones son bloques de código utilizados para dividir un programa en partes más pequeñas, cada una de las cuáles tendrá una tarea determinada. Su sintaxis es: tipo_función nombre_función (tipo y nombre de argumentos) { bloque de sentencias } tipo_función: puede ser de cualquier tipo de dato conocido. El valor devuelto por la función será de este tipo. Por defecto, es decir, si no se indica el tipo, la función devolverá un valor de tipo entero (int). Si se desea que no retorne algún valor se debe indicar el tipo vacío (void). nombre_función: es el nombre que se le da a la función. tipo y nombre de argumentos: son los parámetros que recibe la función. Los argumentos de una función no son más que variables locales que reciben un valor. Este valor se lo envía al hacer la llamada a la función. Pueden existir funciones que no reciban argumentos. bloque de sentencias: es el conjunto de sentencias que serán ejecutadas cuando se realice la llamada a la función. Las funciones pueden ser llamadas desde la función main o desde otras funciones. Nunca se debe llamar a la función main desde otro lugar del programa. Declaración de las funciones Al igual que las variables, las funciones también han de ser declaradas. Esto es lo que se conoce como prototipo de una función. Los prototipos de las funciones pueden escribirse antes de la función main o bién en otro fichero. En este último caso se lo debe indicar al compilador mediante la directiva #include. Ejemplo: /* Declaración de funciones. */ #include <stdio.h> void funcion(void); /* prototipo */ int num=5; /* variable global */ 41 main() /* Escribe dos números */ { int num=10; /* variable local */ printf("%d\n",num); funcion(); /* llamada */ } void funcion(void) { printf("%d\n",num); } Paso de parámetros a una función Las funciones pueden retornar un valor. Esto se hace mediante la instrucción return, que finaliza la ejecución de la función, devolviendo o no un valor. En una misma función se puede tener más de una instrucción return. La forma de retornar un valor es la siguiente: return ( valor o expresión ); El valor devuelto por la función debe asignarse a una variable. De lo contrario, el valor se perderá. Ejemplo: /* Paso de parámetros. */ #include <stdio.h> int suma(int,int); /* prototipo */ main() /* Realiza una suma */ { int a=10,b=25,t; t=suma(a,b); /* guardamos el valor */ printf("%d=%d",suma(a,b),t); suma(a,b); /* el valor se pierde */ } int suma(int a,int b) { return (a+b); } Existen dos formas de enviar parámetros a una función: Por valor: cualquier cambio que se realice dentro de la función en el argumento enviado, NO afectará al valor original de las variables utilizadas en la llamada. Es como si trabajaramos con una copia, no con el original. No es posible enviar por valor arrays, se debe hacerlo por referencia. Por referencia: lo que se hace es enviar a la función la dirección de memoria donde se encuentra la variable o dato. Cualquier modificación SI afectará a las variables utilizadas en la llamada. Se trabajamos directamente con el original. 42 Ejemplo: /* Paso por valor. */ #include <stdio.h> void intercambio(int,int); main() /* Intercambio de valores */ { int a=1,b=2; printf("a=%d y b=%d",a,b); intercambio(a,b); /* llamada */ printf("a=%d y b=%d",a,b); } void intercambio (int x,int y) { int aux; aux=x; x=y; y=aux; printf("a=%d y b=%d",x,y); } Para enviar un valor por referencia se utiliza el símbolo & (ampersand) delante de la variable enviada. Esto le indica al compilador que la función que se ejecutará tendrá que obtener la dirección de memoria en que se encuentra la variable. Las variables con un * son conocidas como punteros, el único dato en 'C' que puede almacenar una dirección de memoria. Ejemplo: /* Paso por referencia. */ #include <stdio.h> void intercambio(int *,int *); main() /* Intercambio de valores */ { int a=1,b=2; printf("a=%d y b=%d",a,b); intercambio(&a,&b); /* llamada */ printf("a=%d y b=%d",a,b); } void intercambio (int *x,int *y) { int aux; aux=*x; *x=*y; *y=aux; printf("a=%d y b=%d",*x,*y); } 43 4.11 ARRAYS Un array es un identificador que referencia un conjunto de datos del mismo tipo. Imagine un tipo de dato int; se puede crear un conjunto de datos de ese tipo y utilizar uno u otro con sólo cambiar el índice que lo referencia. El índice será un valor entero y positivo. En C los arrays comienzan por la posición 0. Vectores Un vector es un array unidimensional, es decir, sólo utiliza un índice para referenciar a cada uno de los elementos. Su declaración será: tipo nombre [tamaño]; El tipo puede ser cualquiera de los ya conocidos y el tamaño indica el número de elementos del vector (se debe indicar entre corchetes [ ]). En el siguiente ejemplo se puede observar que la variable i es utilizada como índice, el primer for sirve para rellenar el vector y el segundo para visualizarlo. Las posiciones van de 0 a 9 (total 10 elementos). Ejemplo: /* Declaración de un array. */ #include <stdio.h> main() /* { int for for } Rellenamos del 0 - 9 */ vector[10],i; (i=0;i<10;i++) vector[i]=i; (i=0;i<10;i++) printf(" %d",vector[i]); Se puede inicializar (asignarle valores) un vector en el momento de declararlo. Si se lo hace así no es necesario indicar el tamaño. Su sintaxis es: tipo nombre []={ valor 1, valor 2...} Ejemplos: int vector[]={1,2,3,4,5,6,7,8}; char vector[]="programador"; char vector[]={'p','r','o','g','r','a','m','a','d','o','r'}; Una particularidad con los vectores de tipo char (cadena de caracteres), es que se debe indicar en qué elemento se encuentra el fin de la cadena mediante el caracter nulo (\0). Esto no lo controla el compilador, y debe ser el programador el que inserte este caracter al final de la cadena. Por tanto, en un vector de 10 elementos de tipo char se puede rellenar un máximo de 9, es decir, hasta vector[8]. Si sólo se rellena los 5 primeros, hasta vector[4], se debe asignar el caracter nulo a vector[5]. Es muy sencillo: vector[5]='\0';. 44 Ejemplo: /* Vector de tipo char. */ #include <stdio.h> #include <conio.h> main() /* Rellenamos un vector char */ { char cadena[20]; int i; for (i=0;i<19 && cadena[i-1]!=13;i++) cadena[i]=getche( ); if (i==19) cadena[i]='\0'; else cadena[i-1]='\0'; printf("\n%s",cadena); } Se puede ver que en el for se encuentran dos condiciones: Que no se hayan rellenado todos los elementos (i<19). Que el usuario no haya pulsado la tecla ENTER, cuyo código ASCII es 13. (cadena[x-i]!=13). También se observa una nueva función llamada getche( ), que se encuentra en conio.h. Esta función permite la entrada de un caracter por teclado. Después se encuentra un if, que comprueba si se ha rellenado todo el vector. Si es cierto, coloca el caracter nulo en el elemento nº20 (cadena[19]). En caso contrario se teine el else, que asigna el caracter nulo al elemento que almacenó el caracter ENTER. Llamadas a funciones con arrays Los arrays únicamente pueden ser enviados a una función por referencia. Para ello deberemos enviar la dirección de memoria del primer elemento del array. Por tanto, el argumento de la función deberá ser un puntero. Ejemplo: /* Envío de un array a una función. */ #include <stdio.h> void visualizar(int []); /* prototipo */ main() /* rellenamos y visualizamos */ { int array[25],i; for (i=0;i<25;i++) { printf("Elemento nº %d",i+1); scanf("%d",&array[i]); } visualizar(&array[0]); } 45 void visualizar(int array[]) /* desarrollo */ { int i; for (i=0;i<25;i++) printf("%d",array[i]); } Matrices Una matriz es un array multidimensional. Se definen igual que los vectores excepto que se requiere un índice por cada dimensión. Su sintaxis es la siguiente: tipo nombre [tamaño 1][tamaño 2]...; Una matriz bidimensional se podría representar gráficamente como una tabla con filas y columnas. En el siguiente ejemplo se puedes ver como se rellena y visualiza una matriz bidimensional. Se necesitan dos bucles para cada una de las operaciones. Un bucle controla las filas y otro las columnas. /* Matriz bidimensional. */ #include <stdio.h> main() /* Rellenamos una matriz */ { int x,i,numeros[3][4]; /* rellenamos la matriz */ for (x=0;x<3;x++) for (i=0;i<4;i++) scanf("%d",&numeros[x][i]); /* visualizamos la matriz */ for (x=0;x<3;x++) for (i=0;i<4;i++) printf("%d",numeros[x][i]); } Si al declarar una matriz también se quiere inicializarla, habrá que tener en cuenta el orden en el que los valores son asignados a los elementos de la matriz. A continuación se pueden observar algunos ejemplos: int numeros[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; quedarían asignados de la siguiente manera: numeros[0][0]=1 numeros[0][1]=2 numeros[0][2]=3 numeros[1][0]=5 numeros[1][1]=6 numeros[1][2]=7 numeros[2][0]=9 numeros[2][1]=10 numeros[2][3]=12 También se pueden inicializar cadenas de texto: Char dias[7][10]= 46 numeros[0][3]=4 numeros[1][3]=8 numeros[2][2]=11 {"lunes","martes","miércoles","jueves","viernes","sábado","domingo"}; 4.12 EJERCICIOS Para la implementación de los ejemplos desarrollados en esta guía se utilizó un IDE (Entorno de Desarrollo Integrado) para C/C++. Hay que aclarar que en cada uno de los ejercicios se incluyó el archivo de cabecera cstdlib, que permite la utilización de la sentencia system(“PAUSE”), esta sentencia obliga al compilador a detener la ejecución del programa hasta que el usuario pulse cualquier tecla, con la finalidad de poder observar el resultado que arroje la aplicación. Ejercicio 4.1 Traducción al lenguaje C del ejemplo 1.3. #include <cstdlib> #include <stdio.h> #define DIV 2 main() { float base, altura,float area; printf("Ingrese la Base del triangulo: "); scanf("%f",&base); printf("Ingrese la Altura del triangulo: "); scanf("%f",&altura); area= base * altura; area= area/DIV; printf("El Area del triángulo es: %f\n", area); system("PAUSE"); } Ejercicio 4.2 Traducción al lenguaje C del ejemplo 2.1. #include <cstdlib> #include <stdio.h> #define DIV 2 #define BASE 3 #define ALTURA 4 main() { float AREA; AREA=BASE*ALTURA/DIV; printf("El Area del triangulo es: %f\n", AREA); system("PAUSE"); } 47 Ejercicio 4.3 Traducción al lenguaje C del ejemplo 3.1. #include <cstdlib> #include <stdio.h> main() { float div, base, altura, area; div = 2; printf("Ingrese la altura: "); scanf("%f",&altura); printf("Ingrese la base: "); scanf("%f",&base); area = base * altura / div; printf("El Area del triangulo es: %f\n", area); system("PAUSE"); } Ejercicio 4.4 Traducción al lenguaje C del ejemplo 3.2. #include <cstdlib> #include <stdio.h> main() { printf("David Ausubel\n"); printf("David Ausubel\n"); printf("David Ausubel\n"); system("PAUSE"); } Ejercicio 4.5 Traducir al lenguaje C el algoritmo realizado en la actividad 3.1. Ejercicio 4.6 Traducción al lenguaje C del ejemplo 3.3. #include <cstdlib> #include <stdio.h> main() { int contador; for(contador = 1; contador <=100; contador++) printf("David Ausubel\n"); system("PAUSE"); 48 } Ejercicio 4.7 Traducción al lenguaje C del ejemplo 3.4. #include <cstdlib> #include <stdio.h> main() { int contador=0; int sumatoria=0; while (contador < 100){ contador += 1; sumatoria += contador; printf("%d\t", contador); printf("%d\n", sumatoria); } printf("[El valor de la suma 1+2+3+...+10 es] %d\n", sumatoria); system("PAUSE"); } Ejercicio 4.8 Traducción al lenguaje C del ejemplo 3.5. #include <cstdlib> #include <stdio.h> main() { int tabla, multiplicando, resultado, contador; printf("Tabla de multiplicar del? : "); scanf("%d", &tabla); for (multiplicando = 1; multiplicando<=10; multiplicando++){ resultado = multiplicando * tabla; printf("%d*%d=%d\n", tabla, multiplicando, resultado); } system("PAUSE"); } Ejercicio 4.9 Traducción al lenguaje C del ejemplo 3.6. #include <cstdlib> #include <stdio.h> main() { float calificacion; printf("Ingrese calificación: "); scanf("%f", &calificacion); 49 if(calificacion >= 7) printf("Aprobado\n"); else printf("Reprobado\n"); system("PAUSE"); } Ejercicio 4.10 Traducción al lenguaje C del ejemplo 3.7. #include <cstdlib> #include <stdio.h> main() { float matematicas; printf("Ingrese la nota de Matemáticas: "); scanf("%f", &matematicas); if(matematicas <= 8) printf("No come helado\n"); else printf("Si come helado\n"); system("PAUSE"); } Ejercicio 4.11 Traducción al lenguaje C del ejemplo 3.8. #include <cstdlib> #include <stdio.h> main() { int estudiante, aprobar; float examenUno, examenDos, trabajo, sumatoria, promedio; for (estudiante = 1; estudiante <=22; estudiante++){ printf("Ingrese la nota de examen uno: "); scanf("%f", &examenUno); printf("Ingrese la nota de examen dos: "); scanf("%f", &examenDos); printf("Ingrese la nota de trabajo: "); scanf("%f", &trabajo); if(examenUno < 0 || examenUno > 10 || examenDos < 0 || examenDos > 10 || trabajo < 0 || trabajo > 10){ printf("Datos no válidos\n"); }else{ sumatoria=examenUno+examenDos+trabajo; promedio=sumatoria/3; if(promedio < 6.5) 50 aprobar=0; //"NO" else aprobar=1; //"SI" printf("Promedio: %f\n", promedio); printf("Aprueba? "); if(aprobar == 1) printf("SI\n"); else printf("NO\n"); } } system("PAUSE"); } Ejercicio 4.12 Traducción al lenguaje C del ejemplo 3.9. #include <cstdlib> #include <stdio.h> main() { int ANGULO1, ANGULO2, ANGULO3, esRectangulo; printf("Ingrese ANGULO 1:"); scanf("%f", &ANGULO1); printf("Ingrese ANGULO 2:"); scanf("%f", &ANGULO2); ANGULO3=180-ANGULO1-ANGULO2; esRectangulo = 0; //"NO" if(ANGULO1 == 90) esRectangulo = 1; //"SI" else if(ANGULO2 == 90) esRectangulo = 1; //"SI" else if(ANGULO3 == 90) esRectangulo = 1; //"SI" else if(esRectangulo == 1) printf("SI es un triángulo Rectángulo\n"); else printf("NO es un triángulo Rectángulo\n"); system("PAUSE"); } Ejercicio 4.13 Traducir al lenguaje C el algoritmo realizado en la actividad 3.2. Ejercicio 4.14 Traducir al lenguaje C el algoritmo realizado en la actividad 3.3. Ejercicio 4.15 Traducir al lenguaje C el algoritmo realizado en la actividad 3.4. 51 BIBLIOGRAFÍA Hernandez Martinez, Ma. de Lourdes. Diseño estructurado de algoritmos, 1998. Lopez García, Juan Carlos. Algoritmos y programación, 2009. Pacho, Sergio. Curso de programación en C, 2001. 52