S.E.P
S.E.S
D.G.E.S.T
NOMBRE DE LA MATERIA: FUNDAMENTOS DE PROGRAMACION DOCENTE: LIC. ISIDRO LOPEZ RUIZ ESPECIELIDAD: ING. EN DESARROLLO DE SOFTWARE
PRESENTA: MARIA ELENA CASTILLO ANTONIO SEMESTRE GRUPO 1º
“A”
San Pedro Comitancillo Oaxaca, a Noviembre del 2009.
ÍNDICE
4.1 DISEÑO DE METODOS (FUNCIONES).........................................................................................3 4.1.1 TECNICAS DE FORMULACION DE ALGORITMOS............................................................6 4.1.2 TIPOS DE ALGORITMOS.........................................................................................................9 4.1.2.1 ALGORITMOS DETERMINISTICOS............................................................................9 4.1.2.2 ALGORITMOS APROXIMADOS....................................................................................11 4.1.2.3 ALGORITMOS HEURÍSTICOS.......................................................................................11 4.1.2.4 ALGORITMOS VORACES...............................................................................................11 4.1.3 ALGORITMOS PROBABILISTICOS......................................................................................13 4.1.4 IDENTIFICACION DEL PROBLEMA....................................................................................13 4.1.5 PLANTEAMIENTO DEL PROBLEMA..................................................................................14 4.1.6 ANALISIS DEL PROBLEMA.................................................................................................15 4.1.7 DISEÑO DE LA SOLUCION...................................................................................................15 4.1.8 PRUEBAS Y DEPURACION...................................................................................................15 4.1.9 DOCUMENTACIÓN................................................................................................................16 4.2 OPERADORES................................................................................................................................16 4.2.1 ARITMETICOS.........................................................................................................................20 4.2.2 LOGICOS..................................................................................................................................21 4.2.3 JERARQUIA DE OPERADORES............................................................................................25 4.3 EXPRECIONES................................................................................................................................26 4.4 ESTRUCTURAS DE CONTROL....................................................................................................26 4.4.1 SELECTIVAS............................................................................................................................33 4.4.2 ITERATIVAS............................................................................................................................34 4.4.2 ITERATIVAS
CONSTRUCCION DEL
COMPORTAMIENTO DE UN OBJETO
4.1 DISEÑO DE METODOS (FUNCIONES) Los métodos son funciones que pueden ser llamadas dentro de la clase o por otras clases. La implementación de un método consta de dos partes, una declaración y un cuerpo. La declaración en Java de un método se puede expresar esquemáticamente como: tipoRetorno nombreMetodo( [lista_de_argumentos] ) { cuerpoMetodo }
En C++, el método puede declararse dentro de la definición de la clase, aunque también puede colocarse la definición completa del método fuera de la clase, convirtiéndose en una función inline. Los métodos pueden tener numerosos atributos a la hora de declararlos, incluyendo el control de acceso, si es estático o no estático La lista de argumentos es opcional, tanto en Java como en C++, y en los dos casos puede limitarse a su mínima expresión consistente en dos paréntesis, sin parámetro alguno en su interior. Opcionalmente, C++ permite utilizar la palabra void para indicar que la lista de argumentos está vacía Los parámetros, o argumentos, se utilizan para pasar información al cuerpo del método. La sintaxis de la declaración completa de un método es la que se muestra a continuación con los items opcionales en itálica y los items requeridos en negrilla: especificadorAcceso static abstract final native synchronized tipoRetorno nombreMetodo( lista_de_argumentos ) throws listaEscepciones
especificadorAcceso, determina si otros objetos pueden acceder al método y cómo pueden hacerlo. static,
indica que los métodos pueden ser accedidos sin necesidad de instanciar un objeto del tipo que determina la clase. Los métodos y funciones en C++ pueden devolver una variable u objeto, bien sea por valor (se devuelve una copia), por puntero o por referencia. Java no soporta punteros, así que no puede devolver nada por puntero. Para devolver un valor se utiliza la palabra clave return. La palabra clave return va seguida de una expresión que será evaluada para saber el valor de retorno. Esta expresión puede ser compleja o puede ser simplemente el nombre de un objeto, una variable de tipo primitivo o una constante. En C++, si un programa devuelve un puntero a un objeto situado en memoria dinámica y el valor de ese puntero no se asigna a una variable, la posibilidad de devolver la memoria al sistema se pierde y se producirá un memory leak, asumiendo que la dirección no está ya disponible para almacenar ninguna otra variable.
en C++ el tipo del valor de retorno debe coincidir con el tipo de retorno que se ha indicado en la declaración del método; aunque en Java, el tipo actual de retorno puede ser una subclase del tipo que se ha indicado en la declaración del método, lo cual no se permite en C++. En general, se permite almacenar una referencia a un objeto en una variable de referencia que sea una superclase de ese objeto. También se puede utilizar un interfaz como tipo de retorno, en cuyo caso, el objeto retornado debe implementar dicho interfaz. Nombre del Método El nombre del método puede ser cualquier identificador legal en Java. Java soporta el concepto de sobrecarga de métodos, es decir, permite que dos métodos compartan el mismo nombre pero con diferente lista de argumentos, de forma que el compilador pueda diferenciar claramente cuando se invoca a uno o a otro, en función de los parámetros que se utilicen en la llamada al método. En C++, dos versiones sobrecargadas de una misma función pueden devolver tipos diferentes. En Java, los métodos sobrecargados siempre deben devolver el mismo tipo. Métodos de Instancia Cuando se incluye un método en una definición de una clase Java sin utilizar la palabra clave static, estamos generando un método de instancia. Aunque cada objeto de la clase no contiene su propia copia de un método de instancia (no existen múltiples copias del método en memoria), el resultado final es como si fuese así, como si cada objeto dispusiese de su propia copia del método. Cuando se invoca un método de instancia a través de un objeto determinado, si este método referencia a variables de instancia de la clase, en realidad se están referenciando variables de instancia específicas del objeto específico que se está invocando. La llamada a los métodos de instancia en Java se realiza utilizando el nombre del objeto, el operador punto y el nombre del método. miObjeto.miMetodoDeInstancia();
En C++, se puede acceder de este mismo modo o utilizando una variable puntero que apunte al objeto miPunteroAlObjeto->miMetodoDeInstancia();
Los métodos de instancia tienen acceso tanto a las variables de instancia como a las variables de clase, tanto en Java como en C++. Métodos Estáticos Cuando una función es incluida en una definición de clase C++, o un método e incluso en una definición de una clase Java, y se utiliza la palabra static, se obtiene un método estático o método de clase. Lo más significativo de los métodos de clase es que pueden ser invocados sin necesidad de que haya que instanciar ningún objeto de la clase. En Java se puede invocar un método de clase utilizando el nombre de la clase, el operador punto y el nombre del método. MiClase.miMetodoDeClase();
En C++, hay que utilizar el operador de resolución de ámbito para poder invocar a un método de clase: MiClase::miMetodoDeClase();
Todas las clases que se derivan, cuando se declaran estáticas, comparten la misma página de variables; es decir, todos los objetos que se generen comparten la misma zona de memoria. Los métodos estáticos se usan para acceder solamente a variables estáticas.
class UnaClase { int var; UnaClase() { var = 5; } unMetodo() { var += 5; } }
En el código anterior, si se llama al método unMetodo() a través de un puntero a función, no se podría acceder a var, porque al utilizar un puntero a función no se pasa implícitamente el puntero al propio objeto (this). Sin embargo, sí se podría acceder a var si fuese estática, porque siempre estaría en la misma posición de memoria para todos los objetos que se creasen de la clase UnaClase. Paso de parámetros En C++, se puede declarar un método en una clase y definirlo luego dentro de la clase (bajo ciertas condiciones) o definirlo fuera de la clase. A la hora de declararlo, es necesario indicar el tipo de argumentos que necesita, pero no se requiere indicar sus nombres (aunque pueda hacerse). A la hora de definir el método sí tiene que indicarse el nombre de los argumentos que necesita el método. En Java, todos los métodos deben estar declarados y definidos dentro de la clase, y hay que indicar el tipo y nombre de los argumentos o parámetros que acepta. Los argumentos son como variables locales declaradas en el cuerpo del método que están inicializadas al valor que se pasa como parámetro en la invocación del método. En C++, se puede pasar como parámetro un puntero que apunte a una función dentro de otra función, y utilizar este puntero en la segunda función para llamar a la primera. Esta capacidad no está directamente soportada en Java. Sin embargo, en algunos casos, se puede conseguir casi lo mismo encapsulando la primero función como un método de instancia de un objeto y luego pasar el objeto a otro método, donde el primer método se puede ejecutar a través del objeto. Tanto en Java como en C++, los métodos tienen acceso directo a las variables miembro de la clase. El nombre de un argumento puede tener el mismo nombre que una variable miembro de la clase. En este caso, la variable local que resulta del argumento del método, oculta a la variable miembro de la clase. Cuando se instancia un método se pasa siempre una referencia al propio objeto que ha llamado al método, es la referencia this.
4.1.1 TECNICAS DE FORMULACION DE ALGORITMOS Las técnicas para la formulación de algoritmos son tres: DIAGRAMAS DE FLUJO: Un diagrama de flujo es la representación gráfica de un algoritmo. También se puede decir que es la representación detallada en forma gráfica de cómo deben realizarse los pasos en la computadora para producir resultados. Esta representación gráfica se da cuando varios símbolos (que indican diferentes procesos en la computadora), se relacionan entre sí mediante líneas que indican el orden en que se deben ejecutar los procesos. Los símbolos utilizados han sido normalizados por el instituto norteamericano de normalización (ANSI):
Símbolo
Descripción Indica el inicio y el final de nuestro diagrama de flujo. Indica la entrada y salida de datos. Símbolo de proceso y nos indica la asignación de un valor en la memoria y/o la ejecución de una operación aritmética. Indica la salida de información por impresora. Conector dentro de página. Representa la continuidad del diagrama dentro de la misma página. Conector fuera de página. Representa la continuidad del diagrama en otra página. Indica la salida de información en la pantalla o monitor.
Símbolo de decisión. Indica la realización de una comparación de valores.
Símbolo de Selección Múltiple. Dada una expresión permite escoger una opción de muchas.
Símbolo del Mientras. Dada una expresión al principio de la iteración esta es evaluada; si la condición es verdadera realizará el ciclo, si es falsa la repetición cesará.
Símbolo del Para. Esta estructura de control repetitiva se usa generalmente cuando se conoce de antemano el número de iteraciones.
Símbolo Repita Hasta. funciona igual que la estructura Mientras, con la diferencia que al menos una vez hará el grupo de instrucciones y luego evaluará una condición. Si la condición evaluada es falsa continua dentro del ciclo y si es verdadera termina la iteración.
Líneas de flujo o dirección. Indican la secuencia en que se realizan las operaciones.
Recomendaciones para el diseño de Diagramas de Flujo •
Se deben usar solamente líneas de flujo horizontal y/o vertical.
•
Se debe evitar el cruce de líneas utilizando los conectores.
•
Se deben usar conectores sólo cuando sea necesario.
•
No deben quedar líneas de flujo sin conectar.
•
Se deben trazar los símbolos de manera que se puedan leer de arriba hacia abajo y de izquierda a derecha.
•
Todo texto escrito dentro de un símbolo deberá ser escrito claramente, evitando el uso de muchas palabras.
PSEUDOCÓDIGO: Es un lenguaje de especificación de algoritmos. El uso de tal lenguaje hace el paso de Codificación final (esto es, la traducción a un lenguaje de programación) relativamente fácil. El pseudocódigo nació como un lenguaje similar al inglés y era un medio representar básicamente las estructuras de control de programación estructurada. Se considera un primer borrador, dado que el pseudocódigo tiene que traducirse posteriormente a un lenguaje de programación. Cabe señalar que el pseudocódigo no puede ser ejecutado por una computadora. La ventaja del pseudocódigo es que en su uso en la planificación de un programa, el programador
se puede concentrar en la lógica y en las estructuras de control y no preocuparse de las reglas de un lenguaje específico. Es también fácil modificar el pseudocódigo si se descubren errores o anomalías en la lógica del programa, además de todo esto es fácil su traducción a lenguajes como pascal, COBOL, C, FORTRAN o BASIC. El pseudocódigo utiliza para representar las acciones sucesivas palabras reservadas en inglés (similares a sus homónimos en los lenguajes de programación), tales como star,begin, end, stop, if-then-else, while, repeat-until….etc
DIAGRAMAS ESTRUCTURADOS (NASSI-SCHNEIDERMAN): El diagrama N-S de Nassi-Schneiderman, también conocido como diagrama de Chapin, es como un diagrama de flujo en el que se omiten las flechas de unión y las cajas son contiguas. Las acciones sucesivas se escriben en cajas sucesivas, y, como en los diagramas de flujo, se pueden escribir diferentes acciones en una caja. Los Diagramas Estructurados, son una técnica que permite formular algoritmos mediante una representación geométrica y de asignación de espacios de un bloque específico.
4.1.2 TIPOS DE ALGORITMOS La mayoría de los sistemas expertos utilizan algoritmos para el razonamiento. Este planteamiento tiene una limitación importante: el sistema es capaz de resolver solamente las situaciones previstas por quien ha diseñado el algoritmo. Por este motivo nadie califica de "inteligente" a un sistema de estas características. Existen distintos tipos de algoritmos de razonamiento: Algoritmos estáticos, es decir, algoritmos que funcionan siempre igual, independientemente del tipo de problema tratado. Por ejemplo, los sistemas basados en el método de resolución. Algoritmos probabilísticos, es decir, algoritmos que no utilizan valores de verdad booleanos sino continuos. Por ejemplo, los sistemas basados en lógica difusa. Algoritmos adaptativos, es decir, algoritmos con cierta capacidad de aprendizaje. Por ejemplo, los sistemas basados en redes neuronales. Los Algorítmos permiten resolver problemas computacionales mediante programación. Como Ejemplo podemos poner dos de los más usuales:
lenguajes
de
Divide y Vencerás: Consiste en descomponer un problema en subproblemas, resolver cada subproblema y combinar las soluciones. El resultado, es la solución del problema original. Si los subproblemas son todavía demasiado grandes, se utiliza la misma táctica con ellos, esto es, dividirlos a ellos también, utilizando un algoritmo recursivo que vaya dividiendo más el subproblema hasta que su solución sea trivial. Backtracking: El Backtracking o esquema de vuelta atrás, es un esquema que de forma sistemática y organizada, genera y recorre un espacio que contiene todas las posibles secuencias de decisiones. Este espacio se denomina el espacio de búsqueda del problema, y se representa como un árbol sobre el que el algoritmo hace un recorrido en profundidad partiendo de la raíz. Se conoce de antemano el orden en que se van a generar y recorrer sus nodos, y se continúa recorriendo el árbol mientras se cumplan las restricciones. Éste método tiene tres posibles
esquemas: encontrar una solución factible, encontrar todas las soluciones factibles, encontrar la mejor solución factible. Un algoritmo pueden además ser: Deterministico, sí en cada paso del algoritmo, es posible predecir la salida para una entrada dada. No determinísticos, sí existe uno ó más pasos en el algoritmo, para el cual es posible predecir cuál será la salida. Por esa razón se tienen los siguiente tipos de problemas: I) Polinomial: Existe al menos un algoritmo polinomial determinístico que lo resuelve. II) No -Polinomiales: Solo existen algoritmos polinomiales del tipo no deterministico que los resuelven.
4.1.2.1 ALGORITMOS DETERMINISTICOS En Ciencias de la computación, un algoritmo determinístico es un algoritmo que, en términos informales, es completamente predictivo si se conocen sus entradas. Dicho de otra forma, si se conocen las entradas del algoritmo siempre producirá la misma salida, y la máquina interna pasará por la misma secuencia de estados. Este tipo de algoritmos ha sido el más estudiado durante la historia y por lo tanto resulta ser el tipo más familiar de los algoritmos, así como el más práctico ya que puede ejecutarse en las máquinas eficientemente. Un modelo simple de algoritmo determinístico es la función matemática, de esta forma se puede establecer el siguiente paralelismo: la función extrae la misma salida para una entrada dada, al igual que los algoritmos determinísticos. La diferencia es que un algoritmo describe explícitamente como la salida se obtiene de la entrada, mientras que las funciones definen implícitamente su salida. Formalmente los algoritmos determinísticos se pueden definir en términos de una máquina de estado: un estado describe que está haciendo la máquina en un instante particular de tiempo. Justo cuando se produce la entrada, la máquina comienza en su estado inicial y, posteriormente, si la máquina es determinística, comenzará la ejecución de la secuencia de estados predeterminados. Una máquina puede ser determinística y no tener límite temporal para la ejecución o quedarse en un bucle de estados cíclicos eternamente. QUÉ HACE A UN ALGORITMO NO DETERMINÍSTICO Una variedad de factores puede ser la causa de que un algoritmo determinístico se comporte como de una forma no determinística: •
Si emplea en la ejecución de la secuencia de estados otro estado "externo" como entrada del proceso, como por ejemplo: una entrada de un usuario, una variable objetivo, un valor de un temporizador de hardware, un valor aleatorio, etc.
•
Si al operar se encuentra con concurrencia de estados, por ejemplo si tiene múltiples procesadores escribiendo al mismo tiempo en un fichero. En este caso el orden preciso en el que cada procesador escribe el dato puede afectar a la salida y no está pre-planificado su valor inicial.
•
Si un error (cuyo origen puede deberse al hardware o al software) causa un inesperado cambio en la secuencia de ejecución de estados.
Aunque los programas reales rara vez son puramente determinísticos, es más fácil que los seres humanos así como otros programas determinar sobre la esencia de lo que realmente son. Por esta razón, la mayoría de los lenguajes de programación y especialmente aquellos
que entran dentro de la categoría de programación funcional son lenguajes que hacen un esfuerzo en prevenir eventos que se ejecutan sin control. Por esta razón este tipo de restricciones fuerzan el carácter determinístico, a los algoritmos determinÍsticos se les denomina purely functional.
Problemas con los algoritmos determinanticos Para algunos problemas es muy difícil implementar un algoritmo determinístico. Por ejemplo, existen eficientes y simples algoritmos probabilísticos que pueden determinar si un número entero es primo o no, pero tienen una pequeña posibilidad de equivocarse. Algunos de ellos son muy conocidos desde 1970 (véase, por ejemplo, el Test de primalidad de Fermat); solamente tras otros 30 años de investigación focalizada en investigar se ha encontrado un algoritmo determinístico similar, pero mucho más lento. Otro ejemplo puede encontrarse en los problemas NP-completos. Dentro de esta categoría puede encontrarse la mayoría de los problemas prácticos; este tipo de problemas puede resolverse rápidamente empleando de forma masiva y paralela una máquina de Turing no determinística, pero no se ha encontrado aún un algoritmo eficiente para esta tarea, al menos ahora sólo encuentran soluciones aproximadas en casos especiales. Otro problema sobre el planteamiento de algoritmos determinísticos es que a veces no es "deseable" que los resultados sean completamente predecibles. Por ejemplo, si se es un jugador de blackjack, un algoritmo puede mezclar una serie de Generador de números Pseudoaleatorios y, de esta forma, un apostador espabilado podría averiguar los números del generador y determinar las cartas sobre la mesa de juego permitiendo engañar durante todo el tiempo al croupier (esto ocurre actualmente). Problemas similares pueden encontrarse en criptografía, donde las claves privadas a menudo se crean mediante uno de estos generadores. Este tipo de problemas se evita mediante el empleo de un generador criptográfico seguro de números Pseudoaleatorios.
4.1.2.2 ALGORITMOS APROXIMADOS Un algoritmo de aproximación es un algoritmo que entrega una solución con una garantía teórica de cercanía al óptimo. Más aun, es frecuente que estos algoritmos posean un desempeño práctico muy superior a su garantía teórica. En las últimas décadas, los algoritmos de aproximación han sido (y continúan siendo) un tema central de investigación en computación teórica y su aplicabilidad es cada vez más evidente.
4.1.2.3 ALGORITMOS HEURÍSTICOS En computación, dos objetivos fundamentales son encontrar algoritmos con buenos tiempos de ejecución y buenas soluciones, usualmente las óptimas. Una heurística es un algoritmo que abandona uno o ambos objetivos; por ejemplo, normalmente encuentran buenas soluciones, aunque no hay pruebas de que la solución no pueda ser arbitrariamente errónea en algunos casos; o se ejecuta razonablemente rápido, aunque no existe tampoco prueba de que siempre será así. Las heurísticas generalmente son usadas cuando no existe una solución óptima bajo las restricciones dadas (tiempo, espacio, etc.), o cuando no existe del todo. A menudo, pueden encontrarse instancias concretas del problema donde la heurística producirá resultados muy malos o se ejecutará muy lentamente. Aún así, estas instancias concretas pueden ser ignoradas porque no deberían ocurrir nunca en la práctica por ser de origen teórico. Por tanto, el uso de heurísticas es muy común en el mundo real.
4.1.2.4 ALGORITMOS VORACES Un algoritmo voraz (también conocido como ávido o devorador) es aquel que, para resolver un determinado problema, sigue una metaheurística consistente en elegir la opción óptima en cada paso local con la esperanza de llegar a una solución general óptima. Este esquema algorítmico es el que menos dificultades plantea a la hora de diseñar y comprobar su funcionamiento. Normalmente se aplica a los problemas de optimización.
Esquema Dado un conjunto finito de entradas C, un algoritmo voraz devuelve un conjunto S (seleccionados) tal que y que además cumple con las restricciones del problema inicial. Cada conjunto S que satisfaga las restricciones se le suele denominar prometedor, y si éste además logra que la función objetivo se minimice o maximice (según corresponda) diremos que S es una solución óptima.
Elementos de los que consta la técnica •
El conjunto C de candidatos, entradas del problema.
•
Función solución. Comprueba, en cada paso, si el subconjunto actual de candidatos elegidos forma una solución (no importa si es óptima o no lo es).
•
Función de selección. Informa de cuál es el elemento más prometedor para completar la solución. Éste no puede haber sido rechazado o escogido con anterioridad. Cada elemento es considerado una sola vez. Luego, puede ser rechazado o aceptado y pertenecerá a .
•
Función de factibilidad. Informa si a partir de un conjunto se puede llegar a una solución. Lo aplicaremos al conjunto de seleccionados unido con el elemento más prometedor.
•
Función objetivo. Es aquella que queremos maximizar o minimizar, el núcleo del problema.
Funcionamiento El algoritmo escoge en cada paso al mejor elemento posible, conocido como el elemento más prometedor. Se elimina ese elemento del conjunto de candidatos ( ) y, acto seguido, comprueba si la inclusión de este elemento en el conjunto de elementos seleccionados ( ) produce una solución factible. En caso de que así sea, se incluye ese elemento en S. Si la inclusión no fuera factible, se descarta el elemento. Iteramos el bucle, comprobando si el conjunto de seleccionados es una solución y, si no es así, pasando al siguiente elemento del conjunto de candidatos. Una vez finalizado el bucle, el algoritmo comprueba si el conjunto S es una solución o no, devolviendo el resultado apropiado en cada caso. El algoritmo se muestra a continuación: // Esquema general de un algoritmo voraz función //C es el conjunto de candidatos// mientras
y no solución(S) hacer
si
entonces
si solución(S) entonces devolver //S es una solución// si no devolver //No hay soluciones//
4.1.3 ALGORITMOS PROBABILISTICOS Un algoritmo probabilista (o probabilístico) es un algoritmo que basa su resultado en la toma de algunas decisiones al azar, de tal forma que, en promedio, obtiene una buena solución al problema planteado para cualquier distribución de los datos de entrada. Es decir, al contrario que un algoritmo determinista, a partir de unos mismos datos se pueden obtener distintas soluciones y, en algunos casos, soluciones erróneas. Se puede optar por la elección aleatoria si se tiene un problema cuya elección óptima es demasiado costosa frente a la decisión aleatoria. Un algoritmo probabilista puede comportarse de distinta forma aplicando la misma entrada. •
A un algoritmo determinista nunca se le permite que no termine: hacer una división por 0, entrar en un bucle infinito, etc.
•
Si existe más de una solución para unos datos dados, un algoritmo determinista siempre encuentra la misma solución (a no ser que se programe para encontrar varias o todas).
•
Un algoritmo probabilista puede encontrar soluciones diferentes ejecutándose varias veces con los mismos datos.
•
A un algoritmo determinista no se le permite que calcule una solución incorrecta para ningún dato.
•
Un algoritmo probabilista puede equivocarse siempre que esto ocurra con una probabilidad pequeña para cada dato de entrada.
•
Repitiendo la ejecución un número suficiente de veces para el mismo dato, puede aumentarse tanto como se quiera el grado de confianza en obtener la solución correcta.
•
El análisis de la eficiencia de un algoritmo determinista es, en determinadas ocasiones, difícil.
•
El análisis de los algoritmos probabilistas es, a menudo, muy difícil.
4.1.4 IDENTIFICACION DEL PROBLEMA Te vas a preguntar ¿Y que tiene que ver esto con la identificación de un problema?, lo más importante es el que identifiques ¿quienes son (posibles usuarios) y como se puede presentar este problema? Cuando detectamos que la solución se puede dar por medio del Diseño, háblese del Diseño Gráfico, Industrial o Arquitectónico y no por otro tipo de alternativas de solución como puede ser por medio de una nueva propuesta administrativa, o una solución médica como si se tratara de algún padecimiento que se resuelve con un fármaco o una terapia, o un nuevo proceso en alguna actividad que no se esta bien realizada, entonces es un problema que a nosotros nos interesa y que podemos buscarle una solución.
La identificación de quien es el que tiene el problema puede ser cualquier persona grupo social o empresa, el como se presenta este problema es labor de nosotros como diseñadores el tratar de buscar el medio o proceso para llegar a dar una respuesta al mismo. Un ejercicio sencillo es el que te presento a continuación y que te permite tener un panorama amplio de las posiblidades de detección del problema. Primero, toma un pedazo de papel y, en la parte superior izquierda escribe lo siguiente: "QUIEN ES EL QUE PADECE EL PROBLEMA". Enlista 7 cosas sobre el mismo. "COMO SE PRESENTA EL PROBLEMA", cosas que identifiquen las causas del problema. Una vez que hayas completado tu lista, enumera cada uno de estos aspectos por orden de importancia. Del otro lado del papel, enlista las cosas en las que creas que pueden ser los factores que den una solución al problema Cuando hayas terminado, dibuja (boceta) o escribe una idea debajo de ambas listas y pregúntate: "Si hubiera de tres a cinco productos o servicios que pudieran mejorar ese problema, ¿cuáles y cómo serían?".
4.1.5 PLANTEAMIENTO DEL PROBLEMA Cuando nos encontramos delante de un problema así lo que nos podemos plantear, en un principio, es cómo se finaliza la ejecución del programa y cuáles son las estructuras e instrucciones que se repiten. En este ejemplo, el proceso que se repite es el movimiento de posición en posición, hasta que se encuentra un bloque con un punto (.). Con lo que nos podemos plantear que todo nuestro programa estará englobado dentro de esta estructura: Mientras BloqueEncima <> "." hacer ... MoverDer Fin Mientras Los puntos suspensivos se sustituirán por más instrucciones después de seguir analizando el problema y la instrucción MoverDer sabemos que también estará ya que nos tenemos que ir desplazando por las diferentes posiciones. 2.- Después de analizar que es lo que se repite y cómo debe acabar el programa, debemos pensar en que es lo que se debe hacer en cada repetición, dicho de otra manera, cuáles son las instrucciones que se deben hacer en cada una de las posiciones. Veamos lo que realizará el Robot en cada uno de los pasos: -Mirar qué bloque tiene encima. -En caso de ser una de las letras (a, e, i, o, u), incrementar en 1 la variable que deberemos crear para cada una de las letras. A estas variables vamos a llamarlas LetraA, LetraE, LetraI, LetraO, LetraU que definiremos como siempre al principio del programa. Debemos acordarnos de definir e inicializar las variables que vamos a utilizar en nuestro ejemplo. Esto lo haremos al principio del programa, fuera del bucle ya que sino, las variables siempre se irían reinicializando y no se incrementarían. -Una vez mirada la letra del bloque que tenemos encima pasaremos a movernos una posición hacia la derecha para volver a empezar los pasos hasta ahora indicados.
4.1.6 ANALISIS DEL PROBLEMA (ALTERNATIVAS DE SOLUCION) Consiste en establecer una serie de preguntas acerca de lo que establece el problema, para poder determinar si se cuenta con los elementos suficientes para llevar a cabo la solución del mismo, algunas preguntas son:
?Con qué cuento? Cuáles son los datos con los que se va a iniciar el proceso, qué tenemos que proporcionarle a la computadora y si los datos con los que cuento son suficientes para dar solución al problema. ?Qué hago con esos datos? Una vez que tenemos todos los datos que necesitamos, debemos determinar que hacer con ellos, es decir que fórmula, cálculos, que proceso o transformación deben seguir los datos para convertirse en resultados. ?Qué se espera obtener? Que información deseamos obtener con el proceso de datos y de que forma presentarla; en caso de la información obtenida no sea la deseada replantear nuevamente un análisis en los puntos anteriores. Es recomendable que nos pongamos en el lugar de la computadora y analicemos que es lo que necesitamos que nos ordenen y en que secuencia para producir los resultados esperados.
4.1.7 DISEÑO DE LA SOLUCION Una vez definido y analizado el problema, se procede a la creación del algoritmo (Diagrama de flujo ó pseudocódigo), en el cual se da la serie de pasos ordenados que nos proporcione un método explícito para la solución del problema. Es recomendable la realización de pruebas de escritorio al algoritmo diseñado, para determinar su confiabilidad y detectar los errores que se pueden presentar en ciertas situaciones. éstas pruebas consisten en dar valores a la variable e ir probando el algoritmo paso a paso para obtener una solución y si ésta es satisfactoria continuar con el siguiente paso de la metodología; de no ser así y de existir errores deben corregirse y volver a hacer las pruebas de escritorio al algoritmo.
4.1.8 PRUEBAS Y DEPURACION Prueba es el proceso de identificar los errores que se presenten durante la ejecución del programa; es conveniente que cuando se pruebe un programa se tomen en cuenta los siguientes puntos: 1. - Tratar de iniciar la prueba con una mentalidad saboteadora, casi disfrutando la tarea de encontrar un error. 2. - Sospechar de todos los resultados que arroje la solución, con lo cual se deberán verificar todos. 3. - Considerar todas las situaciones posibles, normales y aún las anormales. La Depuración consiste en eliminar los errores que se hayan detectado durante la prueba, para dar paso a una solución adecuada y sin errores.
4.1.9 DOCUMENTACIÓN Es la guía o comunicación escrita que sirve como ayuda para usar un programa, o facilitar futuras modificaciones. A menudo un programa escrito por una persona es usado por muchas otras, por ello la documentación es muy importante; ésta debe presentarse en tres formas: EXTERNA, INTERNA y AL USUARIO FINAL. Documentación Interna Consiste en los comentarios o mensajes que se agregan al código del programa, que explican las funciones que realizan ciertos procesos, cálculos o fórmulas para el entendimiento del mismo. Documentación Externa También conocida como Manual Técnico, está integrada por los siguientes elementos: Descripción del Problema, Nombre del Autor, Diagrama del Flujo y/o Pseudocódigo, Lista de
variables y constantes, y Codificación del Programa, esto con la finalidad de permitir su posterior adecuación a los cambios. Manual del Usuario Es la documentación que se le proporciona al usuario final, es una guía que indica el usuario como navegar en el programa, presentando todas las pantallas y menús que se va a encontrar y una explicación de los mismos, no contiene información de tipo técnico.
4.2 OPERADORES Esta es una lista de los operadores de los lenguajes C++ y C. Todos los operadores listados existen en C++. La tercera columna indica si también está presente en C. También hay que tener en cuenta que C no permite la sobrecarga de operadores. Los siguientes operadores son puntos de secuencia en ambos lenguajes (cuando no están sobrecargados): &&, ||, ?:, y , (el operador coma). C++ también incluye los operadores de conversión de tipos const_cast, static_cast, dynamic_cast y reinterpret_cast que no están listados en la tabla por brevedad. El formato de estos operadores significa que su nivel de precedencia no es importante. Estos operadores que están en C (con la excepción del operador coma y el operador flecha también se encuentran en Java, Perl, C# y PHP con la la misma precedencia, asociatividad y semántica. Con una única excepción: la asociatividad del operador ternario en PHP es de izquierda a derecha. Para los objetivos de esta tabla a, b y c representan valores válidos (literales, valores de variables o valores de retorno), nombres de objetos o valores según el caso.
Operadores aritméticos Nombre del operador Más unitario Suma Preincremento Postincremento Asignación con suma Menos unitario (negación) Resta Predecremento Postdecremento Asignación con resta Multiplicación Asignación con multiplicación División Asignación con división Módulo (Resto) Asignación con módulo
Sintaxis +a a + b ++a a++ a += b -a a - b --a a-a -= b a * b a *= b a / b a /= b a % b a %= b
Sobrecargable Incluido en C Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí
Operadores de comparación Nombre del operador Menor que
Sintaxis a < b
Sobrecargable Incluido en C Sí Sí
Menor o igual que Mayor que Mayor o igual que No igual que Igual que Negación lógica AND lógico OR lógico
a <= b a > b a >= b a != b a == b !a a && b a || b
Sí Sí Sí Sí Sí Sí Sí Sí
Sí Sí Sí Sí Sí Sí Sí Sí
Operadores a nivel de bit Nombre del operador Desplazamiento a la izquierda Asignación con desplazamiento a la izquierda Desplazamiento a la derecha Asignación con desplazamiento a la derecha Complemento a uno AND binario Asignación con AND binario OR binario Asignación con OR binario XOR binario Asignación con XOR binario
Sintaxis a << b a <<= b a >> b a >>= b ~a a & b a &= b a | b a |= b a ^ b a ^= b
Sobrecargable Incluido en C Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí
Otros operadores Nombre del operador Asignación básica Llamada a función Índice de Array Indirección (Desreferencia) Dirección de (Referencia) Miembro de puntero Miembro
Sintaxis a = b a() a[b] *a &a a->b a.b
Sobrecargable Incluido en C Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí No
Desreferencia a miembro por puntero
a->*b
Sí
No
Desreferencia a miembro por objeto Conversión de tipo Coma Condicional ternario
a.*b a , b
No Sí Sí
a ? b : c
No
No Sí Sí Sí
Resolución de ámbito
a::b
No
No
Puntero a función miembro
a::*b
No
No
No
Sí
No
No
Sí
No
Tamaño de Identificación de tipo Asignar almacenamiento
(tipo) a
sizeof a sizeof(tipo) typeid(a) typeid(tipo) new tipo
Asignar almacenamiento (Vector) Desasignar almacenamiento Desasignar almacenamiento (Vector)
new tipo[n]
Sí
No
delete a
Sí
No
delete[] a
Sí
No
Extensiones del lenguaje Nombre del operador Sintaxis Sobrecargable Incluido en C Vendedor Dirección de la etiqueta && etiqueta GCC Sí No Obtener tipo min y max
typeof a typeof(expr) a b a >? b
No
Sí
GCC
No
No
GCC
Precedencia de operadores La tabla siguiente es una lista que muestra el orden de precedencia y la asociatividad de todos los operadores del lenguaje de programación C++. Están listados de arriba a abajo por orden de precedencia descendente y con la misma descendencia en la misma celda (pueden haber varias filas de operadores en la misma celda). La precedencia de los operadores no cambia por la sobrecarga. Una tabla de precendencias, aunque adecuada, no puede resolver todos los detalles. Por ejemplo el operador ternario permite expresiones arbitrarias como operador central independientemente de la precedencia del resto de operadores. Así a ? b , c : d es interpretado como a ? (b, c) : d en vez de (a ? b), (c : d). También hay que tener en cuenta que el resultado sin paréntesis de una expresión de conversión en C no puede ser el operando de sizeof. Por eso sizeof (int) * x es interpretado como (sizeof(int)) * x y no como sizeof ((int) *x). Operador :: ++ -() [] . -> typeid()
Descripción Resolución de ámbito (solo C++) Post- incremento y decremento Llamada a función Elemento de vector Selección de elemento por referencia Selección de elemento con puntero Información de tipo en tiempo de ejecución (solo C++)
const_cast dynamic_cast reinterpret_cast static_cast
Conversión de tipo (solo C++) Conversión de tipo (solo C++) Conversión de tipo (solo C++) Conversión de tipo (solo C++)
++ -+!~ (type) * &
Pre- incremento y decremento Suma y resta unitaria NOT lógico y NOT binario Conversión de tipo Indirección
Asociatividad Izquierda a derecha
Derecha a izquierda
sizeof new new[] delete delete[] .* ->* */% +<< >> < <= > >= == != & ^ | && || c?t:f = += -= *= /= %= <<= >>= &= ^= |= throw ,
Dirección de Tamaño de Asignación dinámica de memoria (solo C++) Desasignación dinámica de memoria (solo C++) Puntero a miembro (solo C++) Multiplicación, división y módulo Suma y resta Operaciones binarias de desplazamiento Operadores relaciones "menor que", "menor o igual que", "mayor que" y "mayor o igual que" Operadores relaciones "igual a" y "distinto de" AND binario XOR binario OR binario AND lógico OR lógico Operador ternario
Izquierda a derecha
Derecha a izquierda
Asignaciones Operador Throw (lanzamiento de excepciones, solo C++) Izquierda a derecha
Coma
4.2.1 ARITMETICOS Los operadores aritméticos nos permiten, básicamente, hacer cualquier operación aritmética, que necesitemos (ejemplo: suma, resta, multiplicación, etc). En la siguiente tabla se muestran los operadores de los que disponemos en C y su función asociada. Tabla: Operadores aritméticos Operador Acción Ejemplo Resta
x=5
3; // x vale 2
Suma
x=2
3; // x vale 5
Multiplicación x = 2 3; // x vale 6 División
x = 6 2; // x vale 3
Módulo
x = 5 % 2; // x vale 1
Decremento
x = 1; x
; // x vale 0
Incremento
x = 1; x
; // x vale 2
4.2.2 LOGICOS Los operadores lógicos producen un resultado booleano, y sus operandos son también valores lógicos o asimilables a ellos (los valores numéricos son asimilados a cierto o falso según su valor sea cero o distinto de cero). Por contra, recuerde que las operaciones entre bits producen valores arbitrarios. Los operadores lógicos son tres; dos de ellos son binarios, el último (negación) es unario. Tienen una doble posibilidad de representación en el Estándar C++ actual: la representación tradicional que se indica a continuación, y la natural introducida recientemente que se detalla más adelante . •
Y lógico &&
•
O lógico ||
•
Negación lógica ! NOT
AND OR
Las expresiones conectadas con los operadores && y || se evalúan de izquierda a derecha, y la evaluación se detiene tan pronto como el resultado verdadero o falso es conocido (muchos programas tienen una lógica que se basa en este propiedad). &&
Operador Y lógico
También denominado por su nombre en inglés (generalmente en mayúsculas) AND lógico. Devuelve un valor lógico true si ambos operandos son ciertos. En caso contrario el resultado es false. Sintaxis expr-AND-logica && expresion-OR-inclusive Comentario: La operatoria es como sigue: El primer operando (de la izquierda) es convertido a bool. Para ello, si es una expresión, se evalúa para obtener el resultado (esta computación puede tener ciertos efectos laterales). A continuación, el valor obtenido es convertido a bool cierto/falso siguiendo las reglas de conversión estándar .Si el resultado es false, el proceso se detiene y este es el resultado, sin que en este caso sea necesario evaluar la expresión de la derecha (recuérdese que en el diseño de C++ prima la velocidad). Si el resultado del operando izquierdo es cierto, se continúa con la evaluación de la expresión de la derecha, que también es convertida a bool. Si el nuevo resultado es true, entonces el resultado del operador es true. En caso contrario el resultado es false. Nota: la Norma informa que antes de ser evaluada la expresión derecha, han sucedido todos los posibles efectos laterales de la expresión izquierda, a excepción de la destrucción de los posibles objetos temporales que se hubiesen creado. Ejemplo: int m[3] = {0,1,2}; int x = 0; if (m && x) cout << "Cierto."; else cout << "Falso."; Salida: Falso. El valor m, que es interpretado como un puntero al primer elemento de la matriz, es transformado a un bool. Como es distinto de cero (no es un puntero nulo) el resultado es cierto. A continuación, el valor x es convertido también a bool. En este caso la conversión produce falso, con lo que este es el resultado del paréntesis de la sentencia if. Ejemplo
#include bool alto = true, bajo = false, blanco = true, negro = false; int main (void) { if (alto && bajo) { cout << "Uno cierto" << endl; } else cout << "Uno falso" << endl; if (alto && blanco) { cout << "Dos cierto" << endl; } else cout << "Dos falso" << endl; if (bajo && negro) { cout << "Tres cierto" << endl; } else cout << "Tres falso" << endl; } Salida: Uno falso Dos cierto Tres falso || Operador O lógico Este operador binario devuelve true si alguno de los operandos es cierto. En caso contrario devuelve false. Sintaxis expr-OR-logica || expresion-AND-logica Comentario Este operador sigue un funcionamiento análogo al anterior. El primer operando (izquierdo) es convertido a bool. Para ello, si es una expresión, se evalúa para obtener el resultado (esta computación puede tener ciertos efectos laterales). A continuación el valor obtenido es convertido a bool cierto/falso siguiendo las reglas de conversión estándar . Si el resultado es true, el proceso se detiene y este es el resultado, sin que en este caso sea necesario evaluar la expresión de la derecha (recuérdese que en el diseño de C++ prima la velocidad). Si el resultado del operando izquierdo es false, se continúa con la evaluación de la expresión de la derecha, que también es convertida a bool. Si el nuevo resultado es true, entonces el resultado del operador es true. En caso contrario el resultado es false. Nota: el Estándar establece que antes de ser evaluada la expresión derecha, han sucedido todos los posibles efectos laterales de la expresión izquierda, a excepción de la destrucción de los posibles objetos temporales que se hubieran creado. Ejemplo #include bool alto = true, bajo = false, blanco = true, negro = false; int main (void) { if (alto || bajo) { cout << "Uno cierto" << endl; } else cout << "Uno falso" << endl; if (alto || blanco) { cout << "Dos cierto" << endl; } else cout << "Dos falso" << endl; if (bajo || negro) { cout << "Tres cierto" << endl; } else cout << "Tres falso" << endl; } Salida
Uno cierto Dos cierto Tres falso !
Operador NO lógico:
Este operador es denominado también negación lógica y se representa en el texto escrito por la palabra inglesa NOT (otros lenguajes utilizan directamente esta palabra para representar el operador en el código). Sintaxis ! expresion-cast Comentario El operando expresion-cast (que puede ser una expresión que se evalúa a un resultado es convertido a tipo bool, con lo que solo puede ser uno de los valores cierto/falso. A continuación el operador cambia su valor: Si es cierto es convertido a falso y viceversa. Resulta por tanto, que el resultado de este operador es siempre un tipo bool, aunque al existir una conversión estándar por la que un cero es convertido a false, y cualquier valor distinto de cero a true coloquialmente se dice que este operador convierte un operando 0 en 1 y uno no-cero en 0. En otras palabras: este operador devuelve cierto (true) si la expresión se evalúa a distinto de cero, en caso contrario devuelve falso (false). Ejemplo #include bool alto = true, bajo = false; int main (void) { if (alto) { cout << "Uno cierto" << endl; } else cout << "Uno falso" << endl; if (!alto) { cout << "Dos cierto" << endl; } else cout << "Dos falso" << endl; if (!bajo) { cout << "Tres cierto" << endl; } else cout << "Tres falso" << endl; } Salida: Uno cierto Dos falso Tres cierto Si E es una expresión, !E es equivalente a (0 == E). Como consecuencia, las expresiones que siguen son equivalentes dos a dos: if (! valid); if (valid == 0); ... if (valid); if (valid != 0);
Representación explícita Los operadores lógicos entre valores lógicos &&, ||, !; la relación de desigualdad !=; algunos de los operadores lógicos entre bits (&, |, ^, ~) y sus expresiones compuestas (&=, |=, ^=), tienen una representación realmente difícil de leer, con la desventaja adicional que sus símbolos no siempre están fácilmente accesibles en ordenadores con teclados distintos del estándar USA. Para resolver este problema, el Estándar C++ ha introducido nuevas formas para su representación; las denominamos formas explícitas o naturales, en razón de que se parecen más a las palabras correspondientes del lenguaje natural. Las nuevas formas constituyen palabras-clave, y la tabla de equivalencias es la siguiente: Palabra Símbolo Descripción clave and
&&
Operador Y lógico
or
||
Operador O lógico
not
!
Operador negación lógica
bitand
&
Operador AND entre bits
xor
^
Operador OR exclusivo entre bits
bitor
|
Operador OR inclusivo entre bits
compl
~
Operador complemento a uno de bits
and_eq
&=
xor_eq
^=
or_eq
|=
not_eq
!=
Asignación compuesta (AND entre bits) Asignación compuesta (XOR entre bits) Asignación compuesta (OR entre bits) Operador relacional de desigualdad
Nota: ni el compilador Borland C++ 5.5 ni MS VC++ 6.0 soportan esta característica del estándar, aunque el de Microsoft anuncia en su documentación que pueden utilizarse "defines". Por ejemplo: #define bitand & #define bitor | #define and_eq &= #define or_eq |= #define not_eq != Por su parte, el compilador GNU gcc dispone de la opción de compilación -fno-operatornames, que permite que las palabras-clave and, bitand, bitor, compl, not, y or, no sean tratadas como sinónimos de los operadores correspondientes.
4.2.3 JERARQUIA DE OPERADORES Jerarquía de Operaciones: ()
signo Potencia Producto y división Div Mod Suma y resta Concatenación Relacionales Negación And Or Datos de tipo entero tienen los operadores +, -, *, /, div, mod, abs, sqr, sqrt, ln, exp, sin, cos, tan, pow, etc. Los datos de tipo real tienen los mismos operadores enteros y además trunc, round, int, y otros. La suma y multiplicación de datos de tipo real cumplen la propiedad conmutativa, pero no siempre la asociativa y la distributiva. Para resolver una expresión aritmética se deben seguir las siguientes reglas: · Primero se resuelven las expresiones que se encuentran entre paréntesis. · Se procede aplicando la jerarquía de operadores. · Al evaluar una expresión, si hay dos operadores con la misma jerarquía, se procede a evaluar de izquierda a derecha. · Si hay expresiones relacionales, se resuelven primero paréntesis, luego se encuentran los valores de verdad de las expresiones relacionales y por último se aplica jerarquía de operadores lógicos. En caso de haber iguales, proceder de izquierda a derecha.
4.3 EXPRECIONES En programación, una expresión es una combinación de constantes, variables o funciones, que es interpretada (evaluada) de acuerdo a las normas particulares de precedencia y asociación para un lenguaje de programación en particular. Como en matemáticas, la expresión es su "valor evaluado", es decir, la expresión es una representación de ese valor.
Ejemplos de expresiones •
Expresión aritmética: 3+2, x+1, ...
•
Expresión lógica: x OR y, NOT x, ...
•
Expresión con predicados: P(a) AND Q(b), ...
4.4 ESTRUCTURAS DE CONTROL En programación, las estructuras de control permiten modificar el flujo de ejecución de las instrucciones de un programa. Con las estructuras de control se puede ejecutar instrucciones de forma condicionada. en la programación, se necesitan estrategias para resolver un problema, tan simple como llevar el peso de los pasajeros de un avión, como uno tan difícil como llevar la base de datos de un ministerio…
Es por eso que “Las estructuras de control” son las herramientas que nos ayudan a pensar en grande sin ninguna limitación. Imagina de no existieran, la programación perdería seguidores. Ha de mencionarse que hay ramificaciones de estas estructuras y que las mismas usan variables (para recordar, espero que hallas deducido esto):
å Estructuras Repetitivas. å Estructuras de Alternativas. Definámoslas…
å Estructuras Repetitivas: son aquellas estructuras que nos permiten repetir un número de instrucciones un determinado número de veces.
å Estructuras
de Alternativas: son aquellas estructuras que nos dan la posibilidad de escoger un camino, dependiendo de la opción que tengamos al evaluar una expresión (al decir expresión, no me refiero a matemáticas, sino; a una evaluación de por ejemplo si esto es esto, o aquello llego a, etc…¿me expliqué?)
Clasificación:
å Las estructuras repetitivas se clasifican en 3. Estructura, Para, Mientras y Hasta que. å Las estructuras de Alternativas se clasifican en 3. Estructura Sí-Entonces (condicional simple), Estructura Sí-Entonces-De lo contrario (condicional doble) y Estructura Caso.
Estructuras Repetitivas
å
Estructura Para: la usamos cuando sabemos cuatas veces se van a repetir las instrucciones o podemos decir, un número de veces conocido.
å Estructura Mientras: esta estructura funciona evaluando una opción. Si esta es cierta, entra al ciclo de repetición, de lo contrario continúa con el resto del código. Se utiliza cuando no sabemos cuantas veces se van a repetir.
å Estructura Hasta
que: al igual que la otra, utiliza una expresión para entrar al ciclo repetitivo. Si esta es falsa, el entra, y de lo contrario, continúa con la ejecución del código. Se utiliza cuando sabemos que se repetirán por lo menos una vez o cada vez que no sabemos cuantas veces se van a repetir.
Cabe señalar dos cosas: 1. Que es muy importante saber, que las estructuras Mientras y Hasta que, si trabajan con una expresión para entrar al ciclo, ellas necesitan, POR FUERZA, una expresión (dentro del código) que modifique a la variable del la expresión (antes de entrar). 2. Las variables a utilizar en las expresiones de las tres estructuras deben ser POR FUERZA, enteros, ya que no existe ciclo y medio para decir que la variable es flotante. Veámoslo en Algoritmo.
Estructura Para. Formato: Para (variable1=0; variable1>=número u otra variable; variable1=variable1+1[o dos, o tres]) { Código a ejecutar; }
De otra forma: entero x; Para (x=0; x>2[puedes usar el igual dependiendo de tú lógica]; x=x+1[es valido: x++]) { Código a ejecutar; } *cuando llega aquí, el regresa para evaluar la opción, para ver si es cierta o falsa, eso para con las otras dos estructuras. Explicación: cuando entra por primera vez, pregunta: x>2 (0>2), ¿por que cero?, ya que x vale 0; esto es cierto, el entra. Termina y vuelve pregunta: x>2 (en este caso será: 1>2, ya que al entrar la x aumenta en uno y así sucesivamente, hasta hacer la condición cierta (x>2).
Estructura Mientras. Formato: Mientras(expresión) { Código a ejecutar; Expresión que modifica a la expresión madre; } *cuando llega aquí, regresa para revisar la expresión. Ejemplo: entero y; Mientras(y<5) { Imprimir(“Hola@”); y=y+1; (expresión que modifica, ¿me expliqué con esto?) } *cuando llega aquí, regresa a verificar si la expresión es cierta. Explicación: se declara “y” como entero y toma el valor de 0 por defecto. Cuando llega al ciclo, pregunta: y<5 y="y"> “Se cuenta de 0 hacia delante. El 0 cuenta, pero si no quieres, puedes decir que comience en 1. Si realizas una prueba de escritorio con las dos formas, dan los dos, 5 repeticiones (de 0 a 4 y de 1 a 5)
¿Me estoy explicando? Estructura Hasta que. Formato: Hasta que(expresión) { Código a ejecutar; Expresión que modifica a la expresíon madre. }
*cuando llega aquí, regresa para revisar la expresión. Ejemplo: entero k; Hasta que (k>=2) { Imprima(“¿¿¿Estás aprendiendo?????@”); k++; (esto es válido y modifica a la “k” para utilizar en la expresión) } *cuando llega aquí, regresa a verificar si la expresión es falsa. La explicación es la misma, solo que la exopresión debe ser falsa para entrar.
Estructuras Alternativas
å Estructura Sí-Entonces (condicional simple): se usa cuando, al evaluar una expresión, si está es cierta, entre a ejecutar un único código de instrucciones.
å
Estructura Sí-Entonces-De lo contrario (condicional doble): la usamos cuando al evaluar una opción, si esta es cierta, ejecuta una serie de instrucciones; de darse que no es cierta, ejecutará el otro código de instrucciones.
å Estructura
Caso: se usa cuando se sabe que se escogerá más de dos opciones. Podemos pensar que sería como un menú, de hecho, es esta la estructura propicia para hacer menús. Auque, como la lógica es la que manda, también se pude hacer un menú con estructuras Sí-Entonces o Sí-Entonces-De lo contrario. Estas estructuras estarían embebidas (una dentro de la otra). Esta estructura trabaja con una sola variable que será entera. Dependiendo del valor que tenga, entrará buscando el caso que conquierde con el valor, cuando lo encuentra, ejecutará el código que esté escrito dentro del mismo. Cabe señalar que es muy importante que dentro del código debe estar la sentencias “break;”, que le dice a la estructura, que ya terminó, y que debe salir, para continuar con el resto del código.
Veamos los formatos.
Estructura Sí-Entonces. Formato: Sí (condición) { Código a ejecutar; } Ejemplo: Sí(a>5) { Imprima (“a tiene un valor mayor que 5, por eso entró, ya es cierto”); }
Estructura Sí-Entonces-De lo contrario. Formato:
Sí (condición) { Código a ejecutar si la condición es cierta; } De lo contrario { Código a ejecutar si no se cumple la condición; } Ejemplo: Sí (a<3) { Imprima (“a tiene un valor menor que 3”); } De lo contrario { Imprima (“a tiene un valor mayor que 3”); } Si no se cumple, entra a la parte falsa.
Estructura Caso. Formato: Caso (variable) { Caso 1 { Código de instrucciones ejecutar si la condición es correcta; } Caso 2 { Código de instrucciones ejecutar si la condición es correcta; } Caso 3 { Código de instrucciones ejecutar si la condición es correcta; } Y así sucesivamente… }*esta es la llave que cierra el cuerpo del caso Ejemplo: Caso (a)
{ Caso 1 { Imprima (“¿Estás aprendiendo?”); break; } Caso 2 { Imprima (“Si no entiendes, pregúntame!!!”); break; } }*esta es la llave que cierra el cuerpo del caso. Si la a es 1, entra y realiza lo que está en el bloque uno, si es dos, lo que está en el bloque dos.
4.4.1 SELECTIVAS Existen tres tipos de estructuras de control selectivas, estas se basan en una condición o en una opción para decidir la parte del programa por el que pasará. a. Simple b)Doble o compuesta c)Múltiple Selectiva simple.- evalúa una condición, si esta es verdadera ejecuta la acción o acciones especificadas, si es falsa no realiza ninguna acción.
Nota: Si existe sola una instrucción o sentencia dentro de la condición no es necesario marcarlos con inicio y fin, en caso contrario si, como se muestra en el diagrama anterior. Selectiva doble o compuesta.- evalúa una condición, si esta es verdadera ejecuta la acción o acciones especificadas, si es falsa ejecuta otra acción o acciones.
Nota: Si existe sola una instrucción o sentencia dentro de la condición no es necesario marcarlos con inicio y fin como en este caso que la condición fue falsa, en caso contrario si, en este ejemplo cuando la condición fue verdadera. Ejemplo: Imprimir si un número es positivo o negativo
Nota: las variables no se especifican en el diagrama de flujo, pero si en el pseudocódigo .
4.4.2 ITERATIVAS En C existen 3 estructuras repetitivas: while, for y do .. while
Estructura While Sintaxis:
while(condición) � Acción; En este caso, la sentencia Acción es ejecutada mientras el condicional condición se evalúa verdadera (distinta de 0) En el caso de que el cuerpo del while (acciones a ejecutar en caso de que el condicional se verifique) posea más de una sentencia, todas ellas son encerradas entre llaves:
while(condición) { � Acción1; � Acción2; � ...
} El condicional es una expresion relacional que puede involucrar operadores relacionales (>, <, >=, <=, ==, !=) y/o operadores logicos (&&, ||, !) Ejemplo: /* Programa que imprime la tabla de conversión de Fahrenheit a Celsius para F = 0, 20, 40,..., 300 */ #include <stdio.h> int main() { � int Lower, Upper, Step; � float Fahr, Celsius; � � � �
Lower = 0; Upper = 300; Step = 20; Fahr = Lower;
� while(Fahr <= Upper) � { ��� Celsius = (5.0/9.0) * (Fahr - 32.0); ��� printf("%4.0f F -> %6.1f C\n", Fahr, Celsius); ��� Fahr = Fahr + Step; � } /* fin del while */ � ��return 0; } /* fin del main */
NOTAS: Lazo while(...) { ... } Lo que se encuentra entre paréntesis es una expresión a evaluar. Mientras el resultado de la misma sea distinto de cero, se ejecutan las sentencias asociadas que se encuentran encerradas entre llaves. A este tipo de sentencias se las llama sentencias compuestas. Si el cuerpo de esta sentencia consiste en una sola sentencia simple, pueden omitirse las llaves. Las sentencias compuestas no llevan el carácter; como terminador. Para mejorar la legibilidad del programa, conviene intentar las sentencias compuestas. Cálculo y asignación: Celsius = (5.0/9.0) * (Fahr - 32.0) El punto decimal en los operandos de la división es requerido para que la operación sea llevada en punto flotante; de lo contrario la misma se efectúa como cociente de números enteros, truncando por lo tanto el resultado a cifras enteras. En nuestro caso será truncado a 0. Estructura for Esta estructura es una generalización de la estructura while usada en el ejercicio anterior. Su función es ejecutar iterativamente el cuerpo del bloque, que como en el caso del while
puede ser simple o compuesto. La definición de esta estructura de control posee 3 partes separadas por el carácter ";".
for(a; b; c) { � ... � ... } La parte a es la de inicialización, y puede poseer una sentencia, ninguna, o varias separadas por el carácter ",". Esta parte se ejecuta inmediatamente antes de entrar en el ciclo. La parte b es el criterio o condición de control de la iteración. Se evalúa antes de entrar a cada ciclo, inclusive en la primer iteración. Si su resultado es distinto de cero se ejecuta el ciclo; sino se abandona el ciclo y se sigue con la sentencia posterior al cuerpo del for. La parte c es la re inicialización, que es ejecutada al final de cada ciclo. Podemos simular el bloque for con la siguiente lógica:
a; while(b) { � ... � ... � c; }
Ejemplo: /* Tabla de conversión de grados F a Celsius utilizando constantes simbólicas y bloque for */ #include <stdio.h> #define LOWER 0 #define UPPER 300 #define STEP 20 main() { int Fahr; for(Fahr = LOWER; Fahr <= UPPER; Fahr += STEP) printf("%4.0f F -> %6.1f C\n", Fahr, (5.0/9.0)* (Fahr - 32)); } NOTA:
Uso de constantes simbólicas. Cuando se requieran valores numéricos constantes en un programa, deben definirse como constantes y no usar sus valores numéricos dentro del programa. C permite definir constantes simbólicas (directiva #define al preprocesador) que asocian un símbolo (LOWER, UPPER, STEP) con una expresión (0,300 y 20 respectivamente) de tal manera que el preprocesador reemplaza cualquier ocurrencia de esos símbolos por sus expresiones asociadas
Estructura Do-While la estructura de control do-while es una variación sobre el bloque while
do { Acción1; Acción2; }while(condición); La diferencia esta en que la condición se chequea al final y las acciones son ejecutadas al menos una vez. Por ejemplo /*
Programa que pide al usuario un número entero entre 1 y 10. Se continua pidiendo el valor hasta que cumpla la condición */ #include <stdio.h> int main() { � int n, error; � do { ����� printf("Ingrese un número entero entre 1 y 10: "); ����� scanf("%d", &n); ����� if (error = (n < 1 || n > 10)) �������� printf("\nERROR: Intentelo nuevamente!!\n\n"); �����} while(error); /* ahora puedo procesar el valor ingresado sabiendo que es correcto. */ ��� return 0; } /* fin del main */