1. INTRODUCCION
En lo que sigue de este capítulo, denominaremos BLOQUE DE SENTENCIAS al conjunto de sentencias individuales incluídas dentro un par de llaves. Por ejemplo :
{ sentencia 1 ; sentencia 2 ; ............. sentencia n ; }
Este conjunto se comportará sintacticamente como una
sentencia simple y la llave de cierre del bloque NO debe ir
seguida de punto y coma .
Un ejemplo de bloque ya visto , es el cuerpo del programa
principal de la función main() .
main() { bloque de sentencias }
En las proposiciones de control de flujo de programa , trabajaremos alternativamente con sentencias simples y bloques de ellas .
2. PROPOSICION IF - ELSE
Esta proposición sirve para ejecutar ciertas sentencias de programa , si una expresión resulta CIERTA ú otro grupo de sentencias, si aquella resulta FALSA. Su interpretación literal sería : SI es CIERTA tal cosa , haga tal otra , si no lo es salteéla .
El caso más sencillo sería :
if(expresión) sentencia ; ó if(expresión) sentencia ;
Cuando la sentencia que sigue al IF es única, las dos formas de escritura expresadas arriba son equivalentes . La sentencia sólo se ejecutará si el resultado de "expresión" es distinto de cero (CIERTO) , en caso contrario el programa salteará dicha sentencia , realizando la siguiente en su flujo.
Veamos unos ejemplos de las distintas formas que puede adoptar la
"expresión" dentro de un IF :
if( a > b ) | if( (a > b) != 0 ) | las dos expresiones son idénticas, aunque a veces resulta más claro expresarla de la segunda manera, sobre todo en los primeros contactos con el lenguaje. |
if(a) | if(a != 0) | |
if(!a) | if(a == 0 ) | Las dos superiores son idénticas entre sí , al igual que las dos inferiores Obsérvese que (!a) dará un valor CIERTO sólo cuando a sea FALSO. (ver operador NEGACION en el capítulo anterior ) |
if( a == b ) | ||
if( a = b ) | /* Error */ | La primera es una expresión correcta , el IF se realizará sólo si a es igual a b. En cambio la segunda es un error , ya que no se está comparando a con b , sino ASIGNANDO el valor de esta a aquella . Sin embargo, a veces puede usarse como un truco (un poco sucio) de programacion , ya que primero se realiza la asignación y luego se evalúa el resultado de esta para realizar el IF , es entonces equivalente a escribir : |
a = b ; | ||
if(a) | .................... | con el ahorro de una linea de programa ( a costa de la legibilidad del mismo ). |
En casos más complejos que los anteriores , la proposición IF puede estar seguida por un bloque de sentencias :
if(expresión) if(expresión) { { sentencia 1 ; sentencia 1 ; sentencia 2 ; sentencia 2 ; ............... ............. } }
Las dos maneras son equivalentes , por lo que la posición de la llave de apertura del bloque queda librada al gusto del programador . El indentado de las sentencias (sangría) es también optativo , pero sumamente recomendable ,sobre todo para permitir la lectura de proposiciones muy complejas ó anidadas , como se verá luego. El bloque se ejecutará en su conjunto si la expresion resulta CIERTA. El uso del ELSE es optativo , y su aplicación resulta en la ejecución de una , ó una serie de sentencias en el caso de que la expresión del IF resulta FALSA.
Su aplicación puede verse en el ejemplo siguiente :
if(expresión) if(expresión) { { sentencia 1 ; sentencia 1 ; sentencia 2 ; sentencia 2 ; } } sentencia 3 ; else sentencia 4 ; { sentencia 5 ; sentencia 3 ; sentencia 4 ; } sentencia 5 ;
En el ejemplo de la izquierda no se usa el ELSE y por lo tanto
las sentencias 3 , 4 y 5 se ejecutan siempre . En el segundo caso
, las sentencias 1 y 2 se ejecutan solo si la expresión es
CIERTA , en ese caso las 3 y 4 NO se ejecutarán para saltarse
directamente a la 5 , en el caso de que la expresión resulte
FALSA se realizarán las 3 y 4 en lugar de las dos primeras y
finalmente la 5 .
La proposición ELSE queda siempre asociada al IF más cercano ,
arriba de él .
Es común también , en caso de decisiones múltiples , el uso de
anidamientos ELSE-IF de la forma indicada abajo:
if(exp.1) if(exp.1) sentencia1 ; sentencia1 ; else if(exp.2) else if(exp.2) sentencia2 ; sentencia2 ; else if(exp.3) else if(exp.3) sentencia3 ; sentencia3 ; else else sentencia5 ; sentencia5 ;
Si bién se suele escribir según la modalidad de la izquierda , a la derecha hemos expresado las asociaciones entre los distintos ELSE é IF por medio del indentado del texto.
3. PROPOSICION SWITCH
El SWITCH es una forma sencilla de evitar largos , tediosos y
confusos anidamientos de ELSE-IF .
Supongamos que estamos implementando un Menu , con varias
elecciones posibles . El esqueleto de una posible solución al
problema usando if-else podría ser el siguiente :
#include <<stdio.h>> main() { int c ; printf("\nMENU :") ; printf("\n A = ADICIONAR A LA LISTA ") ; printf("\n B = BORRAR DE LA LISTA ") ; printf("\n O = ORDENAR LA LISTA ") ; printf("\n I = IMPRIMIR LA LISTA ") ; printf("\n\nESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : ") ; if( (c = getchar()) != '\n' ) { if( c == 'A') printf("\nUD. SELECCIONO AGREGAR") ; else if( c == 'B') printf("\nUD. SELECCIONO BORRAR") ; else if( c == 'O' ) printf("\nUD. SELECCIONO ORDENAR") ; else if( c == 'I' ) printf("\nUD. SELECCIONO IMPRIMIR") ; else printf("\n\a\aUD. APRETO UN CARACTER ILEGAL" ) ; } else printf("\n¡ UD. NO HA SELECCIONADO NADA !" ) ; }
Como es fácil de ver , cuando las opciones son muchas, el
texto comienza a hacerse difícil de entender y engorroso de
escribir.
El mismo programa, utilizando un SWITCH , quedaría mucho más
claro de leer, y sencillo de escribir, como se aprecia en el
EJEMPLO siguiente.
#include <stdio.h> #include <conio.h> main()
{ int c ; printf("\nMENU :") ; printf("\n A = ADICIONAR A LA LISTA ") ; printf("\n B = BORRAR DE LA LISTA ") ; printf("\n O = ORDENAR LA LISTA ") ; printf("\n I = IMPRIMIR LA LISTA ") ; printf("\n\nESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : ") ; c = getchar() ; switch (c) { case 'A' : printf("\nUD. SELECCIONO AGREGAR") ; break ; case 'B' : printf("\nUD. SELECCIONO BORRAR") ; break ; case 'O' : printf("\nUD. SELECCIONO ORDENAR") ; break ; case 'I' : printf("\nUD. SELECCIONO IMPRIMIR") ; break ; case '\n': printf("\n¡ UD. NO HA SELECCIONADO NADA !" ) ; break ; default : printf("\n\a\aUD. APRETO UN CARACTER ILEGAL" ) ; break ; } }
El SWITCH empieza con la sentencia : switch (expresión) . La
expresión contenida por los paréntesis debe ser ENTERA , en
nuestro caso un caracter ; luego mediante una llave abre el
bloque de las sentencias de comparación . Cada una de ellas se
representa por la palabra clave "case" seguida por el
valor de comparación y terminada por dos puntos . Seguidamente
se ubican las sentencias que se quieren ejecutar , en el caso que
la comparación resulte CIERTA . En el caso de resultar FALSA ,
se realizará la siguiente comparación , y así sucesivamente .
Prestemos atención tambien a la sentencia BREAK con la que se
termina cada CASE. Una característica poco obvia del SWITCH , es
que si se eliminan los BREAK del programa anterior , al resultar
CIERTA una sentencia de comparación, se ejecutarán las
sentencias de ese CASE particular pero TAMBIEN la de todos los
CASE por debajo del que ha resultado verdadero. Quizás se aclare
esto diciendo que , las sentencias propias de un CASE se
ejecutarán si su comparación ú otra comparación ANTERIOR
resulta CIERTA . La razón para este poco "juicioso"
comportamiento del SWITCH es que así se permite que varias
comparaciones compartan las mismas sentencias de programa , por
ejemplo :
................. case 'X' : case 'Y' : case 'Z' : printf(" UD. ESCRIBIO X , Y , ó Z ") ; break ; ..................
La forma de interrumpir la ejecución luego de haber
encontrado un CASE cierto es por medio del BREAK , el que dá por
terminado el SWITCH .
Al final del bloque de sentencias del SWITCH , aparece una
optativa llamada DEFAULT , que implica : si no se ha cumplido
ningun CASE , ejecute lo que sigue. Es algo superfluo poner el
BREAK en este caso , ya que no hay más sentencias despues del
DEFAULT , sin embargo , como el orden en que aparecen las
comparaciones no tiene importancia para la ejecución de la
instrucción, puede suceder que en futuras correcciones del
programa se agregue algún nuevo CASE luego del DEFAULT , por lo
que es conveniente preveerlo , agregando el BREAK , para evitar
errores de laboriosa ubicación .
Más adelante volveremos sobre otros usos del BREAK.
4. LA ITERACION WHILE
El WHILE es una de las tres iteraciones posibles en C . Su
sintaxis podría expresarse de la siguiente forma :
while(expresion) ó while(expresión) { proposición 1 ; proposición 1 ; proposición 2 ; ............... proposición n ; }
Esta sintaxis expresada en palabras significaria: mientras
(expresión) dé un resultado CIERTO ejecútese la proposición 1
, en el caso de la izquierda ó ejecútese el bloque de
sentencias , en el caso de la derecha.
Por lo general , dentro de la proposición ó del bloque de ellas
, se modifican términos de la expresión condicional , para
controlar la duración de la iteración .
5. LA ITERACION DO - WHILE
Su sintaxis será :
do { proposición 1 ; proposición 2 ; ............... } while (expresión) ;
Expresado en palabras , esto significa : ejecute las proposiciones , luego repita la ejecución mientras la expresión dé un resultado CIERTO . La diferencia fundamental entre esta iteración y la anterior es que el DO-WHILE se ejecuta siempre AL MENOS una vez , sea cual sea el resultado de expresión.
6. ITERACION FOR
El FOR es simplemente una manera abreviada de expresar un WHILE ,
veamos su sintaxis :
for ( expresión1 ; expresión2 ; expresion3 ) { proposición1 ; proposición2 ; .............. } Esto es equivalente a : expresión1 ; while ( expresión2 ) { proposición1 ; proposición2 ; .............. expresion3 ; }
La expresión1 es una asignación de una ó más variables ,
(equivale a una inicialización de las mismas ) , la expresión2
es una relación de algun tipo que , mientras dé un valor CIERTO
, permite la iteración de la ejecución y expresión3 es otra
asignación , que comunmente varía alguna de las variables
contenida en expresión2 .
Todas estas expresiones , contenidas en el paréntesis del FOR
deben estar separadas por PUNTO Y COMA y NO por comas simples .
No es imprescindible que existan TODAS las expresiones dentro del
paréntesis del FOR , pudiendose dejar en blanco algunas de ellas
, por ejemplo :
for ( ; exp2 ; exp3) ó for (exp1 ; ; ) ó for ( ; ; )
Estas dos últimas expresiónes son interesantes desde el punto de vista de su falta de término relacional , lo que implica que el programador deberá haber previsto alguna manera alternativa de salir del lazo ( probablemente mediante BREAK ó RETURN como veremos más adelante ) ya que sinó , la ejecución del mismo es infinita ( ó tan larga como se mantenga encendida la computadora ) .
7. LA SENTENCIA BREAK
El BREAK , ya brevemente descripto con el SWITCH , sirve también
para terminar loops producidos por WHILE , DO-WHILE y FOR antes
que se cumpla la condición normal de terminación . En el
EJEMPLO siguiente vemos su uso para terminar un WHILE
indeterminado.
#include <stdio.h> #include <conio.h> main() { char c ; printf("ESTE ES UN LOOP INDEFINIDO ") ; while(1) { printf( "DENTRO DEL LOOP INDEFINIDO (apriete una tecla):" ) ; if( (c = getch()) == 'Q' ) break ; printf( "\nNO FUE LA TECLA CORRECTA PARA ABANDONAR EL LOOP ") ; } printf("\nTECLA CORRECTA : FIN DEL WHILE ") ; }
Obsérvese que la expresión while(1) SIEMPRE es cierta , por
lo que el programa correrá imparable hasta que el operador
oprima la tecla "secreta" Q . Esto se consigue en el IF
, ya que cuando c es igual al ASCII Q se ejecuta la instrucción
BREAK ,dando por finalizado el WHILE .
El mismo criterio podría aplicarse con el DO-WHILE ó con FOR ,
por ejemplo haciendo
for (;;) { /* loop indefinido */ ............ if( expresión ) break ; /* ruptura del loop cuando expresión sea verdadera */ }
8. LA SENTENCIA CONTINUE
La sentencia CONTINUE es similar al BREAK con la diferencia que
en vez de terminar violentamente un loop , termina con la
realización de una iteración particular y permitiendo al
programa continuar con la siguiente.
9. LA FUNCION EXIT()
La función EXIT() tiene una operatoria mucho más drastica que
las anteriores , en vez de saltear una iteración ó abandonar un
lazo de programa , esta abandona directamente al programa mismo
dándolo por terminado . Realiza también una serie de
operaciones útiles como ser , el cerrado de cualquier archivo
que el programa hubiera abierto , el vaciado de los buffers de
salida , etc.
Normalmente se la utiliza para abortar los programas en caso de
que se esté por cometer un error fatal é inevitable . Mediante
el valor que se le ponga en su argumento se le puede informar a
quien haya llamado al programa ( Sistema Operativo , archivo .bat
, u otro programa ) el tipo de error que se cometió.
10 SENTENCIA GOTO
Si Ud. se ha admirado de que C tenga la operación GOTO ,
recuerde que el hecho de existir NO lo obliga a usarla , en el
mismo sentido que por tener puertas los aviones no está obligado
a saltar por ellas en pleno vuelo.
El uso del GOTO implica un salto incondicional de un lugar a otro
del programa . Esta práctica hace que los programas sean muy
dificiles de corregir ó mantener.
Si no quedara más remedio que usarlo, (y en programación
estructurada SIEMPRE hay remedio) debe marcarse el destino del
salto mediante un nombre seguido por dos puntos .
if( c == 0 ) goto OTRO_LADO ; ............................. OTRO_LADO: printf(........
En este caso si c es cero se saltean todas las sentencias entre el if y el destino , continuandose con la ejecución del printf() . El destino puede ser tanto posterior como anterior al GOTO invocante .
CAPITULO ANTERIOR DEL CURSO | |
PROXIMO CAPITULO DEL CURSO |