Está en la página 1de 45
116 — El lenguaje de programacién C: disefio e implementacién de programas 5.1 INTRODUCCION Un programa de computador se puede definir como una secuencia ordenada de instruecio nes, dedicadas a ejecutar una tarea, Debido a esto, aparece el concepto de fiujo de ejecuci 6r de un programa, el cual se define como el orden que siguen dichas sentencias durante 1a ejecucién del programa. A primera vista, el flujo de ejecucién de un programa deberfa ser el orden en el cual s escriben las instrucciones sobre el papel. Sin embargo esta forma de pensar impone serias limitaciones. Es habitual, por ejemplo, que ciertas partes del cédigo sdlo se ejecuten si sé cumplen determinadas condiciones. A su vez ciertas tareas repetitivas resultan mas cémoda: de redactar si uno se limita a transcribir la tarea una sola vez, indicando ademas el mimer: de veces que es necesario repetir dicha tarea. Una manera més formal de expresar lo anterior implica agrupar los posibles flujos 4 ejecucién de un programa en una serie de patrones o estructuras de programacién, Cada uné de estas estructuras de programacién se comporta exteriormente como una sentencia nic de forma que pueda ser concatenadas dentro de otras estructuras y asi componer el flujo dé ejecucion de un programa completo, Estas estructuras de programacién son independien: tes del lenguaje conereto que se esté utilizando, siendo aplicables a cualquier lenguaje de programacién existente en la actualidad. Los tipos de estructuras de programacién que existen son los siguientes: = Secuencia: constituida por 0, 1 oN’ sentencias que se ejecutan segiin el orden en que han sido escritas. Es la estructura mas simple y la pieza mas bésica a la hora de com: poner estructuras, # Selecei6n: consta de una sentencia especial de decisién y de un conjunto de secuencia: de instrucciones. La sentencia de decisién genera un resultado delimitado dentro de un rango preseleccionado (generalmente verdadero o falso) y, dependiendo del resultado obtenido, se ejecutard una de las secuencias de instrucciones. Pueden existir tantas secuencias de instrucciones como valores posibles del rango de decisién. ® Tteraci6n: consta de una sentencia especial de decisién y de una secuencia de instruc ciones. La sentencia de decisién s6lo genera dos tipos de resultado (verdadero o falso) La secuencia de instrucciones se ejecutard de forma iterativa mientras que la sentencia de decisiGn genere el resultado correcto, en caso contrario finalizara la ejecucion de li estructura de iteracién. La Figura 5.1 incluye un diagrama de flujo de ejemplo para cada uno de los posibles tipos de estructuras, donde C representa una sentencia de decisién (cuyo valor podré se verdadero 0 falso) y Si representa la secuencia a ejecutar. Enel lenguaje C una sentencia simple debe finalizar con un ; para asi identificarla como una tinica sentencia, Asi mismo el lenguaje C considera que toda senteneia, finalizada con +, constituye de por sf una secuencia de instrucciones con una sola sentencia. Por ejemplo 5.1. Introduccion 117 constituye una secuencia de instrucciones con una sola sentencia Pa fate yerdadere serdaere s st Secuencia Seecein teraction Figura 5.1 Ejemplos de los distintos tipos de estructuras de programacién Si se pretende generar secuencias de mas de una sentencia es necesario agrupar entre delimitadores las sentencias que la componen; para ello se utilizan los delimitadores ty }*. Asf de esta forma, la expresion: constituye una secuencia de instrucciones compuesta por dos sentencias. Advertencia 5.1 Secuencias de instrucciones vactas En el lenguaje C es posible definir secuencias de instrucciones vac fas. La forma mas fécil de imaginarlas es utilizar los delimitadores °{? y °)’ sin que incluyan ninguna sentencia. De esta forma la expresi6n: } define una secuencia de instrucciones vacfa. Sin embargo, hay otra forma menos obvia y més problemdtica de definir una secuen- cia de instrucciones vacfa. Como se ha comentado anteriormente, una sentencia, finalizada con ";’, constituye de por si una secuencia de instrucciones con una sola sentencia. De esta forma, si se declara un *;’ sin una sentencia que lo preceda, este simbolo, por si mismo, constituira una secuencia de instrucciones vacia. Por ejemplo la expresi6n: contador = 0; estard formada por dos secuencias de instrueciones, la primera estaré compuesta por una sola sentencia, mientras que la segunda constituird una secuencia de instrucciones vacia. Esta tiltima forma de definir secuencias vacias suele presentar problemas al inte- 118 El lenguaje de programacién C: diseno e implementacion de programas ractuar con las sentencias de control que se verdn a continuacién. Por ello es important entender bien cémo funciona para no Hevarse sorpresas a la hora de escribir los progra- mas. l i A continuacién se expondrin las diferentes sentencias que el lenguaje C le brinda parg implementar los diferentes tipos de estructuras de programacién. 5.2 SENTENCIA if La sentencia jf, propia del lenguaje C permite implementar una estructura de tipo selecei én, es decir, permite decidir qué secuencia de cédigo se va a ejecutar a continuaci6n, La forma general de redactar una sentencia jf es la siguiente: if (expres El funcionamiento de la sentencia é es el siguiente: ® Si la expresién correspondiente al if devuelve un valor verdadero (representado por un valor numérico distinto de cero, generalmente, el uno), se ejecutaré Ia secuencia de instrucciones subsiguiente. = Si la expresidn correspondiente al if devuelve un valor falso (representado por un valor numérico igual a cero), Ja sentencia if finalizard y se ejecutard la sentencia siguiente. La expresién asociada al if debe ir encerrada entre paréntesis para distinguirla del resto del cédigo. La secuencia de instrucciones deberd estar formada tal y como se explicd al comienzo del capitulo, EI diagrama de flujo de la sentencia + est reflejado en la Figura 5.2. verdadero falso Figura 5.2 Diagrama de flujo de Ia sentencia 17 Por ejemplo la siguiente sentencia 17 if (0 == contador) 5.2. Sentenciair 119 f ("ET tedor estd vacio\n" muestra por pantalla la frase E] contador esté vacto siy s6lo siel valor de la variable contador es igual a 0. Por contra la siguiente sentencia: contador comprueba que el valor de la variable contador sea mayor que cero, y, en caso afirmativo, muestra por pantalla la frase £1 contad variable contador a cero. no est ©. Vaciandole e iguala la Consejo de Programacion 5.1 Utilice siempre secuencias delimitadas entre llaves Como se ha explicado anteriormente, la seniencia 17 acepta cualquier tipo de secuencias de ins- trucciones como parte de su estructura. Esto quiere decir que si la secuencia s6lo dispone de una sentencia se puede prescindir de delimitarla entre Haves, ya que el lenguaje C considera cualquier sentencia terminada en ";* como una secuencia de instrucciones completa. Sin embargo prescindir de las Haves a la hora de usar la sentencia if es una prictica poco aconseja- ble, dado que suele dar lugar a errores de codificacién diffciles de detectar y que se producen sobre todo cuando se modifica el eddigo con posterioridad, Tomemos como ejemplo el siguiente eédigo: it printé (" 4 vacfo\n") Este cédigo muestra por pantalla la frase “El contador est vacfo” si se cumple la condici6n de que el valor de la variable cont ador sea igual a0. Si en una revisin posterior del cédigo se pretende que, cada vez que la variable contedor Hegue a cero, ésta se inicie a un valor maximo predeterminado. Podria ocurrir que el programador, de forma descuidada, escribiera lo siguiente: contador Este e6digo. aun siendo totalmente valido, no realiza la tarea para la cual se disenié. La secuencia que se ejecuta cuando la variable contador es igual a cero esté compuesta tinicamente por la sentencia printf, mientras que la sentencia contadar = MAX.CONTADOR constituye la sentencia posterior a la ejecucién del if y se ejecutard sea cual sea el valor de contador. Para que el cédigo realice la tarea encomendada es necesario delimitar la secuencia deseada de instrucciones, entre Haves, de la siguiente forma: if De esta manera la dos sentencias slo se ejecutaran en caso de que la variable contador sea igual a0. Este tipo de problema aparece por suponer que el e6digo no va a ser modificado con posterioridad. La experiencia advierte que la modificacién posterior del cédigo es la norma y no la excepeién. Por tanto es recomendable adecuar las sentencias 17 para que acepten sin problemas cualquier modificacin en su conjunto de sentencias. Lo que implica la utilizacin de las Haves en todo momento, aunque la secuencia de instrucciones se reduzca a una sola sentencia 120 El lenguaje de programacién C: diseiio e implementacién de programas Advertencia 5.2 Cuidado con no incluir un *;' junto ala sentencia if Cuando un programador se acostumbra a escribir programas en lenguaje C, tiende a fi- nalizar todas sus Iineas de cédigo con un *;’, Esto no es correcto en todos los casos. Supéngase que se pretende escribir un cédigo en el que se asigna un valor predetermina- do ala variable contador en el momento que el valor de esta variable sea igual a cero. Un programador versado en el lenguaje C podria, en un momento dado, escribir lo siguiente: | if (0 contador) contador = MAX_CONTADOR; | Este cédigo, a pesar de ser valido, no realiza correctamente la funcién para la cual fue disefiado. Para darse cuenta del fiujo de ejecucién real de este cédigo conviene recordar el concepto de secuencia de instrucciones vacia tratado en la Advertencia 5.1. Una forma | de ver con més facilidad el funcionamiento real de este c6digo seria redactarlo de forma mis acorde con su ejecucién real, tal y como se expone a continuacién. if (0 = contador contador = MAX_CONTADOR: El compilador de C, una vez procesada Ia expresién (0 == contador) espera encontrar la secuencia de instrucciones a realizar en caso de que la expresién sea verdadera. Al | encontrar un °;’ sin ninguna sentencia anterior, el compilador supone que la secuencia de instrucciones a realizar est4 compuesta por una secuencia vacia, la cual serd la que ejecute en caso de que la expresién sea verdadera. La sentencia contador = MAX.CONTADOR; seré considerada como la primera sentencia posterior al if y seré ejecutada sea cual sea el valor de la variable contador. La forma correcta de codificar la tarea que se pretende seria la siguiente: f (0 contador) contador = MAX_CONTADOR; De esta forma se asignard el valor correspondiente a la variable contador si y solo si la variable contador es igual a cero. | Esta misma advertencia vale para todas las estructuras de control. | ‘A continuacién se incluyen un par de programas de ejemplo de uso de la sentencia if. El Programa 5.1 lee del teclado un mimero entero y muestra por pantalla un mensaje en el caso de que ese niimero sea par. Programa 5.1 Programa que lee wt mimero e indica si es par nciude <5 5.2. Sentenciait 121 el nimero printf (*Introduzca un ndmero gnunerc numero) El programa se puede desglosar de la forma siguiente: Hnelude Lo primero que hace es incluir el archivo stdio.h para poder utilizar las funciones #y scant. Después declara la cabecera de la funcidn main que constituye el cuerpo de cualquier programa en C. Por diltimo declara una variable de tipo entero y de nombre numero, prin roduzca un na Sd", &numero) ; Lo siguiente es conseguir del usuario el ntimero a comprobar. Para ello muestra un mensaje, utilizando la funcién pri r por la pantalla y asi indicar al usuario que debe introducir el ntimero. A continuaci6n, utiliza la funcién scan para leer dicho numero y almacenarlo en la variable nimero umero % 2 Elon Ss par.\n jumero) ; Por tiltimo se ejecuta la sentencia jf. El primer paso consiste en evaluar la expresién; dicha expresién est4 compuesta por dos operaciones. En primer lugar se calcula el resto de dividir Ia variable numero entre 2, utilizando el operador de médulo. Después se comprueba dicho resto es igual a cero. En caso afirmativo, la expresién devolverd un resultado verdadero (expresado en C por un valor numérico distinto de cero, generalmente el uno) y . por lo tanto, la sentencia if ejecutard la secuencia de instrucciones correspondiente (la cual mostraré por pantalla um mensaje indicando que dicho mimero es par) antes de finalizar la sentencia {# y con ella el programa En caso contrario la expresién devolverd un resultado falso (expresado en C como un valor numérico igual a cero) y la sentencia # f terminar: finalizando el programa, 122 El lenguaje de programacién C: disefio e implementacién de programas Observe que la secuencia de instrucciones correspondiente al i no va encerrada en- tre llaves. Esto es posible dado que dicha secuencia est compuesta por una sola sentencia finalizada con un *:’. En el momento en el que se quisiera incluir en la secuencia mas de una sentencia, serfa necesario delimitar por medio de Haves la secuencia completa, Se reco- mienda encarecidamente no usar en ningtin caso secuencias de instrucciones que no estén encerradas entre Haves, aunque solo estén compuestas por una sola sentencia, con vistas a facilitar futuras modificaciones del e6digo. Para més informacién consulte el Consejo de programacién 5.1, El siguiente ejemplo tiene como objetivo leer un ntimero de teclado y elevarlo al cua- drado solo si es par. El c6digo correspondiente esta recopilado en el Programa 5.2 Programa 5.2 Programa que lee wn niimero y lo eleva al cuadrado si es par nt main(void ntroduzca ut . id", &numero): numero vt numero * numer adrad cuadrado printf ("E ta return(0); La primera parte del eédigo es idéntica a la del ejemplo anterior, por lo que no se entraré a discutirla en profundidad. Tan solo destacar el hecho de declarar una variable més ‘ado, para almacenar el resultado de la operacién elevar de tipo entero, denominada cuadr al cuadrado. Los cambios principales se producen en la sentencia 4, la cual reza como sigue: #0 1 cuadrad print ("E1 cuadrado de td es * numero «numero, cuadrado) : La sentencia ‘ f incluye la misma expresin que en el ejemplo anterior. El resultado de dicha expresion serd verdadero si y solo si el valor de la variable numero es par, en cuyo caso se ejecutaria la secuencia de instrucciones del 1+; en caso contrario la sentencia 7 finalizaré sin haber ejecutado dicha secuencia. 5.3. Sentencia if-2!se 123 La principal diferencia con el ejemplo anterior radica en la secuencia de instrucciones propia del i* que esta compuesta por més de una sentencia. En este caso la secuencia debe ir encerrada entre llaves, en caso contrario la sentencia if solo reconoceré como secuencia propia la primera de las sentencias Consejo de Programacién 5.2 Evite confirsiones entre asignaciones e igualdades en las expre= stones condicionales En general, las expresiones que gobiernan el flujo de las sentencias de control suelen ser expresiones condicionales, y es frecuente que dichas expresiones condicionales realicen una comparacién entre un valor constante y una variable. Tomemos como ejemplo la siguiente sentencia i fz Esta sentencia ejecuta la secuencia del ‘ f cuando el valor de Ia variable contador es igual a cero, en ese caso el resultado de Ia comparacién sera verdadero, o lo que es lo mismo, distinto de cero. Si por alguno razén, el programador comete un error y se olvida de escribir un *=", la sentencia quedaria como sigue: En este caso la expresin del 1 esté compuesta por Ia asignacién de un valor constante a una Variable, El resultado de dicha expresién serd el valor final de la variable. De esta forma la secuencia del +f se ejecuta si y solo si el valor que se asigna a dicha variable es distinto de cero, En este caso el valor es cero, por lo que dlicha secuencia no se ejecutaré nunca. ‘Como se acaba de observar, el hecho de no incluir uno de los ’=" del operador de igualdad implica un cambio total en la ejecuci6n del programa. En este caso no solo la condicién es totalmente distinta, sino que ademis la variable contadcr se ve modificada de forma imprevista Una forma de evitar este comportamiento indeseado consiste en invertir el orden de los operands, © sea, situar primero el valor constante y después la variable, de la siguiente forma: (0 = contador) El significado es el mismo, pero de esta forma si se olvida de incluir un el cédigo quedarfa como De esta forma la expresisn del °F se convierte en una asignacign de una variable a un valor constante. Esta asignaci6n es imposible por lo que el compilador generar un mensaje de error, Asi se evita que un error, potencialmente muy peligroso, pase desapercibido. Esta forma de redactar las expresiones condicionales es la que se ha seguido a lo largo del Capitulo. Si se acostumbra a codificar de esta forma evitard incluir este tipo de errores en el cédigo y se ahorrard muchos quebraderos de cabeza. 33 SENTENCIA if-else La sentencia {f-e1se es una forma ampliada de Ia sentencia if, por lo tanto forma parte también de las estructuras de seleccién y todo lo dicho anteriormente para la sentencia {f 124 — Ellenguaje de programacién C: disefio e implementacién de programas también se aplica aqui. La sentencia i7-e1se permite seleccionar entre dos secuencias Gistintas de instrucciones. La forma general de redactar una sentencia 1 -e1se es la siguiente: El funcionamiento de la sentencia if-e1s¢ es el siguiente: » Si la expresin devuelve un valor verdadero (representado por un valor numérico dis tinto de cero), se ejecutard la secuencia de instrucciones situada a continuacién del 17 (secuencia de instrucciones 1). = Sila expresién devuelve un valor falso (representado por un valor numérico igual a cero), s¢ ejecutard la secuencia de instrucciones situada a continuacién del else (se- cuencia de instrucciones 2). La expresién debe ir encerrada entre paréntesis para distinguirla del resto del cédigo. Las secuencias de instrucciones deberdn estar formadas tal y como se explicé al comienzo del capitulo. El diagrama de flujo de la sentencia ‘f-e1se esté reflejado en la Figura 5.3. falso verdadero expresiéa '= 0 cuencia 2 Secuencia 1 Figura 5.3 Diagrama de flujo de la sentencia 1#-else ‘Tomemos como ejemplo la siguiente sentencia if-e1se 0 == contador) "El contador esta ador no esta vac Esta sentencia muestra por pantalla la frase £1 contador esté vacfosiy solo siel valor de la variable contador es igual a 0. En cualquier otro caso muestra por pantalla la frase “El contador no esté vacfo”. 5.3. Sentencia if-else 125 Advertencia 5.3 Relacién entre la sentencia i f-e]se y el operador condicional En el Capitulo 3 se mostré el funcionamiento del operador condicional. Este operador trabaja de forma parecida a la sentencia i #-e1se pero con la ventaja de poder ser incluido como parte de una expresién. Como ejemplo tomemos el siguiente cédigo que asigna a | una variable un valor dependiendo de si su valor original es par o no. (numero 5-1 = (numero Esta segunda forma resulta mas compacta aunque menos legible. En general se recomien- da no utilizar el operador condicional a no ser que sea necesario, debido a que complica mucho la legibilidad del cédigo. Las sentencias 1f-2]se (como el resto de sentencias) se pueden combinar entre si de muchas formas. Esto permite ejecutar la combinacidn correcta de secuencias partiendo de los datos que existén en ese momento. Una forma habitual de combinar las sentencias sé es aquella que permite elegir entre mis de dos secuencias dependiendo del valor variable. Por ejemplo el siguiente cédigo: muestra por pantalla la frase “E] contador esta vacio” si el valor de Ja variable contador es igual a 0. En cualquier otro caso ejecuta otra sentencia if la cual muestra por pantalla la frase “El contador es mayor que cero” en caso que el valor de la variable contador sea mayor que cero y en cualquier otro caso muestra por pantalla la frase “El contador es menor que cero”. De esta forma se ejecutan tres secuencias de instrucciones distintas. La primera si el valor de contador es igual a cero, la segunda si el valor de contador es mayor que cero y la tercera si el valor de contador es menor que cero. El diagrama de flujo del i# anidado anterior se muestra en la Figura 5.4. Consejo de Programacién 5.3 Mejorar la legibilidad de los if -21se coneatenados Es muy habitual codificar varias sentencias 7*-e) Se juntas para ejecutar una u otra secuencia de- pendiendo del valor de una variable o cuando las expresiones a comparar son excluyentes entre si. 126 EI lenguaje de programacién C: disefio e implementacién de programas fatso verdadero {also verdadero Figura 5.4 Diagrama de flujo de la sentencia 1 anidada En ese caso la forma més clara de redactar dichas sentencias seria la siguiente: EI funcionamiento es evidente. Si la expresién 1 es verdadera se ejecuta la secuencia del {f com- puesta por las sentencias encerradas entre Haves. En caso contrario se ejecuta la secuencia del ese ‘compuesta por una tinica sentencia if (por eso no es necesario que vaya entre Hlaves). AL ejecutar el segundo + se comprueba la expresién 2, si es verdadera se ejecuta la secuencia del + compuesta por las sentencias encerradas entre Haves. En caso contrario se ejecuta la secuencia del 1 52 compuesta por Jas sentencias encerradas entre Haves. Para el caso de seleccionar entre mas de tres secuencias se procederia de forma aniloga, afiadiendo las sentencias 1 que se necesiten, ‘A continuacién se muestra el Programa 5.3 como ejemplo de uso de la sentencia + f-21s2, El ejemplo comprende una versiGn preliminar de la Agenda electronica que rea- liza la funcién de determinar si un aio es bisiesto! 0 no. Up afto es bisiesto cuando es matltiplo de 4, y no es miltiplo de 100, siempre y cuando no sea méiltiplo de 400 en cuyo caso si es bisiesto. 5.3. Sentencia if-else 127 Programa 5.3 Agenda: Indica si un arto es bisiesto - Programa: Agenda * Deseripcién- Médulo que contiene 1a funeién de infcio del programa +) include * + : main ros entrada: no tiene * 0s salida: no tiene ¥ Lee un aflo e indica st es bisiesto. int main int anyo char printf("Hola, soy su agenda electronica\n”); printf("Pulse una tecla para ver un ejemplo\n "Be" atecla); scanf erminal es bis el uso de la printf("\ndQue afio quiere sa scanf("Sd" Banyo): bisiesto\n" ,anyo); printf("el afilo 2d no es bisiesto\n™,anyo); | else if (0 printf("el afto & es bisiesto\n" ,anyo); afio Sd no es bistesto\n nyo): Este programa define un par de variables (anya y tecl2, que luego se utilizarén en el programa principal). La primera linea que ejecuta es la de la funeién man. "Hola, soy su agenda electronica\n*): El lenguaje de programacién C: disefio e implementacién de programas Estas tres lineas se limitan a mostrar un mensaje de presentacién y esperar a.que se pres ‘una tecla antes de continuar. jone @ aflo quiere n* any ano Antes de seguir adelante, es necesario recordar que un afio se considera bisiesto si es miiltiplo de cuatro y no es miiltiplo de 100, a no ser que sea miltiplo de 400 en cuyo caso si que seria bisiesto. Estas son las principales Iineas del eddigo. Primeramente, con las funciones print? y scanf, se solicita que el usuario introduzca el afio a comprobar, y se espera a que sea introducido, A continuacién se ejecuta lo primera sentencia i #-21 se. La expresién correspondiente comprueba si el afio es miltiplo de 100. Recuerde que un aiio es miltiplo de 100 si el resto de dividirlo entre 100 es cero. Si esta comprobacién es verdadera se ejecuta una nueva sentencia if donde se com- prueba si el afio es miiltiplo de 400. En caso afirmativo el afio seria bisiesto. En otro caso el allo no seria bisiesto, Sila comprobacién del primer if resulta falsa se ejecuta su correspondiente else, el cual se compone de una tinica sentencia if. Esta sentencia i? comprueba que el afio sea 0 no miiltiplo de 4. En caso afirmativo el afio seria bisiesto. En otro caso el aiio no seria bisiesto. Esta descomposicién de problema genera 4 posibles respuestas. Dichas respuestas. de forma resumida serfan las siguientes. Si el aiio es miltiplo de 100 y de 400 entonces es bisiesto. Si el aifo es miltiplo de 100 pero no de 400 entonces no es bisiesto. Sil aiio no es miiltiplo de 100 pero si de 4 entonces es bisiesto. Sil aiio no es miltiplo de 100 ni tampoco de 4 entonces no es bisiesto. La combinacién de las cuatro respuestas anteriores componen el mismo conjunto de respuestas que el correspondiente a la definicién de aio bisiesto redactada anteriormente. 5.4, Sentencia white 129 Por tiltimo, en caso que el afio sea bisiesto. una sentencia printf lo mostrard por pantalla y en caso de que el afio no sea bisiesto, otra sentencia print? hard lo propio. 4 SENTENCIA while La sentencia whi ]¢ forma parte de las estructuras de iteracién. Su funcién consiste en eje- cutar un mimero determinado de veces una secuencia de instrucciones determinada, La forma general de redactar una sentencia whi 1¢ es la siguiente: instrucciones El funcionamiento de la sentencia while es el siguiente: = Mientras que la expresién devuelva un valor verdadero (representado por un valor numérico distinto de cero). se ejecutarg repetidamente la secuencia de instrucciones, evaluando nuevamente la expresién en cada iteracién. # Si la expresién devuelve un valor falso (representado por un valor numérico igual a cero), finalizaré la ejecucién de la sentencia wh’ Te. La expresién asociada al wh )2 debe ir encerrada entre paréntesis para distinguirla del resto del c6digo. La secuencia de instrucciones deberd estar formada tal y como se explicé al comienzo del capitulo. El diagrama de flujo de la sentencia wh7 |e est reflejado en la Figura 5.5. falso exprecién I= 0 verdadero Secuencia Figura 5.5 Diagrama de flujo de la sentencia while Por ejemplo la siguiente sentencia whi le: whi] decrementa la variable contador en una unidad tantas veces como sea necesario hasta que el valor de la variable contador sea igual a cero. 130 Consejo de Programacion 5.4 Utilice siempre expresiones explicitas en las sentencias de control Como se explica en el Capitulo 4, las expresiones booleanas se evalvian como valores numéricos, de forma que un valor igual a cero indica que la expresién es falsa, mientras que un valor distinto de cero indica que la expresi6n es verdadera. Imaginemos que se pretende realizar un bucle determinado mientras que la variable co distinta de cero, un programador avispado podria escribir lo siguiente: dor sea while (con Esta soluciGn es perfectamente vélida, mientras que la variable sea distinta de cero, la expresi6n se evaluard como distinta de cero y. por lo tanto, como verdadera. En el momento en el que la variable sea igual a cero, la expresiGn se evaluard como igual a cero, 0 sea, como falsa, y la sentencia wii le terminaré. A pesar de ser valida, esta solucién no es nada clara y puede conducir a engafios cuando se revise el cédigo con posterioridad. Por ello es recomendable utilizar expresiones explicitas como la siguiente: do El lenguaje de programacién C: disefio e implementacién de programas | whi De esta forma Ia condicién que rige el bucle est claramente expresada, evitando posibles malen- tendidos. Por lo tanto se recomienda que la expresi6n sea una expresién booleana, bien por que sea una variable que se considere booleana (valor 0 0 | exclusivamente), bien por ser una expresi6n condicional. EI Programa 5.4 constituye un ejemplo de uso de la sentencia whi 1. Consiste en un cédigo que calcula, para un niimero N dado, el sumatorio de todos los ntimeros desde 1 hasta V 7" Programa 5.4 Ejemplo: Calewlo del sumatorio desde I hasta N td. suma) : 8.5. Sentencia for 181 El comienzo del programa es muy similar al del Programa 5.2. Tan solo destacar que declara una variable de tipo entero, denominada suma, para almacenar el resultado del su- matorio, y la inicia a cero. La distincién se produce en la sentencia whi | 2 posterior, la cual reza como sigue: white (0 < numero) | uma a+ ume! prin 4N es Bd. \nt Suma}: La ejecucisn de la sentencia whi 1e comienza evaluando la expresién. (numero menor que cero), la sentencia whi 1¢ finalizard al instante, En caso contrario se ejecutard la secuencia propia del hie. Esta secuencia incrementaré el valor de la variable sume con el valor actual de numero y después decrementard en uno el valor de numero Una vez terminada la secuencia se volverd a ejecutar la sentencia whi] comenzando por evaluar de nuevo la expresién. En resumen esta sentencia while se ocupard de afiadir el valor actual de numero al sumatorio total y de decrementar dicha variable, tantas veces como sea necesario, hasta que el valor de numero sea menor que cero. Una vez terminado el bucle. la sentencia print posterior se encargara de mostrar por pantalla la suma total. En este ejemplo se ve claramente que Ja sentencia wi iT primero comprueba la ex- presién y después ejecuta la secuencia, De esta forma la ejecucién de una sentencia whi le puede realizar desde cero hasta NV iteraciones. LY si quiero programar un bucle infinito? Pues es sencillo, basta con escribir en la condicién de control del bucle algo que siempre se cumpla. Por ejemplo: lta ser falsa {.Qué hace el e6digo de este ejemplo? ;No hace nada! Y sirve para eso, para no hacer i nada, Un programa como este es el que ejecutan los computadores cuando no tienen nada que hacer (que es casi siempre). Como Ia UCP no para, sigue ejecutando un bucle vacio, denominado ‘d7e, ¢Cémo se sale del bucle infinito? Mediante interrupciones, pero esa es otra historia, } | 5.5 SENTENCIA for | La sentencia for forma parte también de las estructuras de iteracién. Su funcién consiste, | por tanto, en ejecutar un ntimero determinado de veces, una secuencia de instrucciones | determinada. i La forma general de redactar una sentencia for es a siguiente: | 132 El lenguaje de programacién C: diseno e implementacién de programas El funcionamiento de la sentencia for es el siguiente: = Primera vez que se ejecuta la sentencia for # Se ejecuta la expresién n° | Se evaltia la expresiGn n° 2 y se compara el resultado. % Siel resultado es verdadero se ejecuta la secuencia del for y se vuelve a empezar la sentencia completa 4 Siel resultado es falso, finaliza la ejecucién de la sentencia. = Segunda y sucesivas veces que se ejecuta la sentencia For: # Se ejecuta la expresién n° 3. @ Se evaltia la expresién n° 2 y se compara el resultado. % Si el resultado es verdadero se ejecuta 1a secuencia del for y se vuelve a empezar la sentencia completa Siel resultado es falso, finaliza la ejecucién de la sentencia. Las tres expresiones deben ir separadas entre sf por ':’ y el conjunto de dichas ex- presiones debe estar encerrado entre paréntesis, para distinguirlo del resto del e6digo. La secuencia de instrucciones deberd estar formada tal y como se explicé al comienzo del Capitulo. El diagrama de flujo de la sentencia for esté reflejado en Ia Figura 5.6. expresién 1 ako verdadero Secuencia expracion 3 Figura 5.6 Diagrama de flujo de la sentencia # Probablemente, la mejor forma de entender como funciona una sentencia far es redac- tar un cédigo que realice la misma tarea utilizando como base Ia sentencia wi‘ Te, mucho mis facil de entender. Dicho cédigo equivalente seria el siguiente: 5.5. Sentencia for 133, iones Este ejemplo, ademas, lentes entre si. Esto implica que la utilizacién de una w otra depende, casi en e3 los criterios de disefio que tenga el programador. justra el hecho de que todas las sentencias de iteracién son equiva- clusiva, de Por ejemplo, para redactar un programa que realice una determinada tarea un ntimero N de veces, habria que utilizar la siguiente sentencia for: contado Conviene desglosar el funcionamiento de este ejemplo en varios pasos para entender com- pletamente el funcionamiento de la sentencia for: = Primera vez que se ejecuta la sentencia for @ Se ejecuta la expresion n° 1 (contador = 1). De esta forma se inicia el valor de Ja variable contador a 1 Se evaltia la expresién n° 2(\\ >= con % Si el resultado es verdadero (contador menor o igual que N) se ejecuta la secuencia del for y se vuelve a empezar la sentencia completa. % Siel resultado es falso, finaliza la ejecucién de la sentencia. = Segunda y sucesivas veces que se ejecuta la sentencia for: © Se ejecuta la expresion n° 3 (contador - contador +1), Asf se inerementa en 1 el valor de la variable contador. © Se evaltia la expresion n° 2 (i >= contador) y se compara el resultado. % Si el resultado es verdadero (contador menor o igual que N) se ejecuta la secuencia del for y se vuelve a empezar la sentencia completa. + Siel resultado es falso, finaliza la ejecucién de la sentencia ador) y se compara el resultado. En definitiva, este ejemplo permite ejecutar una secuencia un ntimero N de veces, uti- lizando la variable contador como indice para conocer el mimero de iteracién. Esta es la forma de uso més frecuente de esta sentencia. Advertencia 5.4 Urilizacién del operador ’; en las expresiones del for Como se ha visto anteriormente, la sentencia for permite ejecutar diversas expresiones, dependiendo de cual sea el niimero de iteracién actual. Estas expresiones pueden abarcar cualquier sentencia imaginable en C. Lo tinico que no permite es la ejecucién de una 134 El lenguaje de programacién C: disefo e implementacién de programas secuencia que incluya més de una sentencia, Sin embargo si usted se dedica a observar programas existentes escritos en C podria encontrarse con lo siguiente: int X.Y; :X=kH for (X= 0, Y= 03 ¢ Esta sentencia for inicia dos variables (Xe ¥) la primera vez que se ejecuta y por cada iteracién las incrementa a las dos, finalizando cuando el valor de las dos sea mayor que N. A primera vista puede parecer que las expresiones 2 y 3 de la sentencia for estén compuestas por secuencias de instrueciones de dos sentencias separadas por ',’. Sin em- bargo las dos son expresiones puras. Para entenderlo hay que recordar que una expresién puede estar compuesta por dos més expresiones relacionadas con un operador, el cual genera un resultado comin. En este caso se utiliza el operador *, el cual funciona ejecutando las dos expresiones asociadas a ély devolviendo como resultado el resultado de la segunda expresion. Veamos, por ejemplo, la expresin X = 0, Y = 0, las dos expresiones que la com- ponen son asignaciones simples. El operador ’,’ ejecuta cada una de las dos expresiones y devuelve el resultado de la segunda (el resultado de una asignaciGn es el propio valor de Ta asignacién). Esta practica no es muy recomendable, ya que complica en exceso la comprensindel cédigo, siendo en estos casos més practico el uso de una sentencia wile. En cualquier caso conviene conocer su existencia por si aparece en alguna revisidn de cédigo ajeno. El Programa 5.5, cuya funcién es mostrar por pantalla una cuenta atrés, es un ejemplo sencillo pero que ilustra a la perfeccién el uso de la sentencia for y su utilidad a la hora de realizar recorridos a través de un rango de nimeros, donde las iteraciones necesitan disponer del mimero de iteracién actual, Programa 5.5 Ejemplo: muestra la cuenta atrds desde un niimero N 5.5. Sentencia for 135 = ind Las primeras dos sentencias del programa, solicitan de! usuario el ntimero desde el cual la cuenta atrés. A continuacién se indica por pantalla que va a comenzar la cuenta atras. La siguiente es la sentencia fo ica = numero: @ = in cuya estructura es como sigue: ndice i ed\n" indice En Ia primera iteracién se inicia la variable indice al valor de numero. Después se com- prueba que indice no sea menor que cero, (en cuyo caso finalizarfa el For). Si se cumple la condicién se ejecuta la secuencia del for, mostrando por pantalla el valor de indice. Una vez terminada, se volverd a ejecutar la sentencia for. En las restantes iteraciones, primero se resta | a la variable indice. Despu' prueba que indice no sea menor que cero. En caso afirmativo se muestra por pantalla el valor de indice y se repite la sentencia for. En caso contrario finaliza la sentencia for. La titima sentencia se encarga de indicar por pantalla el final de la cuenta atras, e com= Advertencia 5.5 Complejidad en las expresiones del for Tal y como se deduce de la definicién, las expresiones que componen la sentencia for pueden ser tan complejas como se quiera, si bien resulta recomendable utilizar solo ex- presiones simples y féciles de entender. Como ejemplo valga el siguiente troz0 de cédigo que realiza, a peticién del usuario, una cuenta hacia adelante o una cuenta hacia atras: printf (*0-> acia delante; 1-> Cuenta hacia atrds:\n") scanf (*%d* for (i printf ) && (10 < i): (0 = sentido) 2 i++: T- Primeramente se solicita al usuario el sentido de la cuenta y se guarda en la variable | sentido. Después se inicia el bucle for. La primera vez, se inicia la variable i a cero y | después se comprueba que sit valor esté comprendido entre 10 y —10. Como el resultado ¢s afirmativo se muestra su valor y se realiza una segunda iteracién. A partir de entonces en cada iteracién que se realice lo primero que se ejecuta es la tercera expresidn. Esta expresiOn esté compuesta por un operador condicional, el cual comprueba el valor de la variable sentido y, si si valor es cero, incrementa el valor de la variable i. En caso { 136 — El lenguaje de programacin C: diserio e impfementacion de programas contrario, decrementa el valor de la variable 1. Después se comprueba que el valor de la | variable i esté comprendido entre 10 y —10. Si el resultado es afirmativo se muestra su | valor y se realiza otra iteracién. En otro caso termina la sentencia for. El resultado final | sera una cuenta de 0.29 ode 0a —9 segiin decida el usuario. Como se puede comprobar en este ejemplo, la complejidad de las expresiones del For no tiene limite, pero esto es a costa de dificultar la legibilidad del eédigo, por lo que no se recomienda esta préctica en absoluto. 5.6 SENTENCIA do-while La sentencia do-wh Te forma parte también de las estructuras de iteraci6n. Su funci6n con- siste, por tanto, en ejecutar un ntimero determinado de veces, una secuencia de instrucciones determinada, La forma general de redactar una sentencia do-wh ile es la siguiente: do encia de ins: while (exprestén); El funcionamiento de la sentencia do-whi]e es el siguiente: rucciones = Primeramente s¢ ejecuta la secuencia de instrucciones. = Después se ejecuta la expresién y se comprueba su resultado. Si es verdadero se repite laejecucién de la sentencia. Si es falso, finaliza dicha ejecucién. La expresién debe ir encerrada entre paréntesis para distinguirla del resto del cédigo. La secuencia de instrucciones deberd estar formada tal y como se explicé al comiehzo del capitulo. El diagrama de flujo de la sentencia do- whi Je esta reflejado en la Figura 5.7. Secuencia verdadero expreaion |= 0 falso ‘igura 8.7 Diagrama de flujo de la sentencia do- white Observe que la ejecucién de una sentencia do-whi le obliga a entrar dentro del bucle al menos una vez. También es posible convertir la sentencia do -whi le a.una sentencia while, 6.6, Sentencia do-wniie 137 basta con repetir la secuencia de instrucciones antes de ejecutar el whi ]e, de la siguiente forma nstrucciones én) instrucciones De esta forma se confirma que todas las sentencias de iteracién son equivalentes entre sf Como ejemplo tomaremos el mismo programa que se utiliz6 para la sentencia whi le Dicho programa calcula, dado un ntimero N. el sumatorio desde | hasta V. El Programa 5.6 muestra dicho ejemplo: Programa 5.6 Calculo del sumatorio desde I hasta N nelude nt main(void) { nt numero: ( duzea un mayor que 0): "Is . &numera); dot | suma = suma + numero; numero = num 1 while (0 < numero}; printf resultado de sumar 1+2+...4N es 3d.\n",suma): return(d) El comienzo de este programa es idéntico al del Programa 5.4, Tan solo indicar el cambio en el mensaje producido, indicando que el mtimero debe ser mayor que cero. A partir de ahf se ejecuta la sentencia do-whi le, la cual reza como sigue: do suma numero a + nui } while (0 ¢ numero): printf resul nd La ejecucién de la sentencia 40-wht 1¢ comienza ejecutando la secuencia de instrucciones. Primero incrementa el valor de Ja variable sutra con el valor actual de nunero y después decrementa en uno el valor de numero. A continuacién se evaltia la expresi6n. Si resulta ser falsa (numero menor que cero), la sentencia do- Je finalizard al instante. En caso contrario se volver a ejecutar la senteneia do-whi1e desde el principio. i 138 El lenquaje de programacién C: disefio e implementacién de programas En resumen, esta sentencia do- wii Te se ocupard de afiadir el valor actual de numero al sumatorio total y de decrementar dicha variable, tantas veces como sea necesario hasta que el valor de numero sea menor que cero, Una vez. terminado el bucle, la sentencia printf posterior se encargardi de mostrar por pantalla la suma total. La Figura 5.8 muestra la parte del bucle que se coresponde con sentencias y la sentencia booleana que controla el bucle. secuencia de inetrucciones expresion booleana Figura 5.8 Estructuracién del eddigo en el bucle do-wh! le Este cédigo funciona de forma correcta siempre que el ntimero introducido sea mayor que 0. Supongamos por un momento que sé introduce el valor —7. A la hora de ejecu- tar la sentencia do-wh?]@ Jo primero en ser ejecutado es la operacién suma = suma + numero; por lo que el valor de suma pasarfa a ser igual a —7. Una vez que el cédigo lle; gaa la parte wh*1¢ se evahia la expresi6n correspondiente, que seré falsa, terminando la sentencia do-wht le y, posteriormente, el programa. El resultado obtenido seria —7. algo que no concuerda con la funcionalidad supuesta del programa, (El resultado deberia haber sido 0, indicando que no existe un resultado valido.) Esto es asi debido a que la sentencia do-whi Te no realiza una comprobacién de la condicién de salida hasta que no ha ejecutado una vez la secuencia de instrucciones. Si este comportamiento no es el que se espera del cédigo, es mejor utilizar una sentencia wii Te Quiz el ejemplo que mejor aproveche las propiedades espectficas de la sentencia do-wht le es aquel que pretende obtener una entrada del usuario, repitiendo la lectura en caso de error, Como caso particular se expone el Programa 5.7, que implementa el ment principal de la Agenda electrénica mostrada en este libro como estudio de cas Programa 5.7 Agenda: ment principal Ja funcién de inicio del programa a> 5.6. Sentencia do-white 139 Funcién: main * Parémetros entrada: no tiene * Pardmetros salida: no tiene * Descripcién: Muestra el mend de inicio de 1a agenda. int maintvoid) char tecla; int opcion; printf("Hola, soy su agenda electrénica\n"); print#("Pulsa una tecla para ver un ejemplo\n"): scanf("c" Atecla); I * Bucle principal con estructura do-while + do printf("\nElija una opeins\n printf("l.- Entrar en 1a agenda de usuar printf("O.- Salfrin"); scanf("Sd" ,Bopcion * * Sentencta tf-else para seleccionar 1a opcidn dada if (1 == opeion) { printf("Entrar en 1a agenda de usuario \n" else { printfc"Salir \n | whtle (0 t= opeion): La primera parte del programa es idéntica a la que aparece en el Programa 5.3. Las diferencias aparecen a partir de la sentencia do-whi le: do { intf(*\n€lija una opeién:\n"): printf(*l.- Entrar en la agenda de usuario\n"); rintf("O.- Salir\n"): scanf( "$d" gapcion); 140 El lenguaje de programacién : diserio @ implementacién de programas cionar 1a 8 pr pr: while Cop Al tratarse de una sentencia do-wh? 12, primero se ejecuta la sentencia de instruccion asociada, De esta forma las primeras lineas, formadas por sentencias print #, muestran pantalla el siguiente meni: de usuario Sal continuaciGn se lee la opeién correspondiente. Las sentencias if-else posteriores encargan de ejecutar las acciones correspondientes tanto en el caso de Ia agenda individu como para la agenda de grupo. Una vez terminado Io anterior, se comprueba la expresi6n del do-whi le dedicada comprobar si se ha elegido la opcién de salir. En caso afirmativo la sentencia do- ih i Te ter minard y con ella el programa completo. En caso negativo se volverdi a ejecutar la sentenci do-whi Te, volviendo a mostrarse el memi por la pantalla 5.7 SENTENCIA switch La sentencia switch pertenece a las estructuras de tipo seleccién, es decir, permite decidi qué secuencia de cédigo se va a ejecutar a continuacién. En concreto permite elegir de: I hasta V secuencias de cddigo distintas La forma general de redactar una sentencia sw/i es la siguiente: én 5.7. Sentencia switch 141 El funcionamiento de la sentencia switch es el siguiente: = Primeramente se evaltia la expresién del switch. Esta debe dar como resultado un valor entero 0 un caracter (en otro caso se producird un fallo al compilar) = Después el programa empezaré a ejecutar a partir de la sentencia case cuya expresion coineida con el resultado obtenido de la expresi6n del switch. Se ejecutaran todas las sentencias que haya a continuacién hasta encontrar una sentencia break. o se llegue al final de la sentencia switch completa. Si en el camino se encuentran mé estas serdn ignoradas. sentencias = Sino se encuentra ninguna sentencia ca del switch, pueden ocurrir dos ¢ cuya expresién coincida con el resultado © Que no exista una sentencia defau'] t. en cuyo caso finalizard la sentencia switch. © Que exista una sentencia default, en cuyo caso se ejecutardn todas las sentencias que haya a continuacién hasta encontrar una sentencia break, o se Hegue al final de la sentencia switch completa La expresién del switch debe ir encerrada entre paréntesis para distinguirla del resto del c6digo. Las expresiones de los case no necesitan paréntesis pero deben terminar con ”: para distinguirlas del resto del cédigo. Las sentencias son instrucciones independientes, si bien pueden sustituirse por secuencias completas. Advertencia 5.6 No olvide escribir un bloque default Cada switch debe terminar con un default. Esta opcién por defecto permite realizar acciones siempre que no se cumplan los criterios de los case, lo que es muy titil para controlar errores. Veamos un ejemplo: switch (contador) | printf ("opcion n* {Qué pasa si contador no es 1? Es mejor aclarar la seméntica completa con un bloque default y no dejar programas ambiguos. | El diagrama de flujo de la sentencia switch esta reflejado en la Figura 5.9. La utilizacién de la sentencia switch suele ser bastante especifica (en contraposicién con la sentencia i F-27152 cuyo uso es mas genérico), Normalmente se utiliza para elegir la accién a realizar segiin el valor de una variable. Un ejemplo muy evidente del uso de la sentencia si tch consiste en clasificar los me- ses del affo segtin su ntimero de dias. El Programa 5.8 esta basado en la Agenda electrénica, que sirve como estudio de caso en este libro y su funcidn es la de indicar los dias de un mes 142 El lenguaje de programacién C: disefio e implementacion de programas expresion = expresiin 2 = expresiin n Seavencis 1 Seouencia 2 Secuencia n Figura 5.9 Diagrama de flujo de la sentencia switch dado, suponiendo que el afio no es bisiesto (esta tltima condicién existe para simplificar ¢ e6digo y mantenerlo comprensible). Programa 5.8 Bucle que calcula las dfas de un mes para un aito no bisiesto #include * Tipos enum MesesAnyo | enero, febrero, marzo, abril, mayo, junio, julio, osto, septiembre, octubre, noviembre, diciembre |; typedef enum MesesAnyo TipoMes; * Funefén: main Médulo: agenda.c Parametros entrada: no * Parémetros salida: no * Deseripcién: Dado un mes, muestra tiene ne u nimero de dias. int. main(void) TipoMes mes: int diasMes: cla * Calcular el N dfas de un mes 5.7. Sentencia switch 143 printf(*\nIntroduzca e7 nimero del mes (0-11): "I: seanf("Sd", (int *)&mes): switch (mes) { case abri case junio: case septiembre: case noviembre dia break: Mes — 30; case febrero diasMes = 28; brea default: diasMes = printf("\nE] mes ndmero $d tiene %d dias.\n*,mes,diasMes): return(0)s La primera parte del programa es idéntica a la que aparece en el Programa 5.3, salvo por las siguientes Iineas de cddigo: enum Mesesdnyo | enero, febrero, marzo, abril, mayo, junio, julio, agos’ sel emp: octubre, noviembre, diciembre |; typedef enum MesesAnyo TipoMes; En ellas se define el tipo Tipol2s como un tipo enumerado, cuyos componentes son los meses del afio. Para mas informacién consulte el Capitulo 3. Después de mostrar el mensaje de presentacién, se pide al usuario que introduzca el ntimero de orden del mes. Este ntimero debe estar comprendido entre 0 y 11 ya que es el rango de niimeros asociados con el tipo enumerado Ti poNes. La siguiente sentencia se corresponde con la sentencia switch, la cual tiene este aspecto: switch (mes case case case septiembre case naviembr: case febrero: diasMes = 28; break: default: diasMes = 1 print#(*\nE] mes numero &d tiene &d dfas.\n",mes,diasMes); 144 — El lenguaje de programacién C: disefio e implementacién de programas | Enel caso de que el valor de la variable mes sea igual a abril, junio, septiembre 0 novi la sentencia switch asignard a diasMes el valor 30. Después se ejecutaré la senten break, con lo que terminard la sentencia switch. En el caso de que el valor de Ja variable mes sea igual a febrero, la sentencia swi tc) asignard a di el valor 28. Después se ejecutaré la sentencia rea, con lo que term) nar la senteneia switch Siel valor de Ia variable mes no es igual a ninguno de los meses anteriores, entonces s activard la entrada default y, por tanto, se asignard a di asMes el valor 31. A continuacid terminard la sentencia switch. La sentencia printf posterior mostrar el mimero de mes correspondiente junto ¢ ntimero de dias que posee Advertencia 5.7 No olvide escribir break Cada bloque de sentencias case debe terminar con un break. En caso contrario, el com+ pilador entiende que también debe ejecutarse el bloque del case siguiente y lo engloba todo como el mismo bloque. Veamos un ejemplo: switch (contador) | case 1: printf¢"opcién 1\n"); case 2: printf("opei6n 2\n' bres {Qué ocurriré cuando contador sea 1. Pues que el programa imprimiré: 4 | opcion 1 opeién 2 | Bs eso lo que se pretendia? No hay forma de saber si es un error o se ha programado asi a propésito. j 5.8 BUCLES ANIDADOS Como se comenté al principio del capitulo, las estructuras de programacion (tanto las se, cuencias, como las de seleccién 0 iteracién) se pueden concatenar entre sf de miiltiples formas para dar lugar aun programa concreto. Una forma muy habitual de coneatenacién consiste en utilizar dos o mas estructuras de iteracion y concatenarlas de forma que una de ellas forme parte de la secuencia de instruc: ciones de otra. A su vez estas dos podrfan formar parte de una tercera estructura de iteraci a y asf sucesivamente. Esta forma de concatenacién se conoce como anidamiento de bucles. Su uso esté muy extendido, por ejemplo, a la hora de recorrer, elemento a elemento, estructuras de datos de dos © mas dimensiones, 5.8. Bucles anidados 145 Tomemos como ejemplo el Programa 5.9, el cual solicita un mimero V, calcula el sumatorio desde | hasta Ny en caso que N no sea 0, repite de nuevo toda la operacién: Programa 5.9 Calculo del sumatorio desde I hasta mientras que N sea distinto de 0 finclude contador + 1) 1 n*,suma) La primera sentencia del programa consiste en un bucle do-while que encapsula al resto del programa. De esta forma el nticleo del programa se ejecutara como minimo una vez y como maximo tantas veces como sea, dependiendo de la condicién del do- whi le La secuencia correspondiente a dicho do-wh‘]® comienza con la peticidn al usuario para que introduzea un mimero, A partir de ahi, se ejecuta el siguiente bucle cuyo c6digo es el siguiente: suma — 0; i r = 0; contador <= numer ntadors ontador = contador + = suma + printé El bucle anterior esté compuesto por una sentencia for, la cual utiliza la variable contador como indice, incrementdndola una unidad en cada iteracién. En la primera itera- cidn la variable contador tiene el valor 0, y Ia tiltima iteracin ocurriré cuando la variable contador alcance un valor igual al de la variable numero, resultado de sumar 1#2+,..+N es Sd.\n".suma): En cada iteracién de la sentencia for se afiade el valor de contador al contenido de la variable suma. De tal forma que (suponiendo que inicialmente suma es igual a0 y numero 146 El lenguaje de programacién C: disefio e implementacién de programas €s igual a N), el valor final de suma sera igual a 0+1+2+. . .+N. Este resultado es equivalente al deseado, La Figura 5.10 muestra el diagrama de flujo de los bucles anidados del Programa 5.9. Como se puede ver, cualquier programa, por complejo que sea, se puede representar me- diante blogues bisicos de programaci6n estructurada. false verdadero fake Figura 5.10 Diagrama de flujo de bucles anidados . Observe que un requisito importante consiste en que la variable suma tenga un valor igual a 0 antes de ejecutar la sentencia for. En el Programa 5.4, que realiza la misma operaciGn, se inicia dicha variable en el momento de declararla. Este procedimiento no: seria vélido en este caso. Hay que recordar que la sentencia for esta incluida dentro de una sentencia do-while, esto implica que dicho far va a ser ejecutado, de forma completa, varias veces, La variable suns deberd ser iniciada antes de cada nueva ejecucién completa de la sentencia for, por ello la sentencia de inicio de suma deberd estar incluida dentro del bucle do-while y ser anterior a la ejecucién del bucle far. Esta iniciaciGn previa de las variables es corriente en muchos casos de bucles anidados, asf que tome buena nota de ello. | Adverten: 5.8 Es imposible realizar un anidamiento cruzado de bucles. La gente que descubre por primera vez la programaci6n, al empezar a utilizar estruct de iteraci6n, suele suponer que es posible realizar un anidamiento cruzado de bucles, 5.9, Sentencias break y continue 147 y como muestra el siguiente cédigo. while (expresion) { for (expresién 1: expresién 2; expresién 3) { is nal del bucle while */ } /* final del bucle for */ Este c6digo es imposible por propia definicién. Como se mencioné anteriormente, la tinica forma de anidar bucles consiste en incluir una sentencia de iteracién dentro de otra sen- tencia de iteracién, Si se intentara compilar el c6digo anterior, el compilador entenderia el programa de la siguiente forma: while (expresién) { for (expresién 1; expresién 2; expresi6n 3) ] /* final del bucle for */ } /* Final det bucte while */ 59 SENTENCIAS break Y continue La sentencias break y continue son sentencias que modifican el comportamiento de otras sentencias de control simplemente por el hecho de estar incluidas en algtin punto de su secuencia de instrucciones La sentencia break afecta a las sentencias switch, forma siguiente: while, for y do-while de la = Si aparece una sentencia break dentro de la secuencia de instrucciones de cualquiera de las sentencias anteriores, dicha sentencia termina inmediatamente. : = Si aparece en el interior de un bucle anidado s6lo finaliza la sentencia de iteracién mas interna, el resto se ejecuta de forma normal. La sentencia continue afecta a las semtencias wii le, for y do-while de la forma siguiente: = Si aparece una sentencia continue dentro de la secuencia de instrucciones de cual- quiera de las sentencias de iteraci6n anteriores, dicha sentencia da por terminada la iteracién actual y se ejecuta una nueva iteracién, evaluando de nuevo la expresién con- dicional del bucle. = Si aparece en el interior de un bucle anidado sdlo afecta a la sentencia de iteracién mas interna, el resto se ejecuta de forma normal. La Figura 5.11 muestra sobre el diagrama de flujo de un bucle wh‘ Te, el efecto de usar las sentencias continue y break dentro de dicho bucle. Como se puede apreciar en Ja Figura, usar continue equivale a decir que se ha cumplido la condicién para repetir el bucle, Por el contrario, usar break equivale a decir que no se cumple dicha condicién y 148 — El lenguaje de programacién C: disefio e implementacién de programas que, por tanto, el bucle debe terminar. 2A qué equivalen estas instrucciones en ensamblador? Pues a saltos incondicionales, exactamente igual que el goto. falso empresion I= 0 verdadero Secuencia Figura 5.11 Influencia de conti nue y break dentro de un bucle Como ejemplo se utilizaré el mismo cédigo del Programa 5.9. adapténdolo para utilizar las sentencias break y continue. El resultado esté reflejado en el Programa 5.10. Programa 5.10 Cilculo del sumatorio desde } hasta N, mientras que N sea distinto de 0, utili- zando break y continue #include nt main(void) int numero: int suma; int contador: do { * Leer e1 ndmero printf ("Introduzca un ndmero positivo, 0 para terminar: “); scanf ("8d", &numero) ; if (0 = numero) | printf(*Finalizando el programa. \n"): break: # (0 > numero) 5.9. Sentencias break y continue 149 printf("Error: Namero negat continu or = 0; contador <~ numero; contador suma + contado uma); resultado de sumar 1+2+...4N es %d.\n" La primera parte del programa es idéntica a la del Programa 5.9, es a partir de la obten- cién del ntimero cuando aparecen las diferencias. La primera diferencia importante viene representada por la siguiente sentencia: Esta sentencia 1# comprueba el valor de la variable numero y, en caso que sea igual a 0, muestra por pantalla el mensaje Finalizando e] programa y ejecuta la sentencia break Dicha-sentencia break se ejecuta en el interior de una sentencia de iteracién (sentencia do-wht 14). Por lo tanto dicha sentencia do-whi |e terminard y, al ser la dltima sentencia, el programa finalizard. Por Io tanto, en caso de que el valor de la variable numero sea igual a 0, el programa finalizaré. La sentencia que viene a continuaciGn también es digna de mencién # (0 > numero) printf("Error: Namero negativo.\n"); Esta sentencia if comprueba el valor de Ja variable numero y, en caso que sea menor que 0, muestra por pantalla el mensaje Error: Ndmero negativo y ejecuta la sentencia ntinue. Dicha sentencia cont inue se ejecuta en el interior de una sentencia de iteracién (sen- tencia do-wh/1e). Por lo tanto terminaré la iteracién actual de dicha sentencia do-while, volviéndose a ejecutar desde el principio, evaluando otra vez la expresi6n condicional. Por Jo tanto, en caso de que el valor de la variable numero sea menor que 0, el programa no calculard su correspondiente sumatorio y pedira un nuevo niimero. El resto del programa sigue siendo idéntico al Programa 5.9. La sentencia for se en- carga de calcular el sumatorio correspondiente y la sentencia printf muestra el resultado por pantalla, 150 E/ lenguaje de programacién C: diseno e implementacién de programas Tenga en cuenta que la expresién correspondiente al do-witi le es siempre verdadera. Por tanto la tinica forma de salir de dicha sentencia es por medio de la sentencia break. Sentencias break y continue y programacion estructurada La utilizacion de Las sentencias break nue en las estructuras de iteracién (whi 1é, for, y do-while) esta refiida con las reglas de la programacién estructurada, Como se comenté en el Capitulo 1, en este tipo de programacién todo bloque debe tener un solo punto de entrada y un solo punto de salida y. por lo tanto, no es aconsejable 1a utilizacién de dichas sentencias. En lo que respecta a las estructuras de iteraciGn. La programaci6n estructurada advierte que, cualquier tipo de salto incondicional en la ejecucién del cédigo complica mucho su compresién. Por tanto las iteraciones deben ejecutarse en todo momento de principio a fin Ademés la tinica forma correcta de finalizar una estructura de iteracién debe ser por medio de su expresién condicional. Todas estas reglas persiguen que el cddigo que se realice resulte lo mas comprensible posible. El uso indiscriminado de las sentencias break y continue rompe la estructura del codigo y dificulta mucho la legibilidad del programa tanto para terceras personas como para el propio programador, una vez transcurrido cierto tiempo desde su programacién 5.10 ERRORES DE PROGRAMACION COMUNES Aunque a lo largo del capitulo se han ido describiendo errores de programacién que se cometen cuando se programan estructuras de control en C, a continuacién se describen los principales errores que aparecen cuando se hace programacién con los temas mostrados en este Capitulo. No utilizar secuencias delimitadas entre Haves Prescindir de las Haves cuando se pro- graman sentencias de control puede dar lugar a errores dificiles de detectar y depurar. Estos errores se producen, sobre todo, cuando se modifica el cédigo con posterioridad. Este error genera un comportamiento completamente distinto del programa, Incluir un ; junto a la sentencia de control Finalizar todas las sentencias de C con ; no es correcto en todos los casos. Imagine que escribe lo siguient if (0 — contador); printf ("Contador vacio\n Aungue el ‘f se evalie bien no imprime el mensaje. ;Por qué? Pues porque el ; de detras indica precisamente eso: no hacer nada. Si ocurre esto mismo en sentencias for o whi 12, lo que ocurre es que no se ejecuta el bucle correspondiente Confusiones entre asignacién y comparacién de igualdad Este error es muy frecuen- te y dificil de detectar. Si se escribe if (contador = 0), se est asignando 0 al contador. no se est haciendo una comparacién. Esto se evita poniendo la constante primero, es decir if (0 = contador), lo que daria un error de compilacién y detec- tarfa el problema.

También podría gustarte