FUNDAMENTOS DE PROGRAMACIÓN Unidad 1: programas de computadora 1. Introducción Casi cualquier problema en las áreas de tecnología servicios y negocios puede ser resuelto con programas de computadora, estas soluciones generalmente son más confiables y de menor costo. Los programas de computadoras son parte esencial para la solución de problemas a cualquier nivel, estas soluciones son llamadas aplicaciones y son realizadas por un equipo multidisciplinario donde se encuentran los programadores, diseñadores y analistas de sistemas, entre otros especialistas. Los programadores utilizan lenguajes de programación para desarrollar las aplicaciones, estos lenguajes sirven como puente de enlace entre el análisis realizado por el equipo de desarrolladores y la capacidad de cálculo que ofrece la computadora. En otras palabras por medio del lenguaje de programación, el programador le indicará al computador la secuencia de instrucciones que se deben ejecutar para obtener la solución esperada por los clientes. Por todo lo anteriormente mencionado deducimos que el programador debe tener cierta lógica para trabajar con el lenguaje, esto es, debe saber exactamente las capacidades brindadas por el lenguaje y mas aun debe tener nociones claras de los fundamentos generales de la programación. La programación requiere una serie de conocimientos básicos comunes a cualquier lenguaje de programación que permitan indicarle al computador inequívocamente las tareas a realizar. Dichos conocimientos se conocen como fundamentos de programación, los cuales son un conjunto de reglas técnicas y conceptos que ayudan a definir lo que se puede hacer con un lenguaje de programación y así dar los primeros pasos para la solución de problemas computacionales. 2. Sistema de procesamiento Un ordenador es una maquina de procesamiento de información. Maquina porque tiene cables, circuitos y otros elementos mecánicos; de procesamiento porque es capaz de transformar o procesar datos y de información porque maneja conjuntos ordenados de datos. 3. Algoritmos Proceso para resolver problemas. Conjunto de acciones o secuencia de operaciones que ejecutadas en un determinado orden resuelven un problema planteado. Creado por: Abú Jafar Mohammed Imn Musa Khwararizmi Características: Tiene que estar bien definido Tiene que ser preciso Tiene que ser finito Básicamente un algoritmo es un proceso que define una serie finita de pasos sencillos y sin ambigüedades para la solución de un problema. La programación consiste adaptar un algoritmo al ordenador. El algoritmo es independiente de la implementación en algún lenguaje de programación. 4. Metodología para diseñar algoritmos El diseño de un algoritmo es un proceso creativo ya que no existe un conjunto de reglas que indiquen expresamente como escribir un algoritmo correctamente. Sin embargo, existen una serie de pasos que permiten resolver el problema de una manera más conveniente: Análisis del problema Diseño del algoritmo Verificación del algoritmo 4.1 Análisis del problema El primer paso es identificar el problema. Se debe revisar cuidadosamente el problema para determinar que tipo de información se necesita producir como salida. Luego se identifica toda la información que se necesita para encontrar la solución. En otras palabras es importante considerar lo que se nos esta pidiendo, con que elementos se cuenta y cuales se deben solicitar para así establecer el camino a seguir o la solución a implementar. 4.2 Implementación del algoritmo Es necesario buscar la manera más fácil para simplificar la propuesta. Una forma de hacerlo es identificar los procesos más importantes y colocarlos en orden ascendente según su importancia y precedencia, esto sirve como algoritmo inicial. Este puede ser refinado en sucesivas operaciones hasta obtener la solución más detallada y más fácil de traducir a un lenguaje de programación. 4.3 Verificación del algoritmo Cuando el algoritmo está listo, es necesario comprobar que cumple con los procesos diseñados y produce el resultado esperado. Una manera de hacerlo es por medio de la ejecución manual, que consiste en realizar una prueba con datos significativos y comprobar que al ejecutar todos los procesos se obtienen los resultados esperados. 5. programas de computadora Es una secuencia de instrucciones que le indican al computador que realice operaciones específicas para lograr un resultado deseado. Consiste en uno o más módulos o rutinas, cada uno de los cuales puede estar compuesto de varios subprogramas. Un programas es un conjunto de instrucciones que ejecutadas ordenadamente resuelven un problema, es la implementación de un algoritmo. Un programa de computadora no es: Una caja mágica Intrínsicamente correcto. Un programa de computadora es: Una solución a un problema. Secuencia de instrucciones hechas para ejecutarse computadora Sólo tan correcto como un programador lo haya hecho. en una 1. Definiciones básicas Lenguaje de alto nivel: es un lenguaje de programación orientado al problema, es el más cercano al lenguaje humano. Ejemplo: cobol, PL/I, fortran, java, etc. Algunos lenguajes de alto nivel se denominan orientados a objetos (ó OOPL): smalltalk, java, c++, eiffel, etc. Ventajas: Son independientes del procesador. Fáciles de aprender, implementar y mantener. Tienen carácter genérico. Desventajas: Menos eficientes en el manejo de los recursos. Requiere un proceso de traducción. Lenguajes de bajo nivel (ensamblador): es un lenguaje fuente que usa el programador para codificar sentencias simbólicas que un compilador puede convertir una a una en instrucciones de lenguaje de maquina, hace uso de mnemotecnicos, abreviaturas, para representar instrucciones de maquina. Ventajas: No es tan complicado como el lenguaje de maquina. Eficiente en el manejo de los recursos. Desventajas: Cada procesador tiene su propio ensamblador. Debe ser traducido. juego de instrucciones en Lenguaje de maquina: puede ser interpretado directamente por los circuitos internos de la computadora y está basado de ceros (0) y unos (1). Ventajas: No necesita ser traducido. Opera directamente con la maquina. Puede llegar a ser muy eficiente en el manejo de los recursos. Desventajas: Extremadamente difícil de aprender, implementar y mantener. Es único y particular de cada procesador. Compilar: traducir un programa hecho en un lenguaje de alto nivel a un lenguaje de maquina. Generalmente una instrucción de alto nivel se traduce a varias de lenguaje de maquina. El proceso de compilar se divide en 2 pasos: 1. Compilar las instrucciones de alto nivel para producir lo que se denomina el código objeto. 2. Enlazar (link) que es tomar el código objeto generado y cualquier otro código objeto requerido para que el programa este completo y colocarlos juntos para tener el programa ejecutable. Base de datos: colección de datos completa e integrada, organizada para evitar duplicados, que permite recuperar información para satisfacer a una amplia variedad de usuarios, Sistema operativo: es una colección organizada de software que se usa para ayudar y controlar las operaciones de una computadora. Almacenamiento: se refiere a un dispositivo en el que los pueden ingresar y retener y posteriormente recuperar. datos se 2. Crear un programa de computadora Para crear un programa el programador debe escribir las instrucciones del código fuente en un editor. Este conjunto de instrucciones se denominan archivo fuente, éste es la entrada para el compilador, que lo convierte en un conjunto de comandos entendibles por el computador llamado “programa ejecutable” Si se encuentra algún error en la sintaxis de los comandos en el archivo fuente, el compilador listará cada uno de ellos y no produce el ejecutable. 3. Funcionamiento del compilador/enlazador El compilador crea un archivo objeto y un listado del programa respalda la salida. El archivo objeto se usa como entrada al enlazador para realizar lo que se denomina el paso de “edición de enlace”. El enlazador combina el archivo objeto con otros archivos objetos ya existentes (éstos generalmente se encuentran en un archivo en disco llamado librería de enlace) para producir un programa ejecutable. 4. Datos, tipos de datos, operaciones incorporadas Para que un programa de computadora pueda ser ejecutado debe ser cargado en memoria. La unidad del procesamiento del computador sólo puede trabajar con los datos instrucciones cargadas en memoria. 4.1 Dato Es cualquier elemento de información que se usa a lo largo del programa, son elementos sobre los que se opera cuando se efectúa alguna instrucción. Normalmente un dato tiene un nombre que lo identifica y distingue de los demás, dicho nombre no es más que otra forma de referenciar la dirección de memoria que ocupa el dato. Los datos pertenecen a un tipo de dato específico, que indica el rango de valores que dicho dato puede aceptar y las operaciones que sobre él se pueden hacer. 4.2 Tipo de dato Es una definición que agrupa los valores válidos para un conjunto de datos y las operaciones que se pueden realizar sobre ellos. Los tipos de datos pueden ser: Primitivo: tipos básicos o simples predefinidos en el sistema o definidos por el usuario. o numéricos: enteros, real. o lógicos o boléanos. o carácter. o cadena o string. Complejos: agregados por el programador. Los diversos lenguajes de programación pueden añadir más tipos de datos. En algunos lenguajes se definen tipos especiales para la fecha y hora, sobre todo en los mas modernos tales como java. 4.3 Constantes y variables Las constantes son instancias de un tipo de dato cualquiera que tiene un valor fijo, que se le da cuando se define. Este valor no puede ser modificado durante la ejecución del programa. Las variables son instancias de un tipo de dato cualquiera cuyo valor pude cambiar durante la ejecución del programa. Las variables deben declararse indicando su nombre y su tipo, antes de usarlas. El nombre que se le da a una variable tiene que ser significativo, éste será un conjunto de caracteres que dependiendo del lenguaje pueden tener ciertas restricciones, a esto se le conoce como reglas para construir identificadores. Un identificador es una palabra que no es propia del lenguaje, la construye el programador basándose en ciertas reglas. En algunos lenguajes las variables pueden tomar un valor por defecto si al declararla no se le asigna un valor inicial. Las constantes pueden llevar asociados un nombre o no, si no lo llevan se llaman literales. Su valor hay que darlo al momento de la declaración y ya no puede cambiar a lo largo del programa. Y en cuanto al tipo de dato en algunos lenguajes hay que ponerlo, en otros no hace falta. 4.4 Relación entre variables y constantes en memoria Al declarar una variable o constante con nombre, el sistema reserva un espacio de memoria. El espacio reservado depende del tipo de dato de la variable o constante. En esa zona es en la que se guarda el valor asociado a la variable o constante y cuando el programa use la variable o constante, irá a ese lugar a buscar el valor. 5. Expresiones: tipos y operadores Una expresión es una combinación de constantes, variables, signos de operación, paréntesis y nombres especiales, con un sentido univoco y definido. De la evaluación de una expresión resulta un único valor o resultado. Toda expresión tiene asociada un tipo que se corresponde con el tipo del valor que devuelve la expresión cuando se evalúa. Existen expresiones numéricas y lógicas. 5.1 Expresiones numéricas: operadores aritméticos Es una combinación de variables y constantes numéricas con operadores aritméticos y que al evaluarla devuelve un valor numérico. Los operadores más comunes: +,-,*,/. Otras operaciones programación son: aritméticas soportadas en algunos lenguajes de Operación resto: devuelve el resto de una división lenguaje c pascal operador % mod ejemplo 5%2 5mod2 resultado 1 1 Operación división entera: devuelve el cociente de una división entera en la que no se consideran los decimales. lenguaje c pascal operador / div ejemplo 5/2 5 div 2 resultado 2 2 Operación potencia: devuelve el valor de una base elevada a una potencia dada. lenguaje operador ejemplo resultado basic ^ 5^2 25 Todos los anteriores son operadores binarios, el operador de coloca en el medio y toma 2 operandos. También existen los operadores que utilizan sólo un operando y se denominan unarios. El signo negativo: devuelve el valor actual del operando multiplicado por (-1) lenguaje c operador - ejemplo x=5; -x Operador decremento e incremento: devuelven decrementado o incrementado en una unidad. resultado x=-5 el valor actual --5; ++5; 5.2 Reglas de precedencia El orden en que se evalúan los operadores aritméticos dentro de una expresión influye directamente en el resultado que retorna en dicha expresión veamos el siguiente ejemplo para comprender: 2+3*2+3; Si se evalúa en el orden de aparición tendríamos algo como lo siguiente (((2+3)*2)+3); Resultado: 13 Si se evalúa primero las sumas y luego la multiplicación se tendrá la siguiente expresión: (2+3)*(2+3); Resultado: 25 Si se evalúa primero la multiplicación y luego la suma se tendría la expresión: 2+(3*2)+3; Resultado: 11 Entonces, como resolver esta situación potencialmente problemática? La solución es aplicar prioridad entre los operadores de modo que ante la posibilidad de usar varios operadores aritméticos en una misma expresión siempre aplicaremos primero el de mayor prioridad. Cada lenguaje puede establecer sus propias reglas de prioridad. Siempre se puede utilizar los paréntesis para definir y cambiar el orden en que se evalúa una expresión aritmética. El orden de precedencia definido comúnmente para los operadores aritméticos básicos es: 1. ^ 2. *, /, div y mod 3. +yEntre dos operadores que tienen la misma precedencia para resolver la ambigüedad hay que usar la regla de asociatividad. La más normal es la de la asociatividad por la izquierda. 1.2 expresiones lógicas: operadores relaciónales y lógicos Una expresión lógica es aquella que solo puede devolver uno de dos valores (verdadero o falso). Los valores que pueden aparecer en una expresión lógica son de dos tipos. Lógicos y relacionales. Los operadores lógicos solo trabajan sobre expresiones o datos que retornan valores booleanos. Los operadores relacionales trabajan con expresiones numéricas para realizar comparaciones que retornan un valor booleanos. Es común tener expresiones que combinan tanto los operadores lógicos como relacionales, en estas expresiones se evalúan más de una condición o relación por medio de operadores lógicos. Los operadores relacionales mas usados son: < menor que > mayor que = igualdad (= =) <> diferente (en c: ¡=) <= menor o igual que => mayor o igual que ¿Cómo se evalúa una expresión relacional? 1. se evalúa el primer operando y se sustituye por su valor 2. se evalúa el segundo operando y se sustituye por su valor. 3. se evalúa el operador relacional y se devuelve el valor booleano correspondiente. ((5*4)+1 –(5^2)) <(2-1); -4 < 1; la expresión retorna a verdadero. UNIDAD 2: CONCEPTOS DE DISEÑO ESTRUCTURADO 1. Introducción Las técnicas para facilitar el entendimiento del problema son: El diseño TOP-DOWN (de arriba hacia abajo) Los diagramas de estructura Los diagramas de flujo El pseudocódigo 2. Conceptos de Diseño Estructurado Las características del diseño estructurado son: Tiene una entrada y una salida con variaciones ocasionales Utiliza programación modular Elimina el uso de la sentencia GOTO. 3. Diseño Top Down (refinamiento “paso a paso”) El diseño top down, que implica ir de lo más general a lo más específico, es el proceso de dividir un problema en subproblemas más pequeños. Para entender el diseño top down vea el siguiente problema: Se le ha solicitado que escriba un programa para una tienda de videos. El objetivo del programa es permitir que un cliente registrado en la tienda alquile videos. La tienda tiene un conjunto de reglas que deben cumplirse para que un cliente alquile un video, las cuales son: El cliente es un miembro registrado No tiene ningún alquiler vencido No debe nada a la tienda La película está en el inventario La película no está reservada Un programa de alto nivel será: Alquilar un video. Al descomponer este programa de alto nivel, se obtienen los siguientes subprogramas: Verificar si el cliente es un miembro registrado Verificar los alquileres vencidos Verificar si el miembro debe algún dinero Verificar si la película está en el inventario Verificar si la película ha sido ya reservada Al descomponer de nuevo, cada uno de los pasos anteriores, se obtiene: 1. Verificar si el cliente es un miembro registrado: Ingresar el número de teléfono u otra identificación del cliente en el sistema Leer la pantalla para ver si el sistema ha encontrado un perfil que coincide 2. Verificar los alquileres vencidos: Ver si el perfil refleja cualquier alquiler vencido en el sistema 3. Verificar si el miembro debe algún dinero: Ver si el perfil refleja algún cargo pendiente 4. Verificar si la película está en el inventario: Ingresar el nombre de la película al sistema Verificar si hay alguna copia que no está alquilada 5. Verificar si la película ha sido ya reservada: Ver si las copias que no están alquiladas no están reservadas. De nuevo, al descomponer el sub-programa "Verificar si el cliente es un miembro registrado" 1.1. Verificar si el cliente es un miembro registrado Preguntar el número de teléfono u identificación al cliente 1.2. Ingresar el número de teléfono en el sistema: Seleccionar del menú la opción de verificar el número de miembro llenar el número de teléfono del cliente en el prompt Presionar la tecla que indica al sistema que se está listo para que éste verifique por un número que coincida con el que se ha ingresado 1.3. Leer la pantalla para ver si el sistema ha encontrado alguna coincidencia Visualmente, verificar si el sistema dice que 'sí' o 'no' es un miembro. 4. Diagramas de Estructura Es una manera gráfica de representar el diseño top down. Nos Permite representar en forma clara la organización de alto nivel de un programa. Un diagrama de estructura parcial del ejemplo anterior: Alquilar una película Verificar si es miembro Preguntar No TEL Verificar alq. vencidos Ingresar No TEL Verificar deudas pendientes Examinar Perfil Verificar sí esta en Inventario Verificar si no está reservada Diagrama de Estructura del Problema Anterior 5. Diagramas de Flujo Es una representación gráfica de la lógica del diseño. Generalmente, está a un nivel de detalle más bajo que los diagramas de estructura. Un diagrama de flujo resulta adecuado cuando se desea seguir bajando a un nivel con mayor detalle, tal como agregar bifurcación de condicionales y/o iteración. 5.1 Símbolos Líneas de flujos Conectores Proceso Pantalla Entrada / salida Condición Teclado Principio y Fin Entrada / salida por Disco Subprograma 5.3 Metodología para resolver un problema con diagramas de flujo A Determinar Requerimientos del proceso Determinar Requerimientos del post-proceso Crear Diagrama de flujo Verificar Diagrama de flujo ¿Diagrama de Flujo OK? NO SI Metodología para resolver un problema con Diagrama De Flujo FIN 6. Diagramas N-S O de Nassi-Schederman: Es una forma de representación semejante al diagrama de flujo, pero sin flechas y cambiando los símbolos de condición y repetición. Está conformado por una serie de cajas de procesos que constituyen las secuencias de acciones necesarias para presentar el algoritmo. Las cajas de proceso o acción van unidas entre sí. Los Diagramas N-S son muy útiles para representar diagramas estructurados. Representación de Condiciones: Condición Condición SI Bifurcación <Acción 1 > NO <Acción 2 > Estructuras Repetitivas: Mientras <Condición> <Acciones> Para var desde V1 hasta V2 Ciclos Repetitivos <Acciones> Repetir hasta <Condición> <Acciones> 6.1 Ejemplo de Diagrama N-S o de Nassi-Schederman Se presenta a continuación de nuevo el problema de determinar el producto de un conjunto de enteros representada la solución con un diagrama de NS. INICIO p=1 Leer num Mientras (num >= O) P = P x num Leer num Escribir p FIN Figura 2.4: Diagrama de NS para el Cálculo del Producto de Enteros 7. Pseudocódigo El Pseudocódigo es un lenguaje de documentación de programas similar al inglés (o español) que se parece a cualquier lenguaje de programación de alto nivel, pero no necesita seguir ninguna regla específica, como si lo requieren los programas que van a ser traducidos o compilados. El pseudocódigo normalmente no es muy específico para las áreas de E/S. El pseudocódigo tiene la ventaja que se puede crear fácilmente con cualquier editor de texto. No hay ningún estándar en la industria definido para los pseudocódigos. Un ejemplo de pseudocódigo parecido a PL/I, se muestra a continuación: do while(count = O ) do process count = count - 1 end Un ejemplo de pseudocódigo parecido a COBOL: perform until count = O perform process subtract 1 from count end-perform El pseudocódigo también puede utilizar una serie de palabras claves o palabras especiales que van indicando lo que significa el algoritmo. Ejemplo de palabras claves en pseudocódigo: 1. Inicio y Fin: Por donde empieza y termina el algoritmo. 2. Si <condición> Entonces <acciones> Sino <acciones> 3. Mientras <condición> hacer 4. Repetir / hasta <condición> 5. Desde / hasta 6. Según sea (Para evaluar opciones múltiples) Los comentarios van encerrados entre llaves. Hay que utilizar la identación. La estructura recomendada para los algoritmos en pseudocódigo es: Algoritmo <nombre algoritmo> Var <nombre>: <tipo> Inicio <Instrucciones> Fin 8. Programación Modular Cuando se trabaja con programas grandes se hace difícil: Desarrollar la lógica Escribir el código Probar totalmente el código Realizar el mantenimiento La solución para esto es usar la programación modular. La programación modular rompe el programa en unidades o módulos más pequeños y manejables. Estas unidades más pequeñas se llaman subprogramas, procedimientos o funciones dependiendo del lenguaje que se esté usando. El ejemplo de la Tienda de video representado en forma modular se presenta en la siguiente Figura. Módulo Principal Módulo Cliente Módulo Películas Verificar Cliente Verificar Alquileres vencidos Deudas pendientes Verificar Existencia Verificar Reservaciones Representación de la Programación Modular de la Tienda de video UNIDAD 3: PROGRAMACIÓN ESTRUCTURADA 1. Introducción La característica fundamental de la programación estructurada es que se basa en el uso únicamente de tres estructuras de control. Para ello se apoya en los siguientes conceptos: Recursos abstractos: Son los recursos que se tienen en el momento de programar, Estos recursos se tienen que ir transformando en recursos concretos. Diseño descendente (top down): Se trata de ir descomponiendo el problema en niveles cada vez más sencillos Estructuras básicas de control: Para construir un programa se siguen los pasos de razonamiento anteriores y al final se codifica el programa usando tres tipos de secuencias: repetitivas, alternativas y secuenciales. Al final todo programa va a tener una única entrada y una única salida. Desde la entrada tienen que existir caminos que permiten pasar por todas las partes del programa y llegar a la salida, no se van a permitir los bucles infinitos. 2. Estructuras Secuenciales En las estructuras secuenciales una instrucción sigue a otra en secuencia, es decir, la salida de una instrucción es la entrada de la siguiente. FLUJOGRAMA Diagramas N-S PSEUDOCODIGO Leer num num = num * 2 Escribir num 3. Estructuras Selectivas Se evalúa una condición y en función del resultado lógico (verdadero o falso) se ejecuta un conjunto de instrucciones u otro. Son también denominadas estructuras de control de flujo, estructuras condicionales y de toma de decisiones. Hay tres tipos: simples, dobles o múltiples. 3.1 Estructura Selectiva Simple La estructura selectiva simple es la estructura condicional elemental y básica. Presenta la forma: Sí <condición> entonces <Acciones> Fin si Evaluamos la condición. Si el resultado es verdadero, ejecutamos el conjunto de acciones asociadas al bloque entonces. Si el resultado es falso, no ejecutamos acción alguna. FLUJOGRAMA Diagramas N-S Si <condición> SI Condición SI Condición Acciones Acciones 3.2 PSEUDOCODIGO Acciones Estructura Selectiva Doble Entonces <Acciones> Fin si La estructura selectiva doble es una estructura condicional que evalúa una condición dada. Si es verdad, se ejecutan el conjunto de acciones asociadas a la parte entonces. Si es falso se ejecutan el conjunto de acciones asociadas a la parte sino. FLUJOGRAMA SI Condición Diagramas N-S No Acciones SI Acciones PSEUDOCODIGO Si <condición> Entonces <Acciones> Sino <Acciones> Fin si Condición Acciones Acciones Acciones Acciones 3.2 Estructura Selectiva de Alternativa Múltiple Se evalúa una condición o expresión que puede tomar n valores distintos. Según sea el valor de la expresión en ese instante de tiempo se ejecutan las acciones correspondientes al valor. En muchos lenguajes se conocen como sentencias Case o Switch. Es una sentencia de la forma: Según sea <expresión> <valor1>: <acciones 1> <valor2>: <acciones 2> [<otro>: <acciones n>] fin según En la opción Otro: las acciones asociadas a éste se ejecutan cuando la expresión no toma ninguno de los valores que aparecen antes. El valor con el que se compara la expresión es dependiente de los lenguajes de programación. Por lo general se espera un tipo de dato determinístico y con valores secuencia les tales como los enteros y caracteres. En general ese valor puede ser un valor constante, un rango de valores deterministico o incluso otra condición. FLUJOGRAMA Diagramas N-S Expr Expr V1 V2 Vn V1 V2 Vn otr PSEUDOCODIGO Según sea <expresión> <valor1>:<acciones> <valor2>:<acciones> [<otro> : <acciones>] Fin según 4. Estructuras Repetitivas o de Ciclo Las estructuras repetitivas o de ciclo contienen o representan un bucle o conjunto de instrucciones que se repiten un número finito de veces. Cada repetición del bucle se llama una iteración. Todo bucle tiene asociada una condición, que es la que va a determinar si se ejecuta el bucle y hasta cuando. Existen tres tipos de básicos de estructuras repetitivas: 1. Mientras-hacer (While do) 2. Repetir-hasta (Repeat until) 3. Desde (For) 4.1 Estructura Repetitiva Mientras-hacer Aquí la condición de entrada al ciclo se evalúa antes realizar cualquier iteración del bucle. Si la condición no se cumple, el ciclo no se ejecuta y el programa continúa con la secuencia de acciones siguientes al ciclo. Si la condición es verdadera, se comienza a ejecutar las acciones del Mientras-hacer. Después de la última acción, se repite el proceso de evaluación de la condición; si la condición es verdadera de nuevo, se repite las acciones. Este proceso se conoce como un bucle y continua hasta que la condición sea falsa, y la ejecución prosigue con la sentencia siguiente del programa. Al evaluarse la condición antes de entrar en el bucle al principio, si la condición al ser evaluada la primera vez es falsa, no entraremos nunca en el bucle, el bucle puede que se ejecute O veces, por tanto se usará este tipo de bucle en el caso de que exista la posibilidad de que el bucle pueda ejecutarse O veces. 4.2 Estructura Repetitiva Repetir-hasta Aquí la condición del ciclo se evalúa después de realizar la primera iteración del bucle. Este bucle se repite mientras la condición evaluada al final se mantenga falsa. Al cumplirse la condición y ser verdadera, se sale del bucle. De allí su nombre "repetir hasta" que se cumpla la condición. Se repite el bucle hasta que la condición sea verdadera. En otras palabras, el bucle se repite y ejecuta mientras la condición sea falsa. La condición se evalúa siempre al final del bucle, si es falsa volvemos a ejecutar las acciones, si es verdad se sale del bucle. Como la condición se evalúa al final se pasa al menos una vez por el bucle. Es decir que cuando un bucle se tenga que ejecutar como mínimo una vez, se puede usar una estructura repetir hasta. Si se quiere usar una estructura mientras hacer, la única diferencia es que se debe asegurar que la condición de entrada sea verdadera para dicho ciclo. 4.3 Estructura Repetitiva Desde Se usa cuando se sabe el número exacto de veces que se va ha ejecutar el bucle. El bucle lleva asociado una variable que se denomina variable índice, a la que le asigna un valor inicial y se establece cual va a ser su valor final. La variable índice se incrementa o decrementa en cada iteración del bucle en un valor constante de manera automática. El programador no se tiene que ocupar de actualizar el valor de esta variable en cada iteración del bucle; es una operación implícita. Por tanto en cada iteración del bucle, la variable índice se actualiza automáticamente y cuando alcanza el valor que se establecido como final se termina la ejecución del bucle. 5. Estructuras Anidadas Las estructuras selectivas como los bucles se pueden escribir unas dentro de otras. Esto se conoce como estructuras anidadas. 5.1 Anidación de Condicionales En ocasiones se requiere evaluar un conjunto de condiciones en forma secuencial y separada. En estos casos, se recomienda utilizar una anidación de condicionales. La ventaja de anidar sentencias condicionales, es que cuando una se cumple no hay por que evaluar las condiciones que están debajo o que le siguen. Sintaxis: Si <condicion1> Entonces <sentencia1> Sino si <condicion2> Entonces <sentencia2> Sino si <condicion3> Entonces <sentencia3> Fin si Fin si Fin si OJO: La sentencia según sea (case) siempre equivale a una anidación de condicionales, pero lo contrario no es cierto. 5.2 Bucles Anidados Al igual que se pueden colocar unas expresiones dentro de otras, los bucles pueden estar unos dentro de otros. Al anidar bucles hay que tener en cuenta que el bucle interno funciona como una sentencia más en el bloque del bucle externo, por lo tanto, en cada iteración del bucle externo se van a ejecutar todas las iteraciones del bucle interno. Los bucles deben estar bien formados y ser sintácticamente, nunca pueden cruzarse las sentencias de los bucles. Si se tiene un ciclo desde que internamente posee un ciclo mientras hacer, es necesario finalizar las sentencias o instrucciones del ciclo más interno en este caso mientras-hacer antes de colocar la culminación del ciclo externo desde. Si el bucle más externo se repite n veces y el más interno se repite m veces, si por cada iteración del más externo se repite el más interno, el número total de iteraciones será el producto de m * n. Los bucles que se anidan pueden ser de igual o distinto tipo. Ejemplo: Desde i=1 hasta 8 Desde k=1 hasta 5 Escribir "Profesor n” i “introduzca asignatura Nº” k Leer asignatura Fin desde Fin desde Note como cada ciclo interno termina antes de cerrar el más Externo. No existen limitaciones en cuanto al número de sentencias y estructuras anidadas que se pueden anidar en un mismo bloque, esto depende del lenguaje que se está usando. No obstante no se recomienda abusar de los anidamientos ya que resultan en un código difícil de leer y por lo tanto difícil de mantener. 6. Control de Datos de Entrada Existen una serie de situaciones comunes en programación donde se toman datos desde un dispositivo de entrada y se requiere de alguna forma de control implementada por bucles. 6.1 Usando un Valor Centinela que Determina el Fin del Bucle En este caso se espera la entrada de un valor centinela para decidir si se va ingresar al ciclo o no de entrada de datos. El bucle se va a repetir mientras no se lea un valor determinado. La primera lectura se va a realizar fuera del bucle. Si al ingresar el dato de entrada, éste es el valor centinela no se entra en el bucle y se seguirá con el resto del algoritmo. En caso contrario, se entra en el bucle para seguir con la entrada de datos. Se recomienda utilizar una estructura Mientras-hacer. Ejemplo: Centinela = 9 Leer opción Mientras (opción <> centinela) hacer <Acciones> Leer opción Fin mientras 6.2 Lectura Secuencial de un Archivo Los datos de entrada pueden estar en un archivo, el cual debe ser leído desde el primer al último registro para recuperar todos los datos, para ello se realiza una lectura secuencial de todos los registros del archivo. Una estrategia común de lectura para un archivo con acceso secuencial es: Abrir el archivo, Leer un registro del archivo, Verificar si no es fin de archivo al entrar a un ciclo para recorrer el archivo realizar operaciones con los datos de entrada, Volver a leer datos del archivo, con cada operación de lectura se avanza de registro en registro en los datos del archivo Regresar al ciclo hasta que sea fin de archivo. Ejemplo: Archivo mi_archivo Abrir_Archivo (mi_archivo) Leer_Archivo (mi_archivo) Mientras (NOT (Fin_de_Archivo(mi_archivo))) Hacer <acciones con los datos del archivo> Leer_Archivo (mi_archivo) Fin mientras 6.3 una Cuando se Sabe el Número Exacto de Veces que se Ejecuta Acción o Proceso Cuando se sabe el número exacto de veces que se ejecuta una acción o proceso la opción natural para realizar el control de entrada es utilizar un ciclo o bucle Desde...Hasta. Normalmente, el número de veces que se desea repetir el proceso a controlar es solicitado como un valor de entrada o es suministrado desde alguna otra fuente (variable de entorno, constante, archivo de configuración, entre otros). Una vez que se obtiene este valor, se le asigna a la variable de índice para el ciclo Desde. Se efectúa la operación hasta que se cumpla el número de veces deseado. Ejemplo: i: Entero Mostrar "Ingrese el numero da materias a registrar:” Leer número materias Desde i =1 Hasta numero materias Mostrar "Ingresar datos Materia numero “ Leer materia <Acciones a realizar con materia> Fin desde 6.4 Control de Datos Para no Permitir Datos Erróneos El control de ingreso de datos para evitar datos de entrada erróneos se usa cuando se controla al usuario para que introduzca los datos correctos. Por ejemplo: un valor numérico dentro de un rango determinado. En estos casos se recomienda usar un ciclo Repetir...Hasta. Ejemplo: opcion: Entero opción=0 Repetir Mostrar "Menú:” Mostrar "1. Crear Archivo" Mostrar "2. Borra Archivo" Mostrar "3. Incluir Registro" Mostrar "4. Salir del sistema" Mostrar "Su opción:" Leer opción Hasta (opción >= 1) Y (opción <= 4) UNIDAD 4: PROCEDIMIENTOS Y FUNCIONES 1. Introducción La programación modular es una de las técnicas fundamentales de la programación. Se apoya en el diseño descendente y en la filosofía de "divide y vencerás” Siempre existirá un módulo o programa principal donde comienza la ejecución de todo el programa. A partir de éste, se van llamando al resto de los módulos que posea el sistema. Cada vez que se invoca a un subprograma se le pasa la información que necesita en la llamada, seguidamente comienza a ejecutarse y cuando éste termina su ejecución, el control se devuelve a la instrucción siguiente a la línea de código en la cual se efectuó la llamada en el programa o subprograma. La estructura de un subprograma es muy similar a la estructura de un programa normal, va a tener una información de entrada que es la que se le pasa al hacer la llamada y que se coloca junto al nombre del subprograma. Esta información de entrada se denomina parámetros formales del subprograma o argumentos formales. Dentro del cuerpo del subprograma se pueden colocar cualquier número de acciones o sentencias de código, e incluso declarar variables y llamar a otros módulos tal como se hace desde un programa principal. Al terminar la ejecución del modulo o subprograma puede que este ultimo devuelva o no resultados o valores al programa que lo llamó. A los subprogramas que pueden retornar valores usualmente se les denominan funciones, mientras que a los subprogramas que no poseen valor de retorno se les denomina comúnmente procedimientos. 2. Funciones Desde el punto de vista matemático, una función es una' operación que toma uno o varios operandos (parámetros) y devuelve un resultado. Desde el punto de vista algorítmico una función es un subprograma que toma uno o varios parámetros como entrada y devuelve a la salida un único resultado. Existen dos tipos de funciones: Internas o Incorporadas: vienen definidas por defecto en el lenguaje. Externas o del Usuario: las define el usuario y tienen un nombre o identificador. Para llamar a una función se da su nombre y entre paréntesis van los argumentos o parámetros que se le quieren pasar a la función. 2.1 Declaración de una Función La estructura de una función es semejante a la de cualquier subprograma. Tendrá una cabecera con el nombre y los parámetros, y un cuerpo con la declaración de los parámetros de la función y las instrucciones. 2.1.1 Sintaxis La sintaxis para la declaración de una función depende del lenguaje de programación utilizando, se propone un esquema que usa la palabra Función para indicar el inicio de la función seguido del identificador o nombre, la lista de parámetros, el tipo de dato de retorno de la función y por último el cuerpo de la función enmarcado entre sentencias de inicio y fin de bloque de código. Funcion <nombre funcion> (nombre parámetro: tipo): tipo retorno Var <variables locales de la funcion> Inicio <acciones> retorno <valor> fin <nombre función> La lista de parámetros es la información que se le tiene que pasar a la función. Los parámetros dentro del cuerpo de la función se utilizan como variables locales definidas en la función. Es necesario definirle a cada parámetro su nombre y tipo de dato al momento de declarar la función. El nombre de la función lo da el programador y debe ser un nombre significativo. En las variables locales se declaran las variables que se desea utilizar dentro de la función. Dentro del cuerpo de la función se escriben todas las acciones o sentencias de código destinadas a cumplir el propósito de la función. Por definición una función siempre debe devolver algún valor. Algunos lenguajes de programación declaran un tipo de dato nulo para permitir así que las funciones "no retornen" valores, aunque en realidad retornan un tipo no utilizado. Los parámetros que aparecen en la declaración de la función se denominan parámetros formales. Los parámetros que se utilizan cuando la función es invocada se denominan parámetros actuales o reales. Estos últimos son las constantes, valores de retorno, expresiones, variables u otro elemento del contexto de la llamada que es necesario pasarle a la función. 2.2 Invocar una función Para llamar o invocar a una función se coloca el nombre de la función y entre paréntesis se añaden los parámetros reales que necesita la función. Los parámetros reales pueden ser variables, expresiones e incluso constantes, pero siempre deben corresponder al mismo tipo de datos que los parámetros formales asociados con la función. Por ejemplo: Funcion sumarEnteros (num1: Entero, num2:Entero): Entero Var resultado: Entero Inicio Resultado=num1 + num2 Retornar resultado Fin sumarEnteros La función puede ser llamada desde el programa principal o desde cualquier otro subprograma así: Var resultado : Entero numero : Entero Inicio Resultado=sumarEnteros(8, 9) Mostrar “8 + 9 es: " resultado numero=12; resultado= sumarEnteros(numero, 5) Mostrar "12 + 5 es:” resultado Mostrar "2 + 2 es:” sumarEnteros(2, 2) Fin Para que una función pueda ser invocada desde cualquier parte de un programa, es necesario que la definición de dicha función ya sea del conocimiento previo del compilador antes de usarla. A través de los parámetros reales de la llamada se proporciona a la función la información que necesita para cumplir su cometido y, al momento de hacer la llamada se produce una asociación automática entre los parámetros reales y los parámetros formales. Esta asociación se realiza según el orden de aparición de izquierda a derecha de los parámetros formales de la función. Como regla general el parámetro real y su correspondiente parámetro formal deben ser del mismo tipo. 2.3 Pasos para Hacer la Llamada a una Función Cuando se efectúa la llamada, se cede el control a la función y se asocia, es decir, se asigna el valor de cada parámetro real al parámetro formal correspondiente. Si la llamada a la función es válida entonces se ejecutan las acciones de la función hasta que se encuentre una instrucción del tipo retorno <valor>. Esta instrucción pondrá fin a la ejecución de la función y el control se pasa al punto siguiente de donde se efectuó la llamada. Pueden existir varias sentencias de retorno en la misma función, colocadas en diferentes bloques de código y normalmente dependen de sentencias condicionales para su ejecución. 3. Procedimientos Un procedimiento es un subprograma que realiza una determinada tarea, pero que tras ejecutar esa tarea no tiene ningún valor asociado a su nombre como ocurre en las funciones. Si un procedimiento devuelve información, lo hace a través de parámetros de entrada-salida o de salida. Al invocar a un procedimiento, se le cede el control, comienza a ejecutarse y cuando termina devuelve el control a la instrucción siguiente al punto donde se efectuó la llamada. 3.1 Diferencias entre Funciones y Procedimientos 3.2 Las funciones están diseñadas para devolver un único valor y un procedimiento puede devolver ningún o muchos valores por medio de sus argumentos o parámetros. Ninguno de los resultados devueltos por el procedimiento se asocia a su nombre como ocurre con la función. Mientras que la llamada a una función siempre puede formar parte de una expresión, la llamada a un procedimiento es una instrucción aislada, que por sí sola no puede formar parte de una expresión. Sintaxis La sintaxis para declarar un procedimiento es esencialmente la misma que para definir una función, sólo que no se coloca un tipo de retorno asociado. La cabecera va a estar formada por el nombre del procedimiento que será un identificador válido y que debe ser significativo. Luego, entre paréntesis, se deben colocar los parámetros o argumentos formales que requiere el procedimiento. Por cada parámetro es necesario indicar el tipo de paso de parámetro. Hay dos tipos fundamentales de paso de parámetros: Por valor Por referencia Si no se declara explícitamente el tipo de paso de parámetros, se asume por omisión el tipo de paso de parámetros por valor. En el cuerpo del procedimiento se colocan todas las sentencias necesarias para cumplir con su tarea y no habrá ninguna sentencia de tipo retorno <valor>. Ahora bien, si el procedimiento devuelve resultados a través de sus parámetros, cosa que sólo podrá hacer a través de los parámetros que se pasan por referencia, tendrán que existir sentencias de asignación de valores a estos parámetros pasados por referencia para devolver los resultados. 3.3 Pasos para Hacer la Llamada a un Procedimiento En primer lugar, desde el programa principal o subrutina, se coloca el nombre del procedimiento con su lista de parámetros reales entre paréntesis como una sentencia única. Esto cede el control al procedimiento que se llama y después de esto lo primero que se hace es sustituir cada parámetro formal de la definición por el parámetro actual o real de la llamada asociado a él. Esta asociación entre parámetros formales y reales se realiza de izquierda a derecha por orden de ubicación. Para que se pueda producir la asociación tienen que existir el mismo número de parámetros formales que reales y además, el tipo de dato tiene que coincidir con el del parámetro formal asociado. Se produce un error en la llamada al procedimiento si no se cumple alguna de estas condiciones Finalmente se cede el control a la instrucción siguiente a la que efectuó la llamada al procedimiento. Ejemplo: Procedimiento mitad(num:entero, ent-sal med: real) Inicio med = num/2 Fin mitad Algoritmo calcular_mitad Var n: entero mit: real Inicio Escribir "Introduce un número" Leer n mitad (n, mit) Escribir "La mitad esu mit fin En el ejemplo anterior ent-sal med: real, se usa para indicar que el parámetro del tipo real med es de entrada-salida o que es un parámetro por referencia. 4. Ámbitos: Variables Globales y Locales El ámbito de un identificador ya sea variable, constante, función, entre otros, se refiere a la parte del programa en la que se conoce y por tanto se puede usar a un identificador cualquiera. Recuerde que un identificador es un nombre construido bajo ciertas reglas de sintaxis y se asocia aún elemento del programa. Existen dos tipos de ámbitos básicos: El ámbito global: Se refiere a los identificadores que se declaran dentro del programa principal y fuera de cualquier otro bloque de código. Al ser declarados de esta forma los identificadores globales están disponibles a lo largo del programa y podrán ser usados en cualquier parte del mismo, de allí su nombre de globales porque se dice que son globales al programa . El ámbito local: Se refiere a los identificadores declarados dentro de un bloque de código diferente al programa principal, como por ejemplo una subrutina o procedimiento, siendo visibles y accesibles por lo tanto sólo dentro de ese bloque de código especifico. Como regla general todo identificador sólo es visible y accesible dentro del bloque de código que lo declara y dentro de los bloques anidados que este último pueda tener. Lo contrario no es cierto, es decir, los identificadores declarados en un subbloque de código no son visibles ni accesibles desde el bloque de código del cual depende. El ámbito es importante cuando se trabaja con variables, por lo que se tienen variables locales y globales 4.1 Variable Local Una variable local es aquella que está declarada y definida dentro de un subprograma o subbloque de código. Esto quiere decir que la variable no tiene ningún significado, no se conoce y no se puede acceder a ella desde fuera del subprograma o bloque de código. Las variables locales a un subprograma se definen en la parte de la definición de variables del mismo. Si se tiene una variable local con el mismo identificador que una variable global, las referencias que se hacen dentro del bloque de código en que se declara la variable local harán referencia a dicha variable local y no a la variable global. 4.2 Variable Global Es aquella que está definida a nivel del programa, es decir, su ámbito es el programa o algoritmo principal y todos los subprogramas que dependen de este último. Una variable global se puede acceder desde cualquiera de los subprogramas y el programa principal, salvo que alguno de esos subprogramas tenga definida una variable local con el mismo nombre que la variable global. Hay que ser cuidadosos a la hora de usar variables globales ya que como todos los subprogramas las pueden modificar, esta es la razón por la cual no se deben utilizar variables globales para pasar información entre los subprogramas, se recomienda usar variables locales por medio de parámetros reales para tal fin. 4.3 Procedimientos Anidados La anidación de procedimientos no se permite en todos los lenguajes y consiste en que dentro de un procedimiento se pueda definir o declarar el código completo de otros procedimientos. Si la anidación de procedimientos está permitida, se plantean más problemas en cuanto al ámbito, desde este punto de vista, se dice que una variable local se conoce en el procedimiento en el que está definida y en todos los procedimientos anidados que componen el ámbito de dicho procedimiento, salvo que en alguno de esos procedimientos anidados este definida una variable local con el mismo nombre que la anterior, en cuyo caso, dentro de ese procedimiento, siempre se va a referir a la variable local porque siempre se considera el ámbito más restringido. Veamos el siguiente ejemplo de declaración de variables en diferentes ámbitos. 5. Comunicación entre Subprogramas: Paso de Parámetros La mejor forma para llevar a cabo la comunicación ente subprogramas, es el paso de parámetros. Cuando se invoca una función o procedimiento se le pasa a través de los parámetros los datos que necesita. En el caso de un procedimiento los resultados también se devuelven a través de sus parámetros. Para ello se define el tipo del parámetro a principio del subprograma, que es lo que se conoce como parámetros formales. Al hacer la llamada se pasan los datos a través de los parámetros reales. 5.1 ¿ Cómo se Efectúa la Correspondencia entre Parámetros Formales y Reales?: Existen dos métodos para realizar la correspondencia entre parámetros formales y reales: 5.1.1 Correspondencia Posicional: En este caso se hacen corresponder los parámetros formales y reales por la posición que ocupan (orden de declaración) de izquierda a derecha. Para esto, tiene que haber el mismo número de parámetros formales y reales y deben ser del mismo tipo. Si se tiene el procedimiento: Proc(x : entero, y real) Una llamada valida es: Proc(8, a) Donde 8 es una constante literal entera y a es una variable real previamente definida. En este caso al efectuar la llamada al parámetro formal x se le asigna el valor de 8 y al parámetro formal y se le asignara el valor que tenga almacenado el parámetro real definido por la variable a. 5.1.2 Correspondencia por Nombre Implícito: En este enfoque en la llamada al subprograma se coloca explícitamente a que parámetro formal corresponde cada parámetro real. En la llamada se coloca el nombre del parámetro formal, separado por dos puntos (:) y seguido por el nombre del parámetro real que se pasa, de esta forma no importa la posición en la que se colocan los argumentos del procedimiento o función. Ejemplo: Proc(x : 8, y : a) Proc(y : a, x : 8) 5.2 Tipos de parámetros: Existen tres tipos básicos de parámetros según se usen para entrada de datos o para obtener resultados. Son estos: De entrada: Son parámetros que sólo aportan datos de entrada al subprogama al que pertenecen como parámetros. Sólo pueden ser leídos, pero no modificados. Aunque se modificasen dentro de un subprograma, esa modificación no va a tener efecto fuera del subprograma. De salida: Se usan sólo y exclusivamente para devolver resultados. Su valor al hacer la llamada al subprograma no es de relevancia. Ese valor sólo va a tener sentido cuando termine la ejecución del subprograma. De entrada y salida: El valor del parámetro tiene importancia tanto a la entrada como a la salida del subprograma. Aporta dato cuando se llama al subprograma y por otra parte, devuelve a través de él los resultados. En este caso tiene sentido tanto poder leer como actualizar el parámetro. La mayoría de los lenguajes sólo permiten dos tipos de parámetros; de entrada, sólo para leer datos, y de entrada-salida para leer datos y devolver resultados. 5.3 Métodos de Paso de Parámetros: Existe una variedad de métodos, sólo se estudiarán dos de ellos por ser los más utilizados y conocidos en las herramientas de programación. El paso de parámetros se va a clasificar en: Paso de parámetros por copia o por valor. Paso de parámetros por referencia. 5.3.1 Paso de Parámetros por Copia o Valor: La característica fundamental de este método es que la función invocada no puede modificar el valor de los parámetros reales. Al realizarse la llamada a la función, se copia el valor del argumento en el parámetro formal de la función. El parámetro formal de la función tiene asociada una dirección de memoria diferente a la dirección de memoria del parámetro real, por lo tanto, este parámetro formal se comporta como una variable local en la función a la cual pertenece. Se puede cambiar el valor del parámetro dentro de la rutina y no repercutirá en el argumento originalmente transferido ya que comparten direcciones de memoria diferentes e independientes. Veamos el siguiente ejemplo: Procedimiento Duplicar(x: entero) Inicio x=x* 2 Escribir x Fin Duplicar Algoritmo CopiaValor Var a : entero Inicio a =3 Duplicar (a) Escribir a Fin El valor de a será 3 y el de x será 6. 5.3.2 Paso de Parámetros por Referencia: La característica fundamental de este método es que la función invocada puede modificar el valor de los parámetros reales. Al realizar la llamada a la función, no se copia el valor del argumento en el parámetro de la función. Se almacena la dirección de memoria de su parámetro real asociado, es decir, el parámetro formal apunta a la dirección de memoria del parámetro real que tiene asociado. Cualquier modificación que. se efectúe sobre el parámetro formal dentro de la función, tendrá un efecto directo en el parámetro real asociado, ya que se modificará el valor almacenado en la dirección de memoria que indica el parámetro formal que es a su vez la dirección de su parámetro real asociado. El parámetro no real puede ser ni constantes ni expresiones. Sólo pueden ser variables. Para indicar que el tipo de paso de parámetro es por referencia se va a utilizar la palabra clave ent-sal precediendo al parámetro que se pasa por referencia. Procedimiento Duplicar(ent-sal x : entero) Inicio x=x*2 ¡, Fin Duplicar Algoritmo Referencia Var a Inicio a=3 Duplicar (a) Escribir (a) Fin Al finalizar el algoritmo, el valor de a será igual a seis, valor asignado a x en el subprograma Duplicar (). Podemos resumir lo siguiente: Por valor: el parámetro actual no cambia de valor. Por referencia: el parámetro actual puede cambiar de valor. 6. Recursividad Se dice que un subprograma es recursivo cuando se llama a si mismo. La recursividad se puede utilizar en subprogramas que se pueden definir en términos recursivos, es decir, en término de sí mismo, como procesos de alguna manera repetitivos. Un ejemplo de definición recursiva es el de la función matemática factorial donde: Factorial(x) = x * Factorial(x-1) Hay que ser cuidadosos al utilizar la recursividad e incluso evitarla siempre que sea posible utilizando algoritmos iterativos, ya que cada vez que un subprograma se llama a si mismo hay que almacenar en la pila del sistema (lugar de memoria especial) la dirección de retorno de ese subprograma, con lo cual si se efectúan muchas llamadas recursivamente se irá llenando la pila del sistema pudiendo agotarse la memoria disponible en un momento dado. Esta situación se conoce como desborde de la pila del sistema. Todo programa recursivo tiene que tener alguna condición que ponga fin a la recursividad, un punto en el que el subprograma deje de llamarse a sí mismo cuando se cumpla la condición. De otra forma, se forma un bucle infinito con el consecuente error de desbordamiento de pila mencionado anteriormente. Ejemplo de la función factorial la condición de control es que el factorial de todo número menor o igual a 1 es 1: si x >1 Factorial(x) = x * Factorial(x-1) sino Factorial(x)=1 UNIDAD 5: ESTRUCTURA DE DATOS: ARREGLOS 1. Introducción En las unidades anteriores se estudiaron los conceptos de algoritmos y programas, así como una serie de elementos, entre ellos, la lógica, que ayudan a resolver problemas computacionales. También se discutió cómo un programa o algoritmo puede ser representado gráficamente mediante un diagrama de flujo y se trabajo con los principios de la programación estructurada, sus recursos y técnicas. Aquí de estudiaremos una de las representaciones de datos más usadas la programación llamada denomina arreglo. Los arreglos se utilizan para almacenar datos consecutivos de un mismo tipo, por lo que se usan generalmente en algoritmos de clasificación, ordenamiento y búsqueda. 2. Arreglos Unidimensionales: Vectores Un arreglo unidimensional o vector es un conjunto finito, consecutivo y organizado de elementos homogéneos, es decir, elementos pertenecientes a un mismo tipo de dato. Se dice que es: Finito: El arreglo tiene un número determinado de elementos. Homogéneo: Todos los elementos del arreglo son del mismo tipo. Organizado: Existe una forma de referenciar cada elemento del arreglo y de acceder a cada uno de sus elementos de manera independiente. Consecutivo: Por la forma en que se almacena o representa un vector en la memoria del computador en posiciones consecutivas de la memoria. El índice (valor que referencia la posición del arreglo) tiene que ser de cualquier tipo de datos escalar, porque en un escalar se puede definir un orden y entre dos elementos consecutivos no puede haber infinitos elementos, ejemplo de datos escalar son los enteros y caracteres. Para referenciar un elemento de un arreglo se usa el nombre del arreglo y entre corchetes [ ] el índice que determina la posición de ese elemento en el arreglo. El rango o longitud de un vector o arreglo lineal es la diferencia entre el índice de valor máximo y el índice de valor mínimo de ese arreglo + 1. Normalmente los índices comienzan enumerarse desde O o 1 como el valor mínimo del índice dependiendo del lenguaje (en Pascal inician con 1 y en C inician con O). Sin embargo, nada impide que comiencen con cualquier otro valor. Los arreglos se almacenan siempre en posiciones consecutivas de memoria. Un índice no tiene porque ser un valor constante, sino que puede ser también una variable o una expresión que al ser evaluada devuelva el índice. Para definir un arreglo se da el nombre del arreglo, el rango de sus índices y el tipo de los datos que contiene. Ejemplo: sueldo: arreglo [8] de real i: entero i=2 sueldo[i]= 23.5 Si el valor mínimo del rango del índice es 1 la sentencia sueldo[i]= 23.5, asigna el valor 23.5 a la segunda posición de un arreglo de ocho elementos. Sí el valor mínimo del rango del índice es O la sentencia asigna el valor 23.5 a la tercera posición de un arreglo dado que el valor del índice i es 2. Se considera un error intentar acceder a una posición del arreglo que este fuera del rango del índice. Este error se denomina comúnmente índice fuera de rango. 2.1 Operaciones con Vectores Se va a usar la declaración de vector: ventas: arreglo[12] de entero 2.1.1 Asignar un Dato a una Posición del Arreglo Consiste en asignar un valor dado a una posición del arreglo dada por un índice. 1 2 3 4 5 6 7 8 9 10 11 12 Ejemplo: ventas[5] =60000 2.1.2 Lectura y Escritura de Datos Consiste en usar una posición cualquiera del arreglo definida por un índice para operaciones de entrada y salida. Ejemplo: Desde i = 1 Hasta 12 Escribir "Introduce las ventas del mes” i Leer ventas[i] Fin Desde Desde i = 1 Hasta 12 Escribir "Ventas del mes " i “=” ventas [i] Fin Desde 2.1.3 Recorrido o Acceso Secuencial de un Arreglo Consiste en pasar por todas las posiciones del arreglo para procesar su información. Ejemplo: Desde i = 1 Hasta 12 ventas[i] = ventas[i] + 1000000 Fin Desde 2.1.4 Actualización de un Arreglo: Añadir datos: Es un caso especial de la operación de inserción de un elemento en un arreglo donde el elemento se agrega después de la última posición que contiene información válida en el arreglo. Para hacer esta operación es necesario que, si actualmente el arreglo tiene k posiciones de información válida, tenga un tamaño de al menos k + 1 para que se pueda añadir otro elemento a continuación del elemento en la posición k. Sintaxis: <nom_arreglo>[k + 1] = valor Insertar datos: Consiste en introducir un elemento en el interior de un arreglo, para lo cual será necesario desplazar todos los elementos situados a la derecha del que vamos a insertar una posición a la derecha con el fin de conservar el orden relativo entre los elementos. Para que se pueda insertar un nuevo elemento en el arreglo si ya existen n elementos con información en el arreglo, el arreglo tendrá que tener un tamaño al menos de n + 1 para poder insertar el nuevo elemento. C E F J M O Al insertar G en la cuarta posición queda: C E F G J M O Si k es la posición donde se va a insertar el nuevo elemento, n el número de elementos válidos en el arreglo en el momento de la inserción y suponiendo un tamaño mínimo de n + 1, el algoritmo de inserción es: Desde i= k Hasta n A[i+1]=A[i] Fin Desde Eliminar Datos: Para eliminar un elemento de un arreglo, si ese elemento está posicionado al final del arreglo, no hay ningún problema, simplemente si el tamaño del arreglo era n, ahora será n-1. Si el elemento a eliminar ocupa cualquier otra posición entonces se tendrá que desplazar todos los elementos situados a la derecha del elemento a borrar una posición hacia la izquierda para que el arreglo quede organizado. C E F J M O Al borrar el elemento J de la cuarta posición. C E F M O Suponiendo que el número de elementos validos actualmente es n y que se desea borrar el elemento de la posición k. Desde i = k Hasta n - 1 A[i]=A[i+1] Fin Desde 3. Arreglos Bidimensionales: Matrices m x n Un arreglo bidimensional de M x N elementos es un conjunto de M x N elementos, todos del mismo tipo, cada uno de los cuales es referenciado a través de 2 subíndices. El primer subíndice varía entre 1 y M si ha empezado a numerar el índice en 1. El segundo índice varía entre 1 y N, sí ha empezado a numerar el índice en 1. En general se puede definir un arreglo de 2 dimensiones de la siguiente manera: <nombre_arreglo>: arreglo[rangoI, rangoII] de <tipo> Ventas mensuales de cinco años: ventas: arreglo[5, 12] de real tamaño = m x n = 5 x 12 = 60 M es el número de filas y N es el número de columnas, es decir, la 1ª dimensión indica las filas y la 2ª indica las columnas. Al acceder a un elemento I, J se está accediendo al elemento que ocupa la fila I y la columna J. En memoria, todos los elementos del arreglo se almacenan en posiciones contiguas. Matriz de ventas 5 x 12, total de 60 elementos. 1 2 1 2 3 4 5 3 4 5 6 7 8 9 10 11 12 120 ventas[4, 3] = 120 3.1 Manejo de Matrices: Operaciones comunes con las matrices bidimensionales: 3.1.1 Colocar el valor de cero a todos 105 elementos de la matriz. Esta es una operación útil cuando se desea inicializar todos los elementos de la matriz a un valor dado. Sintaxis: M: arreg1o[m, n] de entero Var i, j : entero Desde i=1 Hasta m Desde j=1 Hasta n M[i, j] = 0 Fin Desde Fin Desde 3.1.2 Colocar el valor de cero a sólo los elementos de una fila dada En este caso se mantiene fija la fila y se recorren las columnas asignándoles un valor suministrado, usualmente ese valor es cero. Sintaxis: M: arreg1o[m, n] de entero Var i, j : entero i = fila Desde j=1 Hasta n M[i, j] = 0 Fin desde ventas: arreg1o[5, 12] de entero Var i, j : entero i=3 Desde j = 1 Hasta 12 M[i, j] = 0 Fin desde En este caso se le asignó el valor de cero a los elementos de la tercera fila de la matriz ventas. 4. Arreglos Multidimensionales: Matrices m x n x ... z Un arreglo multidimensional es una matriz de 3 ó más dimensiones. Si se tiene un arreglo de N dimensiones, donde cada dimensión es de tamaño d1, d2, .. ,dN, el número de elementos del arreglo será d1 *d2 * .. *dN. Para acceder a un elemento del arreglo se utilizan N índices, cada uno de los cuales referencia a una posición dentro de una dimensión, siempre según el orden de declaración. En memoria, el arreglo se sigue almacenando en posiciones consecutivas. La declaración de un arreglo multidimensional será: nombre_arreglo: arreglo[rangoI, rangoII, ... , rangoN] de tipo Ejemplo: Matriz de ventas mensuales por cinco años para tres vendedores: ventas : arreglo[3, 5, 12] de real ventas [2, 4, 10]=1200.5 5. Almacenamiento de Arreglos en Memoria Un arreglo en memoria siempre se almacena en posiciones contiguas a partir de la dirección base de comienzo del arreglo, la cual se asigna cuando se declara una variable del tipo arreglo. El tamaño que ocupa el arreglo en memoria es el producto del número de sus elementos por el tamaño de cada uno de ellos. Arreglo[100] de carácter Si se asume que cada carácter necesita un byte para ser almacenado entonces el arreglo necesita un total de 100 bytes de memoria. 1 byte * 100 elementos = 100 bytes En el caso de un arreglo multidimensional, también se almacena en posiciones contiguas de memoria. Su tamaño será el producto de sus elementos por el tamaño requerido para representar cada elemento en memoria. Arreglo[3, 5, 12] de enteros Si se asume que cada entero necesita dos byte para ser almacenado y se tiene un total de 3 x 5 x 12 = 180 elementos, entonces el arreglo requiere un total de 360 bytes de memoria. 2 byte * (3 * 5 * 12) elementos = 360 bytes UNIDAD 6: REPRESENTACION DE DATOS 1. Introducción Las computadoras al igual que los seres humanos necesitan de un lenguaje para comunicarse con su entorno. En los sistemas computacionales se han establecido formas para representar internamente los datos y la información que será procesada por un programa o aplicación. Entre ellos están los sistemas de representación numérica y los sistemas de representación de caracteres como el ASCII o el UNICODE. 2. Representación de Datos Caracteres ASCII EBCDIC Numéricos Binario Decimal Hexadecimal Las computadoras leen unos y ceros (1,0) y las personas leen caracteres como m, T, 4 ó !. Para codificar los datos legibles por las personas a datos que entienda la computadora se debe tener alguna forma de traducción. El dato carácter normalmente se representa con código ASCII en las computadoras estaciones de trabajo y en EBCDIC en las computadoras grandes (mainframe). El dato numérico decimal se almacena típicamente en formato binario o hexadecimal en todas las computadoras. Todas estas formas de representación se discuten en detalle a continuación. 3. Notación Binaria Las características de la notación binaria se pueden resumir en: La notación binaria es la forma más simple de representar los datos. Las computadoras pueden usar directamente esta forma. El modo binario significa que sólo hay dos estados en que puede estar el dato: APAGADO (0) o ENCENDIDO (1). Cada componente binario (0 ó 1) se llama bit. El sistema de numeración binaria se usa en la mayoría de las computadoras como un medio para representar los valores de los datos. Cada bit, digito binario, en una localidad de almacenamiento particular se establece en 0 o en 1. En la mayoría de las computadoras se agrupan 8 bits para formar lo que se conoce como un byte. Note que mientras la notación binaria es la forma más fácil a utilizar por la computadora, es el más difícil para las personas. 4. Representación de Valores de Caracteres Cualquier carácter se puede representar usando configuraciones únicas de bit. Las representaciones actualmente más usadas son: EBCDIC y ASCII. En EBCDIC, los ocho bits se usan para representar el carácter. Esto permite representar 256 caracteres diferentes. Unos representan letras, otros números, otros signos de puntuación, y otros caracteres especiales llamados "caracteres de control". ejemplos de letras: 1100 representan la d. 0100 representan la D, y 1000 0100 Los valores del carácter para los números 0 1 2 3 4 5 6 7 8 9 =1111 = 1111 = 1111 = 1111 = 1111 = 1111 = 1111 = 1111 = 1111 = 1111 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 Representación Binaria La sigla EBCDIC viene de Extended Binary Coded Decimal Interchange Code (Código de Intercambio Decimal Codificado en Binario Extendido). Fue desarrollado inicialmente por IBM y lo usan los sistemas de computadoras grandes (mainframes) y algunas computadoras más pequeñas. Se han separado los ocho bits de un byte en dos grupos de cuatro bits, esto lo hace fácil de leer. Actualmente se denominan los primeros cuatro bits la porción zona y los últimos cuatro bits la porción digitos. Ejemplos de caracteres de control es: NULL significa nulo (todos los bits son cero) LF que quiere decir retorno de línea (0010 0101) 5. Caracteres ASCII El código ASCII también usa un código de 8 bits. En ASCII, por ejemplo el carácter A se representa por 0110 0101 Y el carácter B se representa por 0110 011O. Si dos computadoras van a comunicarse entre sí y la computadora que transmite el mensaje almacena los datos en EBCDIC y la receptora almacena los datos en ASCII, los códigos de EBCDIC deben convertirse a los códigos ASCII correspondientes. La mayoría de las computadoras de escritorio, como las PCs usan el código ASCII. Las siglas ASCII viene de American Standard Code for Information Interchange (Código Estándar Americano para el Intercambio de Información). El código ASCII fue desarrollado con la intención de simplificar y estandarizar la comunicación máquina-a-máquina y sistema-asistema. 6. Representación de Valores Numéricos La representación de los datos numéricos en una computadora se lleva a cabo asignando un valor específico a cada bit. Se pueden usar grupos de bits para representar valores decimales. A cada bit se le asigna el valor decimal: 1, 2, 4, Y 8 respectivamente. Determinando sí el bit está ENCENDIDO o APAGADO se agrega el valor decimal al total. El siguiente ejemplo representa el número 13 decimal. 1 1 23 (=8) + 1x8+ 0 1 Numero Binario 22 (= 4) + 21 (=2) + 2° (=1) valor del bit 1x4+ 1x1 valor decimal 0x2+ El valor se calcula agregando el valor de cada componente que tiene el valor de uno "1." En el ejemplo anterior, 8 + 4 + 1 = 13. El valor más grande que puede representarse en un patrón de bits que consta de cuatro dígitos binarios 1111 es equivalente al número decimal 15. También es común usar el bit de orden mayor, él más a la izquierda, para indicar si el valor es positivo o negativo. Cuando se usa se le llama el bit de signo. El rango de números que se pueden representar en una combinación binaria de 8 bits con signo es de -127 a +127. Si en cambio se usan los 8 bits completos para representar datos sin signo, entonces el rango va de 0 a 255. 7. Convertir de Decimal a Binario Para convertir un número entero decimal de base 10 a base 2 binario, se divide el número por el valor binario más grande que lo divida. Repita la operación de la división con el resto hasta que el cociente sea 0. Cuando un número puede ser dividido por un valor binario haga esa posición del bit a 1 (encendido), en otro caso cero. Como ejemplo se va a convertir el número decimal 149 a su equivalente binario: Número Decimal 149 2048 1024 512 0 0 0 256 0 128 1 64 0 32 0 Número Binario 16 1 8 4 0 2 1 1 0 1 Valor Bit El sistema convierte el formato decimal que se esté usando a binario. 8. Convertir de Binario a Decimal Para convertir un número binario a uno decimal se usa lo que se denomina notación extendida. Como ejemplo se va a convertir el número binario 100110 a decimal: 100110 = (1X2)5 + (0X2)4 + (0X2)3 + (1X2)2 + (1X2)1+ (0x2)0 = 32 + 0 + 0+ 4 + 2 + 0 = 38 9. El Sistema Numérico Hexadecimal La notación que normalmente se usa es la del sistema numérico hexadecimal llamada también "hex". En hexadecimal se agrupan cuatro dígitos binarios para representar un dígito hexadecimal. Los símbolos válidos del hexadecimal son: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E, Y F. La siguiente tabla muestra valores equivalentes para binario, hexadecimal y decimal. BINARIO 0000 0001 0010 HEXADECIMAL 0 1 2 DECIMAL 0 1 2 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 3 4 5 6 7 8 9 A B C D E F 3 4 5 6 7 8 9 10 11 12 13 14 15 Tabla de Valores de los Diferentes Sistemas El sistema hexadecimal se le llama también sistema numérico base 16. 10. Convertir de Decimal a Hexadecimal Para convertir de decimal a hexadecimal, se mostrará un método diferente al que se usó para la conversión binaria. Divida el número decimal entre 16, y convierta el resto a un número hexadecimal para obtener el digito más a la izquierda del hexadecimal. Entonces divida el cociente entre 16 y use el resto para el segundo dígito. Repita hasta que el resto sea cero. Para dar un ejemplo se va a convertir el decimal 1710 a su equivalente número hexadecimal 6AF 6 0 resto 16 6 resto 16 106 resto 16 1710 resto A F 6 10 14 Conversión de Decimal a Hexadecimal 11. Convertir de Hexadecimal a Decimal Para convertir de hexadecimal a decimal, se usa el mismo método para convertir en número en representación binaria a decimal, sólo que se multiplica por 16 en lugar de 2 las bases. Ejemplo: convertir el hex 9C4D a su equivalente número decimal 40,013: 9C4D=(9x163)+(Cx16 2 )+(4x161)+(Dx160)=(9x4096)+(Cx256)+(4x16)+(Dx1) = (9x4096)+(12x 256)+(4 x16)+(13x1) =36,864+3,072+64+13 = 40,013 12. Decimal Empaquetado Para los campos numéricos que usan EBCDIC todas las posiciones de la zona del campo, se usan salvo un byte que contiene el signo para el número. Para conservar el almacenamiento, pueden usarse los datos decimales condensados (empaquetados). La representación de datos en forma decimal empaquetado contiene dos dígitos decimales por byte, salvo el medio-byte más a la derecha que contiene un dígito y un signo de 4 bits. Digitos D Signo Decimal Empaquetado D Representación D D D D D La representación de datos decimales empaquetados es una forma económica los datos numéricos la BYTE de representarBYTE BYTE internamente en BYTE computadora. El hecho de que el dato de carácter EBCDIC tienen un campo de "zona" de F para todos los números implica que hay realmente un desperdicio de espacio. De manera, que es posible empaquetar los campos de datos numéricos eliminando el medio byte de campo del campo zona y utilizar esos cuatro bits para representar otro dígito del número. Debido a la necesidad de los números positivos o negativos, se usa una de las ubicaciones del campo de zona como un indicador del signo para el número completo. Éste se coloca en el último medio byte como se mostró anteriormente. Para los números decimales empaquetados los códigos binarios 0000-1001 se conocen como los dígitos decimales y los códigos restantes, 1010-1111. se usan como señales. Los códigos tienen el significado siguiente: Código Hex Valor Binario Signo A 1010 B 1011 C 1100 D 1101 E 1110 F 1111 + - + - + + * * S * Códigos predefinidos Un campo decimal empaquetado que contiene un valor negativo 38,264 ocupará tres bytes de almacenamiento y aparecerá en la memoria como: 38 26 4D Número Decimal Empaquetado en la Memoria Para determinar el número de bytes requerido para un número decimal empaquetado, agregue uno, para el medio-byte de signo, al número de digitos con el que está representado y divídalo entre dos. 13. Límites del Almacenamiento Los bits se combinan, en grupos de 8 para formar los bytes. La computadora referencia los datos en lo que se denomina palabras. La disposición de bytes en palabras permite que el procesador sea eficiente cuando carga las instrucciones y los datos. 0000 0001 0002 0003 0004 0005 0006 0007 BYTE BYTE BYTE BYTE BYTE BYTE BYTE BYTE HALF HALF HALF HALF FULL FULL DOUBLE WORD Limites del Almacenamiento La computadora necesita tener sus datos en un formato que sea fácilmente accesible. Esto significa que deben ser colocados en límites de sean predecibles y útiles. Los elementos de un programa y los datos que usa se alinearán típicamente en uno de los tres límites de palabras como se mostró anteriormente. Las direcciones dentro de la computadora son descritas en uno de estos cuatro "límites": byte, media palabra, palabra o palabra doble. Un límite de media palabra es divisible entre dos, una palabra completa es divisible entre cuatro y una palabra doble es divisible entre ocho. 14. Del Bit a la Base de Datos A continuación se presenta la "jerarquía" de datos, del elemento más pequeño representado por el bit hasta al más grande constituido por la base de datos, con los que generalmente se trabaja en un programa de computadora. Los programas generalmente trabajan con los datos ubicados en nivel más alto de la jerarquía, representado por campos, registros o archivos. 0 Bit Byte 0101100 1 5962 Campo 5962 Southern Lee, Robert E. 1069A ... Registro 5962 Lee. Robert E. 10691069A 2447 Lincoln 1 n7? Dixon. Mason 1070 . . Archivo . Jerarquía de los Datos UNIDAD 7: ENTRADA Y SALIDA 1. Introducción La solución a problemas de la vida real mediante computadoras incluye el uso de programas especializados para resolver dichos problemas. Los programas generalmente usarán, leyendo y escribiendo, datos provenientes de fuentes externas. Para que esto sea posible las computadoras ofrecen capacidades de entrada y salida que le permiten a las aplicaciones comunicarse con ese entorno que se encuentra fuera del programa mismo. Aquí se introducen los conceptos básicos de entrada y salida mediante los cuales los programas de computadora pueden intercambiar, capturar y mostrar datos para la soluciones de problemas específicas. 2. Entrada y Salida de un Programa Un programa se carga en la computadora en el Procesador o la Unidad Central de Procesamiento (CPU). Cuando el programa se ejecuta, necesitará probablemente leer datos o escribir datos a algún dispositivo. El lenguaje que se use para escribir un programa tendrá algunos comandos especiales o funciones que se pueden usar para realizar la entrada y salida. La entrada y salida generalmente son las partes más complejas de cualquier programa o cualquier lenguaje de programación. La transferencia real de datos hacia o desde los dispositivos de E/S será generalmente la parte más lenta de un programa. Los comandos que se usan para la entrada son normalmente: read, get o sean. Los comandos de la salida son por su parte: print, write o put. 3. Buffer de Datos Los datos externos que se procesan en un programa se leen y escriben realmente en un buffer que maneja la computadora. El sistema lee físicamente los datos de algún dispositivo externo a un buffer de entrada y los escribe en un buffer de salida. El sistema es propietario de los buffers y los administra. El programa accede a los datos usando estos buffers del sistema. Lee del buffer de entrada y escribe al buffer de salida. Cuando se empieza el procesamiento con una operación de entrada, el sistema lee los datos del dispositivo de entrada y llena el buffer de entrada. A medida que se vacían los datos del buffer de entrada, el sistema sigue la pista del buffer y llena el buffer desde el dispositivo cuando está vacío. El buffer de salida también es monitoreado por el sistema dado que gradualmente lo llena. Cuando está lleno, el sistema escribe el contenido del buffer de salida al dispositivo de salida designado. Todo este movimiento de datos externo lo maneja el sistema denominado Sistema de Control de I/O (IOCS). El IOCS corre "asincrónicamente" a la ejecución del programa. Esto significa que se puede continuar haciendo lo que se quiere a los datos y el sistema se ocupa de transportarlos hacia y desde los dispositivos de E/S. LEER (read) Entrada Salida ESCRIBIR (write) Buffers de Datos ... HACER MIENTRAS (MAS DATOS) LEER /*PROCESAR*/ ESCRIBIR FIN HACER ... 4. Imprimir Datos Imprimir la salida a una impresora requiere ciertas consideraciones especiales: Separar los formatos de salida para las líneas de datos y las líneas del título Contadores de línea Contadores de páginas Encabezados de páginas • Caracteres de control de carro en las líneas de salida Estos elementos enumerados anteriormente deben ser manejados en el programa. Se requiere de algunas consideraciones de formato especiales cuando se escriben datos a un dispositivo de impresión. Un contador de línea se mantiene para tener seguimiento de cuántas líneas se han impreso para que así se pueda tener control de cuándo saltar a una nueva página y colocar los encabezados en una nueva página de salida. El contador de páginas permite colocar el número de la página en la nueva página. Formatos de líneas separados se requieren para imprimir las líneas de datos y líneas de encabezado. Normalmente el encabezado de la página requiere de formatos únicos de línea para las múltiples líneas de encabezado y los encabezados de columna. El control de carro de impresora le indica a la impresora dónde imprimir la próxima línea. 5. Control de Carro de Impresora La mayoría de los lenguajes de programación que proporcionan acceso directo a una impresora, también proporcionan un medio para controlar dónde se va a imprimir una línea. Esto generalmente se hace con un carácter de control en la primera posición de la impresión de cada línea. En la Figura 7.3 se presenta los caracteres de control. Caracteres Acción de Control espacio Espaciar 1 línea O Espaciar 2 línea - Espaciar 3 línea 1 Saltar a página + Suprimir espaciado una nueva Caracteres de Control Los caracteres de control se colocan en la primera posición de la impresión de cada línea y no se verán en la copia impresa. Este carácter de control siempre se aplica a la línea que se va a imprimir. Cuando se usa el carácter de control "0" se da la apariencia de doble espacio. El "+" puede usarse para suprimir el espaciado de línea, para dar apariencia de sobreImpresión (overstrike) o de negrita. 6. Imprimir Salida: Reportes Cuando se escriben los reportes a una impresora, el programador tiene que considerar cosas tales como los encabezados de páginas, números de las páginas, contadores de página y pie de páginas. Existen varios tipos de líneas que deben definirse: Línea de título: Contiene el nombre del reporte superior de cada página Líneas de encabezados: Los encabezados de las alineados con el de los datos Líneas de Datos: Los detalles del reporte Las líneas resumen: totales finales o información Líneas de pie de página: Contiene los números información de seguridad, etc. y aparece en .parte columnas deben ser complementaria de la página, fecha, El programador define la información para las partes constantes de las líneas de título, encabezado y de pie de página. Estos registros constantes se imprimirán mediante una rutina que se llama cuando se alcanza el fin de una página. El fin de una página se determina contando las líneas y probando este valor contra un número máximo deseado de líneas por página. Cuando se alcanza el límite de la página, el programa debe imprimir una línea de pie de página opcional en la página actual y luego imprimir una línea de título en una nueva página. Si se usan encabezados de columnas, éstos deben imprimirse antes de continuar la impresión y contar las líneas de detalle. La rutina que maneja el procesamiento de la línea de título también debe ocuparse de la a del titulo para la primera página. 7. Encabezados de Páginas El programador define el tamaño de la página y una variable contador de línea. El contador de línea se inicializa con el tamaño de la página para que la rutina de encabezado de página sea llamada para la primera página. Las consideraciones para el contador de línea son: El contador de línea se debe comparar (>=) con el tamaño de página después de imprimir cada línea de detalle para determinar cuándo se debe llamar a la rutina de encabezado de página. Se debe incrementar inmediatamente después de imprimir una línea, basado en el espaciado simple, doble o triple. Siempre debe reflejar el número de la línea de la última línea escrita. La rutina de encabezado de página debe reinicializar el contador de línea. El tamaño de la página es el número máximo de líneas a ser impresas en la página. El programador decide el número que será y lo fija como una constante en el programa. La rutina de encabezado de página también debe ocuparse de la variable contador de página. Debe incrementase cada vez que una nueva página se escribe. Esta variable puede ser parte de la línea del titulo o de pie de página. 8. Entrada/Salida de Archivo: Formatos de Registros Los datos escritos o leídos desde un archivo generalmente se manejan como un registro. Existen típicamente dos formas en que pueden procesarse los datos de un registro, como registros fijos ó como registros variables. Los registros también pueden bloquearse para lograr eficiencia. Otros tipos de E/S usan un archivo de disco o cinta. Este medio normalmente trabaja con registros de datos, que requiere que el programador considere los formatos del registro. El tamaño de los registros fijos se establece generalmente como un parámetro en el proceso de E/S. El tamaño de los registros variables varía para cada registro y se coloca en la cabecera del registro para indicar el número de bytes que éste ocupa. Esto también se cumple para bloques de datos. El número de registros en cada bloque :e un conjunto de datos de bloque fijo se da como un parámetro del sistema de E/S. Sin embargo, el tamaño para bloque variable puede ser diferente para cada bloque, así que el tamaño también es embebido en una porción de la cabecera de cada bloque. Organizar datos en los bloques permite al sistema de control de E/S leer o escribir múltiples registros, el valor de un bloque, para cada transacción en el flujo de los datos. NOTA: EN LA GUÍA EXISTE UN PROBLEMA PROPUESTO Y UN ALGORITMO PARA LA SOLUCIÓN DEL MISMO. UNIDAD 8: EJEMPLOS DE PROGRAMAS Verificar la Secuencias Una secuencia puede ser: Una serie continua o conectada: el alfabeto Un orden consecutivo o por rango: los naipes Un conjunto de elementos ordenados: los números naturales Una verificación de secuencia es el proceso de garantizar el orden correcto de los registros al procesar un archivo secuencial, esto implica que esos datos se han ordenado previamente y requiere una jerarquía de datos y un valor clave para determinar el orden correcto Verificar la secuencia implica trabajar con un archivo de registros de datos que se ha ordenado previamente, generalmente en orden ascendente. Ejemplos de valores claves para ordenar pueden ser el número del empleado para registros de empleado o el número de parte para los registros del inventario. El proceso de ordenar las cosas en orden ascendente es un problema de programación clásico. Esto se puede realizar a través de alguna función del sistema o proceso periférico fuera del programa que se está produciendo. 1. Rupturas de Control La ruptura de control (Control Break) es el reconocimiento de un cambio en el valor clave cuando se procesa secuencias de registros que contienen múltiples registros para una clave. Normalmente se usa para procesar registros en secuencia en un sistema que contiene múltiples actualizaciones a registros maestros. La ruptura de control normalmente implica recolectar subtotales o imprimir los resúmenes intermedios. Un ejemplo de procesamiento con ruptura de control es el procesamiento de promedio de notas de los estudiantes de un salón de clase. La clave para hacer la ruptura de control puede ser ellO del estudiante o el nombre del estudiante. A medida que el programa lee el conjunto ordenado de los registros de notas del estudiante, promedia las notas de todos los cursos del estudiante en particular y rompe el control cuando encuentra un nuevo ID de estudiante o nombre. Al interrumpir el control, este programa calcula el promedio de notas del estudiante y luego reinicializa todos los acumuladores para preparar el procesamiento del próximo estudiante. 2. Emparejar Transacciones Emparejar Transacciones es emparejar el valor clave de un registro de un archivo contra el valor clave de los registros en un archivo maestro El Archivo Maestro es una colección de registros que contienen los datos permanentes o acumulados para un sistema. Archivo Maestro Transacciones 00120 01655 24898 59437 76990 98144 01655 59437 76990 Transacciones Emparejar transacciones es una actividad común en el procesamiento de archivos. Típicamente hay muchos registros de transacción para ser procesados contra sólo un registro en el archivo maestro con el valor clave. Algunos ejemplos dónde se aplica son: Las notas del estudiante de un semestre, las transacciones, emparejado contra los registros de notas permanentes para la cohorte, el archivo maestro La comprobación diaria y la actividad de depósito, las transacciones, emparejado contra el registro de cuenta para la cuenta corriente, el archivo maestro Diariamente el punto de venta y la actividad de reabastecer, las transacciones, emparejado contra la información detallada de inventario actual para un producto, el archivo maestro Ejercicio de Punto de Chequeo Diseñe un programa para generar un informe del resumen de ventas para un grupo de departamentos. El formato del informe debe reflejar el número del departamento y las ventas totales. Cada departamento puede tener múltiples registros de entrada. Se requiere verificar la secuencia del número del departamento. Si un registro de entrada está fuera de la secuencia, imprima un mensaje de error, los resultados acumulados y termine el programa. Su informe debe contener las cabeceras de las columnas y debe ocuparse de páginas múltiples. Un título para e[ informe es optativo. Su tarea será examinar los registros de entrada y el formato del informe deseado y hacer [o siguiente: Liste la entrada, salida y localidades de almacenamiento de proceso requeridas Liste los requisitos de pre-proceso, proceso y post-proceso Dibuje un diagrama de flujo que muestre una solución correcta Verifique su solución usando los dos juegos de entrada que se muestran a continuación: Entrada 2: Entrada 1: 5 200.00 5 100.00 5 100.00 6 50.00 6 200.00 16 300.00 Salida 1: 16 100.00 Dpto. No. Ventas 5 200.00 5 100.00 5 100.00 16 300.00 16 200.00 9 50.00 Salida 6 2: 200.00 Dpto. No. Ventas 5 400.00 5 400.00 6 250.00 16 500.00 16 400.00 Punto de Chequeo Error de Secuencia