Universidad de Santiago Facultad de Ingeniería Algoritmos y estructura de datos Tema 1: Sentencias de Control Contenido ü Definiciones ü Sentencias Condicionales ü Sentencias de Ciclos SENTENCIAS DE CONTROL 1 INTRODUCCIÓN ............................................................................................................................. 2 2 SELECCIÓN...................................................................................................................................... 2 2.3 2.4 2.5 2.6 2.7 2.8 3 OPERADOR CONDICIONAL ............................................................................................................. 2 SENTENCIA IF ............................................................................................................................... 2 SENTENCIA IF..ELSE ................................................................................................................... 4 SENTENCIA IF..ELSE MÚLTIPLE ................................................................................................... 6 SENTENCIAS IF ANIDADAS............................................................................................................ 8 SENTENCIA SWITCH ................................................................................................................. 10 BUCLES ........................................................................................................................................... 12 3.3 SENTENCIA WHILE.................................................................................................................... 12 3.4 SENTENCIA FOR......................................................................................................................... 14 3.4.1 Flexibilidad del bucle FOR................................................................................................ 15 3.5 SENTENCIA DO..WHILE ............................................................................................................ 17 4 BREAK, CONTINUE Y GOTO ..................................................................................................... 18 5 EJERCICIOS ................................................................................................................................... 19 5.3 5.4 5.5 SELECCIÓN SIMPLE ..................................................................................................................... 19 SELECCIÓN MÚLTIPLE ................................................................................................................. 20 BUCLES....................................................................................................................................... 21 Tema 1. SENTENCIAS DE CONTROL 1 Introducción Las sentencias de un programa en C se ejecutan secuencialmente, esto es, una a continuación de la anterior empezando por la primera y acabando por la última. Sin embargo, el lenguaje C dispone de varias sentencias para modificar este flujo secuencial de la ejecución. Las más utilizadas se agrupan en dos familias: • Las bifurcaciones, que permiten elegir entre dos o más opciones según ciertas condiciones. • Los bucles, que permiten ejecutar repetidamente un conjunto de instrucciones tantas veces como se desee, cambiando o actualizando ciertos valores. 2 Selección 2.3 Operador condicional El operador condicional permite evaluar alternativamente expresiones según una condición lógica. Ofrece una forma de alternancia cómoda en ciertas ocasiones, pero demasiado simple para otras muchas. Tiene la siguiente forma general: <expresion_1> ? <expresion_2> : <expresion_3>; Se evalúa <expresion_1> y: • Si el resultado de dicha evaluación es TRUE, se ejecuta <expresion_2>. • Si el resultado es FALSE, se ejecuta <expresion_3>. 2.4 Sentencia IF Esta sentencia de control permite ejecutar o no una sentencia simple o compuesta según se cumpla o no una determinada condición. TRUE ¿? FALSE Acciones Tiene la siguiente forma general: ... if (<expresión>) <sentencia>; ... Se evalúa <expresión> y: • Si el resultado es TRUE, se ejecuta <sentencia> y se prosigue en la línea siguiente. • Si el resultado es FALSE, se salta <sentencia> y la ejecución continúa en la línea siguiente. Debe tenerse en cuenta que <sentencia> puede ser una sentencia simple o compuesta (bloque { ... }). Si fuese compuesta entonces tendría la forma: . . . if (<expresión>) { <sentencia>; <sentencia>; <sentencia>; . . . } . . . Ejemplo: . . . int D, d, c = 0; printf(“Dividendo: ”); scanf(“%d”, &D); printf(“Divisor: ”); scanf(“%d”, &d); if (d != 0) c = D / d; printf(“Resultado de la división: %d\n”, c); . . . Otro Ejemplo: . . . int D, d, c = 0; printf(“Dividendo: ”); scanf(“%d”, &D); printf(“Divisor: ”); scanf(“%d”, &d); if (d == 0) { printf(“El divisor no puede ser cero\n”); printf(“El resultado será el Divisor\n”); d = 1; } c = D / d; printf(“Resultado de la división: %d\n”, c); . . . 2.5 Sentencia IF..ELSE Esta sentencia permite realizar una bifurcación, ejecutando una parte u otra del programa según se cumpla o no una cierta condición. FALSE Acciones si FALSE TRUE ¿? Acciones si TRUE La forma general es la siguiente: . . . if (<expresión>) <sentencia_1>; else <sentencia_2>; . . . Se evalúa <expresión> y: • Si el resultado es TRUE, se ejecuta <sentencia_1> y se prosigue en la línea siguiente a <sentencia_2>. • Si el resultado es FALSE, se salta <sentencia_1>, se ejecuta <sentencia_2> y se prosigue en la línea siguiente. Nótese que tanto <sentencia_1> como <sentencia_2> pueden ser sentencias simples o compuestas (bloques { ... }). . . . if (<expresión>) { <sentencia>; <sentencia>; <sentencia>; . . . } else { <sentencia>; <sentencia>; <sentencia>; . . . } . . . Ejemplo: char c; c = getchar(); if (c == ‘\n’) putchar(c); else putchar(c + 1); Otro Ejemplo: . . . float f, g, h; . . . f = 24 * pow(b, 4) / 5; if (f > 25 && f < 50) { g = sqrt(f) * sin(b); h = PI * cos(g); } else { g = sqrt(f) * cos(b); h = log(f) * sin(g); } printf(“Los resultados son: %f, %f\n”, g, h); . . . 2.6 Sentencia IF..ELSE múltiple Esta sentencia permite realizar una ramificación múltiple, ejecutando una entre varias partes del programa según se cumpla una entre n condiciones. ¿? TRUE Acciones FALSE ¿? TRUE Acciones FALSE ¿? TRUE Acciones FALSE Acciones La forma general es la siguiente: if (<expresion_1>) <sentencia_1>; else if (<expresion_2>) <sentencia_2>; else if (<expresion_3>) <sentencia_3>; else if (...) ... [else <sentencia_n>;] Se evalúa <expresion_1> y: • Si el resultado es TRUE, se ejecuta <sentencia_1>. • Si el resultado es FALSE, se salta <sentencia_1> y se evalúa <expresion_2>. • Si el resultado es TRUE se ejecuta <sentencia_2>, mientras que si es FALSE se evalúa <expresion_3> y así sucesivamente. • Si ninguna de las expresiones o condiciones es TRUE se ejecuta <expresion_n> que es la opción por defecto (puede ser la sentencia vacía, y en ese caso puede eliminarse junto con la palabra else). Todas las sentencias pueden ser simples o compuestas. Ejemplo: /* Calculo del recibo de la luz */ #define TARIFA1 5.418 #define TARIFA2 7.047 #define TARIFA3 9.164 #define BASE1 1300.0 #define BASE2 3414.0 #define LIMITE1 240.0 #define LIMITE2 540.0 void main(void) { float kwh; float importe; // Kilowatios consumidos // del recibo printf(“¿Consumo en Kwh?”); scanf(“%f”, &kwh); if (kwh < LIMITE1) importe = TARIFA1 * kwh; else if (kwh < LIMITE2) importe = BASE1 + TARIFA2 * (kwh – LIMITE1); else importe = BASE2 + TARIFA3 * (kwh – LIMITE2); printf(“Por %.1f kwh es %.0f ptas.\n”, kwh, importe); } 2.7 Sentencias IF anidadas Una sentencia if puede incluir otros if dentro de la parte correspondiente a su sentencia. TRUE ¿? TRUE FALSE ¿? Acciones FALSE A estas sentencias se les llama sentencias anidadas (una dentro de otra), por ejemplo, if (a >= b) if (b != 0.0) c = a/b; En ocasiones pueden aparecer dificultades de interpretación con sentencias if...else anidadas, como en el caso siguiente: if (numero > 6) if (numero < 12) printf(“¡Caliente!\n”); else printf(“Lo siento, has perdido\n”); Que también podría ser escrito como: if (numero > 6) if (numero < 12) printf(“¡Caliente!\n”); else printf(“Lo siento, has perdido\n”); Se podría plantear la duda de a cuál de los dos if corresponde la parte else del programa. Los espacios en blanco (las indentaciones de las líneas) parecen indicar en el primer caso que la sentencia que sigue a else corresponde al segundo de los if, pero en el segundo caso parecen indicar justo lo contrario. Al ser el lenguaje C libre de formato las dos formas de escribir serán perfectamente válidas. Para resolver la ambigüedad la regla es: El else pertenece al if más cercano. Sin embargo, no se debe olvidar que el compilador de C no considera los espacios en blanco (aunque sea muy conveniente introducirlos para hacer más claro y legible el programa). Si se quisiera que el else perteneciera al primero de los if no bastaría cambiar los espacios en blanco, sino que habría que utilizar llaves, en la forma: if (numero > 6) { if (numero < 12) printf(“¡Caliente!\n”); } else printf(“Lo siento, has perdido\n”); Ahora el primer if se ajusta a la estructura general: if (<expresión>) <sentencia_1>; else <sentencia_2>; Ya que el bloque entre llaves es una sola sentencia (compuesta, pero solo una sentencia) ajustándose a la forma <sentencia_1>. Recuérdese que todas las sentencias if e if...else, equivalen a una única sentencia por la posición que ocupan en el programa. 2.8 Sentencia SWITCH La sentencia que se va a describir a continuación desarrolla una función similar a la de la sentencia if ... else con múltiples ramificaciones, aunque presenta también importantes diferencias. ¿? TRUE Acciones FALSE ¿? TRUE Acciones FALSE ¿? TRUE Acciones FALSE Acciones DEFAULT La forma general de la sentencia switch es la siguiente: switch (<expresion>) { case <expresion_cte_1>: <sentencia_1>; case <expresion_cte_2>: <sentencia_2>; ... case <expresion_cte_n>: <sentencia_n>; [default: <sentencia>;] } Se evalúa <expresion> y se considera el resultado de dicha evaluación. • Si dicho resultado coincide con el valor constante <expresion_cte_1>, se ejecuta <sentencia_1> seguida de <sentencia_2>, <sentencia_3>, ..., <sentencia>. • Si el resultado coincide con el valor constante <expresion_cte_2>, se ejecuta <sentencia_2> seguida de <sentencia_3>, ..., <sentencia>. • En general, se ejecutan todas aquellas sentencias que están a continuación de la <expresion_cte> cuyo valor coincide con el resultado calculado al principio. • Si ninguna <expresion_cte> coincide se ejecuta la sentencia que está a continuación de <default> si existe. Si se desea ejecutar únicamente una <sentencia_i> (y no todas las que va a continuación, hay que poner una sentencia break a continuación, en algunos casos puede utilizarse la sentencia return o la función exit()). El efecto de la sentencia break es dar por terminada la ejecución de la sentencia switch. Existe también la posibilidad de ejecutar la misma <sentencia_i> para varios valores del resultado de <expresión>, poniendo varios “case <expresion_cte>:” seguidos. switch (<expresion>) { case <expresion_cte_1>: <sentencia_1>; break; case <expresion_cte_2>: case <expresion_cte_3>: <sentencia_2>; break; default: <sentencia_3>; } Ejemplo: . . . char c; . . . c = getchar(); switch (c) { case case case case ‘+’: ‘-’: ‘*’: ‘/’: opcion = VALIDA; break; case ‘f’: case ‘F’: exit(0); default: opcion = INVALIDA; break; } . . . 3 Bucles Además de bifurcaciones, en el lenguaje C existen también varias sentencias que permiten repetir una serie de veces la ejecución de unas líneas de código. Esta repetición se realiza, bien un número determinado de veces, bien hasta que se cumpla una determinada condición de tipo lógico o aritmético. De modo genérico, a estas sentencias se les denomina bucles. Las tres construcciones del lenguaje C para realizar bucles son el while, el for y el do...while. 3.3 Sentencia WHILE Esta sentencia permite ejecutar repetidamente, mientras se cumpla una determinada condición, una sentencia o bloque de sentencias. ¿? FALSE TRUE Acciones La forma general es como sigue: while (<expresion_de_control>) <sentencia>; Se evalúa <expresion_de_control>: • Si el resultado es FALSE se salta <sentencia> y se prosigue la ejecución. • Si el resultado es TRUE se ejecuta <sentencia> y se vuelve a evaluar <expresion_de_control>. Alguna variable de las que intervienen en <expresion_de_control> habrá tenido que ser modificada, pues si no el bucle continuaría indefinidamente. La ejecución de sentencia prosigue hasta que <expresion_de_control> se hace FALSE, en cuyo caso la ejecución continúa en la línea siguiente a sentencia. En otras palabras, sentencia se ejecuta repetidamente mientras <expresion_de_control> sea TRUE, y se deja de ejecutar cuando <expresion_de_control> se hace FALSE. La condición para decidir si se sale o no del bucle está antes de <sentencia>, por lo que es posible que esta no se llegue a ejecutar ni una sola vez. Ejemplo: int i = 0; while (i++ < 5 ) printf(“EL valor de i es: %d\n”, i); La ejecución de este código escribirá esto en pantalla: El El El El El valor valor valor valor valor de de de de de i i i i i es es es es es 0 1 2 3 4 Dentro del bucle es necesario ejecutar acciones que hagan que la condición de control cambie alguna vez a falso, de lo contrario se entraría en un bucle infinito como en el ejemplo siguiente: int i = 0; while (i < 5 ) // No se emplea el operador ++ printf(“EL valor de i es: %d\n”, i); Esta ejecución escribirá esto en pantalla: El valor El valor El valor El valor El valor . . . . . . de de de de de i i i i i es es es es es 0 0 0 0 0 La sentencia del bucle también puede ser una sentencia compuesta (bloque) como en el ejemplo siguiente: fahrenheit = 0.0; while(fahrenheit <= 300.0 ) { centigrados = (5 * (fahrenheit - 32.0)) / 9.0; printf("%17.2lf%17.2lf\n", fahrenheit, centigrados); fahrenheit += 20.0; } Al evaluarse primero la condición de control es posible que nunca se ejecute el cuerpo del bucle: int i = 10; while (i < 5 ) { i++; printf(“EL valor de i es: %d\n”, i); } 3.4 Sentencia FOR For es quizás el tipo de bucle mas versátil y utilizado del lenguaje C. Inicialización ¿? FALSE TRUE Acciones Actualización Su forma general es la siguiente: for (<inicializacion>; <expresion_de_control>; <actualizacion>) <sentencia>; Posiblemente la forma más sencilla de explicar la sentencia for sea utilizando la construcción while equivalente: <inicializacion>; while (<expresion_de_control>) { <sentencia>; <actualizacion>; } • • • Antes de iniciarse el bucle se ejecuta <inicializacion>, que es una o más sentencias que asignan valores iniciales a ciertas variables o contadores. A continuación se evalúa <expresion_de_control>: o Si es FALSE se prosigue en la sentencia siguiente a la construcción for o Si es TRUE se ejecutan <sentencia> y <actualizacion>, y se vuelve a evaluar <expresion_de_control>. El proceso prosigue hasta que <expresion_de_control> sea FALSE. <inicializacion> es una o más sentencias que asignan valores iniciales a ciertas variables o contadores. <sentencia> puede ser una única sentencia terminada con (;), otra sentencia de control ocupando varias líneas (if, while, for, ...), o una sentencia compuesta o un bloque encerrado entre llaves {...}. <actualizacion> sirve para actualizar variables o incrementar contadores. Un ejemplo típico puede ser el producto escalar de dos vectores a y b de dimensión n: for (pe = 0.0, i=1; i<=n; i++) { pe += a[i]*b[i]; } • • • Se inicializa la variable pe a cero y la variable i a 1. El ciclo se repetirá mientras que i sea menor o igual que n. Al final de cada ciclo el valor de i se incrementará en una unidad. En total, el bucle se repetirá n veces. La ventaja de la construcción for sobre la construcción while equivalente está en que en la cabecera de la construcción for se tiene toda la información sobre como se inicializan, controlan y actualizan las variables del bucle, mientras que en el bucle while estás acciones están mezcladas con otras sentencias. Obsérvese que la inicialización consta de dos sentencias separadas por el operador (,). Ejemplo: int num; printf(“\tn\tn al cubo\n”); for (num = 1; num <= 6; num++) printf(“\t%5d\t5d\n”, num, num*num); Generará en pantalla la siguiente salida: n 1 2 3 4 5 6 n al cubo 1 8 27 64 125 216 3.4.1 Flexibilidad del bucle FOR Usando el bucle FOR de la forma vista es muy parecido a otros bucles FOR de distintos lenguajes, sin embargo es mucho más flexible que estos. Existen otras posibilidades, a continuación se muestran 9 de ellas: 1. Emplear el operador decremento para contar en sentido descendente en lugar de ascendente. for (n = 10; n > 0; n--) printf(“Quedan %d segundos\n”, n); printf(“Contacto!!!\n”); 2. Contar de dos en dos, diez, en diez, etc. for (n = 2; n < 60; n += 13) printf(“%d\n”, n); 3. Contar caracteres en vez de números. for (ch = ‘a’; ch < ‘z’; ch++) printf(“El caracter ASCII de %c es %d.\n”, ch, ch); 4. Comprobar alguna otra condición en lugar del número de iteraciones. for (num = 1; num*num*num < 560; num++) 5. Incrementar una cantidad en proporción geométrica en lugar de aritmética. for (deuda = 100.0; deuda < 150.0; deuda *= 1.1) printf(“Su deuda asciende a %.2f.\n”, dueda); En cada ciclo se incrementa la deuda un 10%. Mostrando esta salida: Su Su Su Su Su deuda deuda deuda deuda deuda asciende asciende asciende asciende asciende a a a a a 100.00. 110.00. 121.00. 133.10. 146.41. 6. Usar cualquier expresión legal como tercera expresión. for (x = 1; y <= 75; y = 5*x++ + 10) printf(“%10d %10d\n, x, y); 7. Se pueden dejar una o más expresiones en blanco (sin olvidar los ;). ans = 2; for (n = 3; ans <= 25;) ans = ans * n; ans = 2; n = 3; for (; ans <= 25;) ans = ans * n; for(;;) printf(“Impreso dentro de un bucle infinito\n”); 8. No es necesario que la primera expresión inicialize una variable. for (printf(“Dame numeros\n”); n == 6;) scanf(“%d”, &n); printf(“Este es el numero buscado!!!\n”); 9. Se pueden alterar los parámetros de las expresiones del bucle dentro del mismo. for (n = 1; n <= 10000; n += delta) 3.5 Sentencia DO..WHILE Esta sentencia funciona de modo análogo a while, con la diferencia de que la evaluación de <expresion_de_control> se realiza al final del bucle, después de haber ejecutado al menos una vez las sentencias entre llaves. Estas se vuelven a ejecutar mientras <expresion_de_control> sea TRUE. Acciones TRUE ¿? FALSE La forma general de esta sentencia es: do <sentencia>; while (<expresion_de_control>); <sentencia> puede ser una única sentencia o un bloque. En ese caso tomaría la forma: do { <sentencia>; } while (<expresion_de_control>); Ejemplo: char c; do { c = getchar(); putchar(c); }while (c != ‘\n’); Otro ejemplo: int i; do { printf(“Dame un numero entre 1 y 100: ”); scanf(“%d”, i); }while (i >0 && i <= 100); Lee del teclado un numero asegurándose de que el usuario lo teclea en el rango permitido.