7.Estructuras de control de flujo.

7.1.Introducción.

7.2.Bifurcaciones.

7.3.Bucles.

7.4.Sentencias de control de flujo.

7.5.Ejemplos.

7.6.Ejercicios.




7.1.Introducción.

En principio, las sentencias de un programa en C se ejecutan secuencialmente, esto es, cada una a continuación de la anterior empezando por la primera y acabando por la última. 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, y los bucles, que permiten ejecutar repetidamente un conjunto de instrucciones tantas veces como se desee, cambiando o actualizando ciertos valores.

7.2.Bifurcaciones.

7.2.1.Bifurcación simple (if).

Esta sentencia de control permite ejecutar o no una sentencia simple o compuesta según se cumpla o no una determinada condición. Esta sentencia tiene la siguiente forma general:

...

if (expresion)

sentencia;

...


Explicación: Se evalúa expresion. Si el resultado es verdadero (true, ≠0), se ejecuta sentencia; si el resultado es falso (false , =0), se salta sentencia y se prosigue en la línea siguiente. Hay que recordar que sentencia puede ser una sentencia simple o compuesta (bloque { ... }).

Ejemplos:

...

/*Imprime el mayor de dos números.*/

mayor=b;

if (a>b)

mayor=a;

printf(“el mayor es %d”,mayor);

...


...

/*Convierte un número de negativo a positivo y añade 1 a la cantidad de números negativos.*/

...

if(a<0)

{

b=-a;

negativo=negativo+1;

}

printf(“%d sin signo es %d y llevamos”

“ %d números negativos”, a, b, negativo);

...


7.2.1.Bifurcación doble (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. La forma general es la siguiente:

...

if (expresion)

sentencia_1;

else

sentencia_2;


Explicación: Se evalúa expresion. Si el resultado es verdadero(true, ≠0), se ejecuta sentencia_1 y se prosigue en la línea siguiente a sentencia_2; si el resultado es falso (false, =0), se salta sentencia_1, se ejecuta sentencia_2 y se prosigue en la línea siguiente. Hay que indicar aquí también que sentencia_1 y sentencia_2 pueden ser sentencias simples o compuestas (bloques { ... }).

Ejemplo:

...

if (a<1000)

printf(“el número introducido es pequeño");

else

printf(“el número introducido es grande”);

...



7.2.3.Bifurcación múltiple (if...else if....else).

Esta sentencia permite realizar una ramificación múltiple, ejecutando una entre varias partes del programa según se cumpla una entre n condiciones.

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;

...


Explicación: Se evalúa expresion_1. Si el resultado es verdadero, se ejecuta sentencia_1. Si el resultado es falso, se salta sentencia_1 y se evalúa expresion_2. Si el resultado es verdadero se ejecuta sentencia_2, mientras que si es falso se evalúa expresion_3 y así sucesivamente.

Si ninguna de las expresiones o condiciones es verdadera 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.

7.2.4.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 como se puede ver presenta también importantes diferencias.

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;

}

...


Explicación: 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_n. Si el resultado coincide con el valor constante expresion_cte_2, se ejecuta sentencia_2 seguida de sentencia_3, ..., sentencia_n. 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 se desea ejecutar únicamente una sentencia_i (y no todo un conjunto de ellas), basta 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 expresion, poniendo varios case expresion_cte seguidos.

El siguiente ejemplo ilustra las posibilidades citadas:

...

switch (expresion)

{

case expresion_cte_1:

sentencia_1;

break;

case expresion_cte_2:

case expresion_cte_3:

sentencia_2;

break;

default:

sentencia_3;

}

...

7.2.5.Bifurcaciones anidadas.

Una sentencia if puede incluir otros if dentro de la parte correspondiente a su sentencia, 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 (a >= b)

if (b != 0.0)

c = a/b;

else

c = 0.0;

...


En principio 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 que la sentencia que sigue a else corresponde al segundo de los if, y así es en realidad, pues la regla es que el else pertenece al if más cercano. Sin embargo, no se olvide 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), y que 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 (a >= b)

{

if (b != 0.0)

c = a/b;

}

else

c = 0.0;

...


7.2.6.Operador condicional (¿... : ...).

El operador condicional es un operador con tres operandos (ternario) que realiza una función parecida a if.....else y que tiene la siguiente forma general:


expresion_1 ? expresion_2: expresion_3;


Explicación: Se evalúa expresion_1. Si el resultado de dicha evaluación es verdadero se ejecuta expresion_2; si el resultado es falso, se ejecuta expresion_3.

El siguiente ejemplo aclara el uso de este operador:


Equivale a:
mayor=(a>b)?a:b;

if(a>b)

mayor=a;

else

mayor=b;



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

7.3.1.Bucle mientras (while).

Esta sentencia permite ejecutar repetidamente una sentencia o bloque de sentencias, mientras se cumpla una determinada condición. La forma general es como sigue:

...

while ( expresion_de_control)

sentencia;

...

Explicación: Se evalúa expresion_de_control y si el resultado es falso se salta sentencia y se prosigue la ejecución. Si el resultado es verdadero se ejecuta sentencia y se vuelve a evaluar expresion_de_control.

Evidentemente alguna variable de las que intervienen en expresion_de_control habrá tenido que ser modificada, pues si no el bucle continuaría indefinidamente.

En otras palabras, sentencia se ejecuta repetidamente mientras expresion_de_control sea verdadera, y se deja de ejecutar cuando expresion_de_control se hace falsa.

Obsérvese que en este caso el control para decidir si se sale o no del bucle está antes de sentencia, por lo que es posible que sentencia no se llegue a ejecutar ni una sola vez.

7.3.2.Bucle mientras (do.....while). (parecido a hasta)

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 la sentencia; éstas se vuelven a ejecutar mientras expresion_de_control sea verdadera. La forma general de esta sentencia es:

...

do

sentencia;

while( expresion_de_control);

...

Donde sentencia puede ser una única sentencia o un bloque, y en la que debe observarse que hay que poner (;) a continuación del paréntesis que encierra a expresion_de_control, entre otros motivos para que esa línea se distinga de una sentencia while ordinaria.

7.3.3.Bucle para (for).

Este es quizás el tipo de bucle más versátil y utilizado del lenguaje C. Su forma general es la siguiente:

..

for (inicia;control;actualizacion)

sentencia;

...


Posiblemente la forma más sencilla de explicar la sentencia for sea utilizando la construcción while que sería equivalente. Dicha construcción es la siguiente:

...

inicia;

while (control)

{

sentencia;

actualizacion;

}

...


Donde sentencia puede ser una única sentencia terminada con (N), otra sentencia de control ocupando varias líneas (if, while, for, ...), o una sentencia compuesta o un bloque encerrado entre llaves {...}.

Antes de iniciarse el bucle se ejecuta inicia, que es una o más sentencias que asignan valores iniciales a ciertas variables o contadores. A continuación se evalúa control y si es falsa se prosigue en la sentencia siguiente a la construcción for; si es verdadera se ejecutan sentencia y actualizacion, y se vuelve a evaluar expresion_de_control.

El proceso prosigue hasta que control sea falsa.

La parte de actualizacion sirve para actualizar variables o incrementar contadores.

Un ejemplo típico puede ser la recogida de 10 números introducidos por teclado e impresión de la suma de todos ellos:

...

for (i=0, suma=0; i<10; i++)

{

scanf(“%d”,&numero);

suma=suma+numero;

}

printf(“La suma es %d”,suma);

...


Primeramente se inicializan las variables i y suma a cero; el ciclo se repetirá mientras que i sea menor que 10, y al final de cada ciclo el valor de i se incrementará en una unidad. En total, el bucle se repetirá 10 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.

Obsérvese que la inicializacion consta de dos sentencias separadas por el operador (,).

7.4.Sentencias de control de flujo.

7.4.1.Sentencia break.

La instrucción break interrumpe la ejecución del bucle donde se ha incluido, haciendo al programa salir de él aunque la expresión de control correspondiente a ese bucle sea verdadera.

7.4.2.Sentencia continue.

La sentencia continue hace que el programa comience el siguiente ciclo del bucle donde se halla, aunque no haya llegado al final de la sentencia compuesta o bloque.

7.4.3.Sentencia goto.

La sentencia goto hace saltar incindicionalmente, al programa, a la sentencia donde se haya escrito la etiqueta correspondiente. Por ejemplo:

...

if (condicion)

goto otro_lugar; /* salto al lugar indicado por la etiqueta*/

sentencia_1;

sentencia_2;

...

otro_lugar: /* esta es la sentencia a la que se salta*/

sentencia_3;

...




Obsérvese que la etiqueta termina con el carácter (smile. La sentencia goto no es una sentencia muy prestigiada en el mundo de los programadores de C, pues disminuye la claridad y legibilidad del código. Fue introducida en el lenguaje por motivos de compatibilidad con antiguos hábitos de programación, y siempre puede ser sustituida por otras construcciones más claras y estructuradas.

7.5Ejemplos.

Sentencia if:

/* hacefrio.c -- porcentaje de días bajo cero */

#include <stdio.h>

#define ESCALA "Celsius"

#define CONGELA 0

int main(void)

{

float temperatura;

int congelado = 0;

int dias = 0;


printf("Introduzca la lista de temperaturas mínimas diarias.\n");

printf("Use grados %s, y pulse s para terminar.\n", ESCALA);

while (scanf("%f", &temperatura) == 1)

{

dias++;

if (temperatura < CONGELA)

congelado++;

}

if (dias != 0)

printf("%d días en total: %.1f%% bajo cero.\n", dias, 100.0 * (float) congelado / dias);

if (dias == 0)

printf("¡No se han introducido datos!\n");

return 0; /* programa terminado correctamente */

}



Parte de lo anterior con if......else:

..

if (dias != 0)

printf("%d d¡as en total: %.1f%% bajo cero.\n", dias, 100.0 * (float) congelado / dias);

else printf("¡No se han introducido datos!\n");

return 0; /* programa terminado correctamente */

...


Más if.

/* divisores.c -- calcula divisores con if anidados */

#include <stdio.h>

#define NO 0

#define SI 1

int main(void)

{

long num; /* número a analizar */

long div; /* divisores potenciales */

int primo;


printf("Cálculo de los divisores de un número.\n");

printf("Introduzca el número deseado; ");

printf("pulse s para salir.\n");

while (scanf("%ld", &num) == 1)

{

for (div = 2, primo = SI; (div * div) <= num; div++)

{

if (num % div == 0)

{

if ((div * div) != num)

printf("%ld es divisible por %ld y %ld.\n", num, div, num/div);

else

printf("%ld es divisible por %ld.\n", num, div);

primo = NO;/*el número no es primo*/

}

}

if (primo == SI)

printf("%ld es primo.\n", num);

printf("Introduzca otro número para analizar; ");

printf("pulse s para salir.\n");

}

return 0;

}



Elección múltiple else if.

/*/* animales-else-if.c -- ejemplo de sentencia else if */

#include <stdio.h>

int main(void)

{

char ch;

printf("Déme una letra y responderé‚ con ");

printf("un nombre de animal\nque comience por ella.\n");

printf("Pulse una letra; para terminar pulse #.\n");

while((ch = getchar()) != '#')

{

if (ch >= 'a' && ch <= 'z') /* sólo minúsculas */

if (ch=='a')

printf("aranillo, oveja salvaje del Caribe\n");

else if (ch=='b')

printf("babirusa, cerdo arlequinado de Malasia\n");

else if (ch=='c')

printf("chascalote, ballena gigante del Nepal\n");

else if (ch=='d')

printf("destemplat, pingüino rojo de Kenia\n");

else if (ch=='e')

printf("equigobo, camello siberiano\n");

else

printf("Humm....‚ése no me lo sé.\n");

else

printf("Sólo me trato con letras minúsculas.\n");

while (getchar() != '\n')

continue; /* salta carácter nueva línea */

printf("Introduzca otra letra o un #.\n");

} /* fin del while */

return 0;

}



Este sistema no es muy “elegante” para las bifurcaciones múltiples es mucho más apropiada la sentencia switch, como se muestra a continuación.


Elección múltiple swich:

/* animales.c -- ejemplo de sentencia switch */

#include <stdio.h>

int main(void)

{

char ch;

printf("Déme una letra y responderé‚ con ");

printf("un nombre de animal\nque comience por ella.\n");

printf("Pulse una letra; para terminar pulse #.\n");

while((ch = getchar()) != '#')

{

if (ch >= 'a' && ch <= 'z') /* sólo minúsculas */

switch (ch)

{

case 'a' :

printf("aranillo, oveja salvaje del Caribe\n");

break;

case 'b' :

printf("babirusa, cerdo arlequinado de Malasia\n");

break;

case 'c' :

printf("chascalote, ballena gigante del Nepal\n");

break;

case 'd' :

printf("destemplat, pingüino rojo de Kenia\n");

break;

case 'e' :

printf("equigobo, camello siberiano\n");

break;

default :

printf("Humm....‚ése no me lo sé.\n");

} /* fin del switch */

else

printf("Sólo me trato con letras minúsculas.\n");

while (getchar() != '\n')

continue; /* salta carácter nueva línea */

printf("Introduzca otra letra o un #.\n");

} /* fin del while */

return 0;

}



Bucle while.

/* sumas.c -- suma enteros de forma interactiva */

#include <stdio.h>

int main(void)

{

long num;

long suma = 0L; /* inicializa suma a cero */

int estado;


printf("Introduzca un entero a sumar. ");

printf("Pulse s para salir.\n");

estado = scanf("%ld", &num); /*scanf() vale 1 si recoje un número*/

while (estado == 1) /* == significa "son iguales" */

{

suma = suma + num;

printf("Introduzca el siguiente. ");

printf("Pulse s para salir.\n");

estado = scanf("%ld", &num);

}

printf("La suma de estos enteros es %ld.\n", suma);

return 0;

}




Bucle más “C”: Nos permite sustituir las dos llamadas a la función scanf() por una sola, y a su vez dejar al código más estructurado.

...

while(scanf(“%ld”,&num)==1) /*mientras recojamos correctamente el número*/

{

/*acciones del bucle*/

}

...



Cuando un bucle finaliza:

/* cuando.c -- cuando se termina un bucle */

#include <stdio.h>

int main(void)

{

int n = 5;

while (n < 7)

{

printf("n = %d\n", n);

n++;

printf("Ahora n = %d\n", n);

}

return 0;

}


Salida del programa anterior:


n = 5

Ahora n = 6

n = 6

Ahora n = 7



Detalles de sintaxis:

/* while1.c -- ¿donde están las llaves? */

#include <stdio.h>

int main(void)

{

int n = 0;

while (n < 3)

printf("n es %d\n", n);

n++;

printf("Eso es todo lo que sabemos hacer\n");

return 0;

}

Otro:

/* while2.c -- ¿y los puntos y coma? */

#include <stdio.h>

int main(void)

{

int n = 0;

while (n++ < 3);

printf("n es %d\n", n);

printf("Eso es todo lo que sabemos hacer\n");

return 0;

}


¿Qué es más verdad?

/* verdad.c -- ¿què valores son ciertos? */

#include <stdio.h>

int main(void)

{

int n = 3;

while No

printf("%d\n", n--);

n = -3;

while No

printf("%2d\n", n++);

return 0;

}


Problemas con la verdad:

/* problema.c -- uso erróneo de = */

#include <stdio.h>

int main(void)

{

long num;

long suma = 0L;

int estado;

printf("Introduzca un entero a sumar. ");

printf("Pulse s para salir.\n");

estado = scanf("%ld", &num);

while (estado = 1)

{

suma = suma + num;

printf("Introduzca el siguiente. ");

printf("Pulse s para salir.\n");

estado = scanf("%ld", &num);

}

printf("La suma de estos enteros es %ld.\n", suma);

return 0;

}



Bucle con contador:

/* suerte1.c -- bucle contador */

#include <stdio.h>

#define NUMERO 22

int main(void)

{

int cont = 1; /* inicialización */

while (cont <= NUMERO) /* test */

{

printf("¡Buena suerte!\n"); /* acción */

cont++; /* incremento cont */

}

return 0;

}


Bucle con condición de salida do....while:

/* dowhile.c -- bucle con condición de salida */

#include <stdio.h>

int main(void)

{

char ch;

do

{

scanf("%c", &ch);

printf("%c", ch);

} while (ch != '#');

return 0;

}


Bucle for:

/* suerte2.c -- bucle contador que utiliza for */

#include <stdio.h>

#define NUMERO 22

int main(void)

{

int cont;

/*Todos los datos están en esta línea*/

for (cont = 1; cont <= NUMERO; cont++)

printf("¡Buena suerte!\n");

return 0;

}


Flexibilidad del bucle for:


1) Sentido descendente: for (seg=5; seg>0; seg--){.....}

2) Contar con incrementos: for (n=5; n<60; n+=5){.....}

3) Contar con caracteres: for (ch=’a’; ch<=z; ch++){.....}

4) Condiciones distintas: for (n=1; p*n<234; n++){.....}

5) Incremento geométrico: for (deuda=100.0; deuda<150.0; deuda*=1.1){.....}

6) Cualquier expresión válida en “c”: for (x=1; y<=75; y=(++x*5)+50){.....}

7) Expresiones en blanco: for (n=5; ans<=25;){....} for(;;){.....}

8) No es necesario iniciar una variable:

for(printf(“Empiece a meter números\n”); num!=6;)

scanf(“%d”, &num);

printf(“Este es el que yo quería”);

9) Se puede alterar los parámetros dentro del bucle:

for (n=1; n<minimo; n+=incremento){.....}

etc.

Zenón encuentra el bucle for:


/* zenon.c -- suma de una serie */

#include <stdio.h>

#define LIMITE 15

int main(void)

{

int cont;

float suma, x;

for (suma=0.0, x=1.0/2.0, cont=1; cont <= LIMITE; cont++, x /= 2.0)

{

suma += x;

printf("suma = %f en la etapa %d.\n", suma, cont);

}

return 0;

}



break:


/* break.c -- usa break para salir del bucle */

#include <stdio.h>

int main(void)

{

float largo, ancho;

printf("Calculo el área de un rectángulo.\n");

printf("Para salir introducir una letra en la anchura.\n");

printf("Longitud del rectángulo:\n");

while (scanf("%f", &largo) == 1)

{

printf("Longitud = %0.2f:\n", largo);

printf("Anchura del rectángulo\n");

if (scanf("%f", &ancho) != 1)

break;

printf("Anchura = %0.2f:\n", ancho);

printf("Area = %0.2f:\n", largo * ancho);

printf("Longitud del rectángulo:\n");

}

return 0;

}



continue:

/* salta.c -- usa continue para saltar parte del bucle */

#include <stdio.h>

#define MIN 0.0

#define MAX 100.0

int main(void)

{

float puntos, float total = 0.0, min = MAX,max = MIN;

int n = 0;

printf("Calcula el valor máximo, mínimo y la media"

" de una serie de números comprendidos entre 0 y 100.\n"

"Introduce una letra para terminar.\n");

printf("Introduzca puntuaciones:\n");

while (scanf("%f", &puntos) == 1)

{

if (puntos < MIN || puntos > MAX)

{

printf("%0.1f no es un valor válido.\n", puntos);

continue;

}

printf("Se acepta %0.1f:\n", puntos);

min = (puntos < min)? puntos: min;

max = (puntos > max)? puntos: max;

total += puntos;

n++;

}

if (n > 0)

{

printf("El promedio de %d valores es %0.1f.\n", n, total/n);

printf("Mínimo = %0.1f, máximo = %0.1f\n", min, max);

}

else

printf("No se han indicado valores válidos.\n");

return 0;

}




7.6.Ejercicios.

a)Realiza un programa que lea dos números del teclado y, mediante la sentencia if...else, muestre el mayor de dos números.

b)Haz un programa que, mediante la sentencia switch, presente en pantalla un sencillo menú con al menos cinco opciones.

c)Diseña un programa que muestre los números del 1 al 100 utilizando un bucle while.

d)Haz el mismo programa anterior, pero con un bucle for.

e)Construye un programa que muestre los números pares, comprendidos entre 1 y 100 y que, mediante break pare el bucle en un número previamente introducido por el teclado.

f)Realizar un programa con un bucle infinito para presentar permanentemente un menú que incluirá una opción de salida haciendo uso de la sentencia return.

g)Haz un programa que calcule la raíz cuadrada de un número por el método interactivo de Newton. ( ri=((n/ri)+ri)/2, test=ri*ri, repetir mientras n>test y n-test>=precisión o n<test y test-n>=precisión).

h)Realizar un programa que mediante la sentencia switch, indique el número de días que tiene el mes introducido por teclado, representado por los números entre 1 y 12.

i)Desarrollar un programa que realice la suma, resta y producto de dos números enteros y permita la selección de la operación mediante un menú.

j)Elabora un programa que muestre en pantalla un “triángulo mágico” como el que se muestra a continuación, y que permita seleccionar el número de líneas.





1







1
2
1





1
2
3
2
1



1
2
3
4
3
2
1

1
2
3
4
5
4
3
2
1

k)Haz un programa que muestre en pantalla una onda senoidal, una onda triangular y una cuadrada.

l)Juego de adivinar el número generado por el ordenador. Es necesario utilizar las funciones srand() y rand(), cuyo prototipo se encuentra en stdlib.h, la función time() que se define en time.h.

Last modified: Thursday, 27 May 2010, 10:28 AM