Programación en C/Instrucciones de control

De Wikilibros, la colección de libros de texto de contenido libre.

← Expresiones Instrucciones de control Uso de Funciones →


Como ya se ha mencionado, C es un ejemplo de programación estructurada. En este tipo de programación, es necesario contar con ciertas estructuras que permitan controlar el flujo del programa, es decir, tomar decisiones y repetir acciones.

Contenido

[editar] La estructura condicional if ... else

En la gran mayoría de los programas será necesario tomar decisiones sobre qué acciones realizar. Esas decisiones pueden depender de los datos que introduzca el usuario, de si se ha producido algún error o de cualquier otra cosa.

La estructura condicional if ... else es la que nos permite tomar ese tipo de decisiones. Traducida literalmente del inglés, se la podría llamar la estructura "si...si no", es decir, "si se cumple la condición, haz esto, y si no, haz esto otro".

Un ejemplo sencillo sería el siguiente (no se trata de un programa completo, sino tan sólo una porción de código):

	if (edad < 18) 
		printf("No puedes acceder.\n");
	else
		printf("Bienvenido.\n");

Este código de ejemplo dice que si edad es menor que 18 se imprimirá "No puedes acceder.\n", mientras que en caso contrario se imprimirá "Bienvenido.\n".

Como se ve en el ejemplo, la estructura de un condicional es bastante simple:

	if (condición) {
		sentencias_si_verdadero;
	} else {
		sentencias_si_falso;
	}

Cuando la condición sea verdadera, se ejecutarán las sentencias dentro del primer bloque de código, cuando la condición sea falsa, se ejecutarán las sentencias del segundo bloque de código.

La indentación (los espacios al comienzo de las líneas) no es necesaria, pero ayuda a la claridad del código. La utilización de las llaves {... } es obligatoria cuando se quiere utilizar más de una instrucción por bloque, y optativa cuando sólo se quiere escribir una instrucción. Por claridad, sin embargo, es recomendable utilizarlas aún cuando sólo vaya a haber una instrucción.

El bloque del else es opcional. Si no se lo encuentra, sólo se realizará la acción correspondiente al bloque if.

A continuación, un ejemplo con una función, que devuelve el mayor de dos números:

int mayor(int a, int b)
{
	int elmayor = a;
	if (b > a) {
		elmayor = b;
	}
	return elmayor;
}

[editar] Operadores de Comparación

Las condiciones son expresiones que utilizan operadores para tomar la decisión apropiada. Son los operadores de comparación, y su resultado puede ser 1 (equivalente a verdadero) o 0 (equivalente a falso). Este resultado provocará que se ejecute el código del bloque if o el del bloque else, según corresponda.

A continuación un listado de los posibles operadores de comparación en C y su significado.

Operadores de Comparación
Operador Significado
< estrictamente menor que
> estrictamente mayor que
<= menor o igual que
>= mayor o igual que
== igual a
!= distinto de


Por otro lado, en C se toma como falso el valor 0, y como verdadero cualquier otro valor. Esto nos permite utilizar condiciones sin operador:

float division(int dividendo, int divisor)
{
	if (divisor) {
		return dividendo / divisor;
	} else {
		printf ("No se puede dividir por cero\n");
		return 0;
	}
}

[editar] Agrupación de operadores

Además, es posible utilizar varios de estos operadores a la vez, mediante los operadores lógicos "y", "o" y "no"; los operadores correspondientes en C son &&, || y !, respectivamente. Para realizar combinaciones de operadores, se utilizan paréntesis que agrupan las condiciones.

Hay que notar que el operador ! es unario, es decir, no lleva ningún operando a su izquierda, afecta sólo al operando que hay a su derecha.

Un ejemplo donde se ven agrupaciones de operadores puede ser la decisión de si un año es bisiesto o no. Los años son bisiestos si son divisibles por 4, pero no si son divisibles por 100, a menos que también sean divisibles por 400.

	if ( (!(a % 4)) && (a % 100) || (!(a % 400)) )  {
		printf("es un año bisiesto.\n");
	} else {
		printf("no es un año bisiesto.\n");
	}

En este caso, se utiliza la operación módulo, que obtiene el resto de la división entera de un número por otro. Cuando un número es divisible por otro, el resto de su división entera será cero. Siendo que cero es equivalente a falso, y cualquier valor distinto de cero es equivalente a verdadero, podemos usar el operador ! para verificar si el número es múltiplo de 4, de 100 o de 400.


[editar] Evaluación de corto circuito

La evaluación en corto circuito es una característica del lenguaje C que se utiliza para optimizar la ejecución de programas. Consiste en que el programa puede verificar si una expresión es verdadera o falsa antes de haber evaluado toda condición.

Por ejemplo, si se tiene una condición como la siguiente:

	if ((a > 2) || (b < 4)) {
		...
	}

Al ejecutarse el programa, se evaluará primero si a > 2. En el caso en que sea verdadero, no continuará con la siguiente condición, ya que el resultado será de cualquier modo verdadero.

De la misma forma, si la condición fuera:

	if ((a > 2) && (b < 4)) {
		...
	}

En este caso, si no se cumple que a > 2, no se evaluará la siguiente condición, ya que el resultado será falso de todos modos.

Esta característica no tiene demasiada importancia al comenzar a programar, pero facilitará ciertas operaciones y optimizaciones en programas avanzados.


[editar] La estructura condicional switch ... case

La estructura condicional switch ... case se utiliza cuando queremos evitarnos las llamadas escaleras de decisiones. La estructura if nos puede proporcionar, únicamente, dos resultados, uno para verdadero y otro para falso. Una estructura switch ... case, por su parte, nos permite elegir entre muchas opciones:

switch (semaforo) {
	case 1:
		printf("El semáforo está verde.\n");
		break;
	case 0:
		printf("El semáforo está rojo.\n");
		break;
	case 2:
		printf("El semáforo está anaranjado.\n");
		break;
	case 3:
		printf("El semáforo está anaranjado parpadeante.\n");
		break;
	default:
		printf("ERROR:¡El semáforo no puede estar en ese estado!.\n");
}

La estructura anterior, de realizarse con sentencias if, necesitaría cuatro de ellas, resultando un enorme bloque muy difícil de leer. En la mayoría de los casos, además, la sentencia switch proporciona una ganancia en velocidad del código, pues permite al compilador trabajar en base a que se trata de una decisión múltiple para una única variable, cosa que con sentencias if el compilador no tiene por qué detectar.

Como vemos, para cada valor de la variable se ejecuta un bloque de sentencias distinto, en el que no necesitamos llaves. Hay un caso especial, default, que se ejecuta si ningún otro corresponde, y que no es necesario poner. Es, en todo, equivalente al bloque else de una sentencia if.

Las sentencias break son muy importantes, ya que el comportamiento normal de un bloque switch es ejecutarlo todo desde la etiqueta case que corresponda hasta el final. Por ello, si no queremos que se nos ejecute más de un bloque, pondremos sentencias break al final de cada bloque excepto el último.

Es decir, las etiquetas case son puntos de entrada de la ejecución, y no implican que al acabarse el bloque case la ejecución salte al final del bloque switch. Las etiquetas case siguientes a la que hemos utilizado para entrar son, sencillamente, ignoradas.

A la ausencia de sentencias break se le llama, en ocasiones, "dejar caer la cascada switch".

[editar] El bucle while

El bucle while sirve para ejecutar código reiteradas veces.

while (/* Condición de ejecución del bucle */) {
	/* Código */
}

La condición ha de ser una sentencia que devuelva un valor booleano, y esta puede ser el valor booleano en sí, verdadero (true o 1) si la condición se cumple, o falso si esta no se cumple (false o 0). También puede ser el nombre de una variable, y el valor de la expresión dependerá de su contenido. Aunque sea una variable no booleana, siempre se podrá usar, si vale 0 será como si la condición no se cumpliera, y siempre que sea diferente de 0, se considerará que la condición se cumple.

La forma más obvia tal vez, y la más usada sin duda, son las sentencias comparativas, que usan los operandos ==, !=, <=, >=, <, >. Su uso sería así:

variable o valor inmediato operador variable o valor inmediato

Tened en cuenta que además de las variables y los valores inmediatos, también se pueden poner allí llamadas a funciones que devuelvan un valor.

int tecla = 0;
while (tecla == 0) {
	tecla = readkey(); /* Intentamos leer una pulsación de tecla */
}

En este ejemplo lo que hacemos es que el programa se ature hasta que el usuario pulse una tecla, con lo que cambiará el valor de la variable "tecla".

[editar] El bucle for

El bucle for es un bucle muy flexible y la vez muy potente ya que tiene varias formas interesantes de implementarlo, su forma más tradicional es la siguiente:

for (/* inicialización */; /* sentencia condicional */; /* incremento o decremento */) {
	/* código a ejecutar */
}

Inicialización: en esta parte se inicia la variable que controla el bucle y es la primera setencia que ejecuta el bucle, solo se ejecuta una vez ya que solo se necesita al principio del bucle.

Sentencia condicional: es la segunda sentencia que ejecuta el bucle, es una sentencia condicional válida, que determina si el bucle se ejecutará o no. incremento o decremento: es la ultima sentencia que ejecuta el bucle por lo general incrementar la variable con que se inicio el ciclo, después de eso el bucle revisa nuevamente la condición, si es verdadera tiene lugar una ejecución más del cuerpo del ciclo, si es falsa se termina el ciclo y así la repetición. Aquí muestro un ejemplo de un bucle que se ejecuta 100 veces:

for (int i=0; i < 100; i++) {
	printf("%i\n", i);
}

No es necesaria por ejemplo en la primera la sentencia iniciar la variable que utilizara el bucle si ya ha sido inicializada en otra parte del bloque de sentencias donde se encuentra el bucle.

Por lo general la sentencia condicional se compone de la variable que se utilizo para la inicailizacion del bucle a la cual se le aplica alguna de los operadodores relacionales <, <=, >, >=; junto con otro valor; esta parte del bucle también se puede implementar con una variable de tipo bool.

NOTA: recuerde que en las que cualquier sentencia donde se evalúa una expresión valida, un valor de retorno=0 se considera falso y cualquier valor distinto de cero es verdadero, así false=0 y true=1.

Creo que es importante comentar que esos tres "parámetros" que se le pasan a la sentencia for se pueden omitir, pero los punto-y-coma entre ellos sí se han de dejar. También cabe destacar que si no se pone la condición de ejecución del bucle, este se ejecutará indefinidamente hasta que se ejecute una sentencia break o se termine la función o el programa mediante un return.

[editar] El bucle do...while

El bucle do...while es un bucle que, por lo menos, se ejecuta una vez.

Su forma es esta:

do {
	/* CODIGO */
} while (/* Condición de ejecución del bucle */)

Os muestro un ejemplo sencillo de uso:

int aleatorio;
do {
	aleatorio = rand();
} while (aleatorio != 25)

La verdad es que este ejemplo puede resultar un poco absurdo, pero es bastante intuitivo. El código del bucle asigna un valor aleatorio a la variable definida anteriormente, y mientras esa variable no tenga el valor 25, el bucle sigue ejecutándose.

[editar] El goto

La sentencia goto sirve para indicar al programa que continue ejecutándose desde la línea de código indicada. La verdad es que es una sentencia poco aceptada por la comunidad de programadores, pues puede provocar que se hagan programas un poco "sucios" y confusos.

Su sintaxis es más o menos así:

/* Código */
ETIQUETA:
/* Código */
goto ETIQUETA;
/* Código */

Así, cuando se ejecute la sentencia goto, el programa continuará su ejecución a partir de la etiqueta marcada. Como se puede observar se puede usar para crear un bucle, o para ir a una parte del código u otra si se combina con una sentencia if...else. pero para los bucles ya hay estructuras definidas, y para la ejecución opcional de bloques de código, ya existen las Funciones.

Sólo en ocasiones muy excepcionales será recomendado el uso del goto al crear iteraciones muy complejas.


← Expresiones Instrucciones de control Uso de Funciones →
Herramientas personales