Este sitio web usa cookies de terceros para analizar el tráfico y personalizar los anuncios. Si no está de acuerdo, abandone el sitio y no siga navegando por él. ×


3. Estructuras de control

3.1. Estructuras alternativas

(Nota: En la versión 2016 del curso tienes una variante más reciente y más detallada de este apartado)

3.1.1. if

Vamos a ver cómo podemos comprobar si se cumplen condiciones. La primera construcción que usaremos será "si ... entonces ...". El formato en C es

if (condición) sentencia;

Vamos a verlo con un ejemplo:

/*---------------------------*/
/*  Ejemplo en C nº 14:      */
/*  C014.C                   */
/*                           */
/*  Condiciones con if       */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero>0)  printf("El numero es positivo.\n");
    
  return 0;
}

Nota: para comprobar si un valor numérico es mayor que otro, usamos el símbolo “>”, como se ve en este ejemplo. Para ver si dos valores son iguales, usaremos dos símbolos de “igual”: if (numero==0). Las demás posibilidades las veremos algo más adelante. En todos los casos, la condición que queremos comprobar deberá indicarse entre paréntesis.

Ejercicios propuestos:

3.1.2. if y sentencias compuestas

La "sentencia" que se ejecuta si se cumple la condición puede ser una sentencia simple o una compuesta. Las sentencias compuestas se forman agrupando varias sentencias simples entre llaves ( { y } ):

/*---------------------------*/
/*  Ejemplo en C nº 15:      */
/*  C015.C                   */
/*                           */
/*  Condiciones con if (2)   */
/*  Sentencias compuestas    */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero>0)  
  {  
    printf("El numero es positivo.\n");
    printf("Recuerde que tambien puede usar negativos.\n");
  }  /* Aqui acaba el "if" */
    
  return 0;
}    /* Aqui acaba el cuerpo del programa */

En este caso, si el número es negativo, se hacen dos cosas: escribir un texto y luego... ¡escribir otro! (Claramente, en este ejemplo, esos dos “printf” podrían ser uno solo; más adelante iremos encontrando casos en lo que necesitemos hacer cosas “más serias” dentro de una sentencia compuesta).

Se pueden incluir siempre las llaves después de un "if", como medida de seguridad: un fallo frecuente es escribir una única sentencia tras "if", sin llaves, luego añadir una segunda sentencia y olvidar las llaves... de modo que la segunda orden no se ejecutará si se cumple la condición, sino siempre, como en este ejemplo:

/*---------------------------*/
/*  Ejemplo en C nº 15:      */
/*  c015b.c                  */
/*                           */
/*  Condiciones con if (2b)  */
/*  Sentencias compuestas    */
/*  incorrectas!!!           */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un número: ");
  scanf("%d", &numero);
  if (numero>0)  
    printf("El número es positivo.\n");
    printf("Recuerde que también puede usar negativos.\n");

  return 0;
}

En este caso, siempre se nos dirá "Recuerde que también puede usar negativos", incluso cuando hemos tecleado un número negativo. En un vistazo rápido, vemos las dos sentencias tabuladas a la derecha y tendemos a pensar que las dos dependen del "if", pero no es así. Se trata de un error difícil de detectar. Por eso, muchos autores recomiendan incluir siempre las llaves tras un "if", e incluso algún lenguaje de programación posterior a C obliga a que siempre sea así.

3.1.3. Operadores relacionales: <, <=, >, >=, ==, !=

Hemos visto que el símbolo “>” es el que se usa para comprobar si un número es mayor que otro. El símbolo de “menor que” también es sencillo, pero los demás son un poco menos evidentes, así que vamos a verlos:

Operador

Operación

<

Menor que

>

Mayor que

<=

Menor o igual que

>=

Mayor o igual que

==

Igual a

!=

No igual a (distinto de)

Y un ejemplo:

/*---------------------------*/
/*  Ejemplo en C nº 16:      */
/*  C016.C                   */
/*                           */
/*  Condiciones con if (3)   */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero!=0)  printf("El numero no es cero.\n");
    
  return 0;
}

Los operadores sólo se pueden usar tal y como aparecen en esa tabla. Por ejemplo, no es un operador válido “!<” para expresar que un número no es menor que otro.

Ejercicios propuestos:

3.1.4. if-else

Podemos indicar lo que queremos que ocurra en caso de que no se cumpla la condición, usando la orden “else” (en caso contrario), así:

/*---------------------------*/
/*  Ejemplo en C nº 17:      */
/*  C017.C                   */
/*                           */
/*  Condiciones con if (4)   */
/*  Uso de else              */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero>0)  printf("El numero es positivo.\n");
    else  printf("El numero es cero o negativo.\n");
      
  return 0;  
}

Podríamos intentar evitar el uso de “else” si utilizamos un “if” a continuación de otro, así:

/*---------------------------*/
/*  Ejemplo en C nº 18:      */
/*  C018.C                   */
/*                           */
/*  Condiciones con if (5)   */
/*  Esquivando else          */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero>0)  printf("El numero es positivo.\n");
  if (numero<=0) printf("El numero es cero o negativo.\n");
    
  return 0;
}

Pero el comportamiento no es el mismo: en el primer caso (ejemplo 17) se mira si el valor es positivo; si no lo es, se pasa a la segunda orden, pero si lo es, el programa ya ha terminado. En el segundo caso (ejemplo 18), aunque el número sea positivo, se vuelve a realizar la segunda comprobación para ver si es negativo o cero, por lo que el programa es algo más lento.

Podemos enlazar los “if” usando “else”, para decir “si no se cumple esta condición, mira a ver si se cumple esta otra”:

/*---------------------------*/
/*  Ejemplo en C nº 19:      */
/*  C019.C                   */
/*                           */
/*  Condiciones con if (6)   */
/*  if encadenados           */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main()
{
  int numero;

  printf("Escriba un numero: ");
  scanf("%d", &numero);
  if (numero < 0)
    printf("El numero es negativo.\n");
  else 
    if (numero == 0)
      printf("El numero es cero.\n");
    else
      printf("El numero es positivo.\n");
        
  return 0;
}

Ejercicio propuesto :

 

3.1.5. Operadores lógicos: &&, ||, !

Estas condiciones se puede encadenar con “y”, “o”, etc., que se indican de la siguiente forma

Operador

Significado

&&

Y

||

O

!

No

De modo que podremos escribir cosas como

if ((opcion==1) && (usuario==2)) ...
if ((opcion==1) || (opcion==3)) ...
if ((!(opcion==opcCorrecta)) || (tecla==ESC)) ...

(Suponiendo que ESC fuera una constante ya definido con anterioridad).

La siguiente forma de escribir una condición es incorrecta (y es un error muy frecuente en los que empiezan a programar en C):

if ( opcion1 || opcion2 == 3 ) ...

porque la forma correcta de comprobar si la variable “opcion1” o bien “opcion2” valen “3” sería ésta:

if (( opcion1 == 3 ) || ( opcion2 == 3 )) ...

Ejercicios propuestos :

3.1.6. Cómo funciona realmente la condición en un “if”

Como suele ocurrir en C, lo que hemos visto tiene más miga de la que parece: una condición cuyo resultado sea “falso” nos devolverá un 0, y otra cuyo resultado sea “verdadero” devolverá el valor 1:

/*---------------------------*/
/*  Ejemplo en C nº 20:      */
/*  C020.C                   */
/*                           */
/*  Condiciones con if (7)   */
/*  Valor de verdad          */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("2==3 vale %d\n", 2==3);  /* Escribe 0 */
  printf("2!=3 vale %d\n", 2!=3);  /* Escribe 1 */
    
  return 0;
}

En general, si la “condición” de un if es algo que valga 0, se considerará que la condición es falsa (no se cumple), y si es algo distinto de cero, se considerará que la condición es verdadera (sí se cumple). Eso nos permite hacer cosas como ésta:

/*---------------------------*/
/*  Ejemplo en C nº 21:      */
/*  C021.C                   */
/*                           */
/*  Condiciones con if (8)   */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main() {
  int numero;

  printf("Escribe un numero: ");
  scanf("%d", &numero);
  if (numero!=0)  /* Comparacion normal */
    printf("El numero no es cero.\n");
  if (numero)     /* Comparacion "con truco" */
    printf("Y sigue sin ser cero.\n");
      
  return 0;
}

En este ejemplo, la expresión “if (numero)” se fijará en el valor de la variable “numero”. Si es distinto de cero, se considerará que la condición es correcta, y se ejecutará la sentencia correspondiente (el “printf”). En cambio, si la variable “numero” vale 0, es considera que la condición es falsa, y no se sigue analizando.

En general, es preferible evitar este tipo de construcciones. Resulta mucho más legible algo como “if (numero!=0)” que “if(numero)”.

3.1.7. El peligro de la asignación en un “if”

Cuidado con el operador de igualdad: hay que recordar que el formato es if (a==b) ... Si no nos damos cuenta y escribimos if (a=b) estamos asignando a “a” el valor de “b”.

Afortunadamente, la mayoría de los compiladores nos avisan con un mensaje parecido a “Possibly incorrect assignment” (que podríamos traducir por “posiblemente esta asignación es incorrecta”) o “Possibly unintended assignment” (algo así como “es posible que no se pretendiese hacer esta asignación”). Aun así, sólo es un aviso, la compilación prosigue, y se genera un ejecutable, que puede que se comporte incorrectamente. Vamos a verlo con un ejemplo:

/*---------------------------*/
/*  Ejemplo en C nº 22:      */
/*  C022.C                   */
/*                           */
/*  Condiciones con if (9)   */
/*  Comportamiento           */
/*    incorrecto             */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main()
{
  int numero;

  printf("Escriba un número: ");
  scanf("%d", &numero);
  if (numero < 0)
    printf("El número es negativo.\n");
  else 
    if (numero = 0)
      printf("El número es cero.\n");
    else
      printf("El número es positivo.\n");
  
  return 0;
}

En este caso, si tecleamos un número negativo, se comprueba la primera condición, se ve que es correcta y se termina sin problemas. Pero si se teclea cualquier otra cosa (0 o positivo), la expresión “if (numero=0)” no comprueba su valor, sino que le asigna un valor 0 (falso), por lo que siempre se realiza la acción correspondiente a el “caso contrario” (else): siempre se escribe “El número es positivo”... ¡aunque hayamos tecleado un 0!

Y si esto es un error, ¿por qué el compilador “avisa” en vez de parar y dar un error “serio”? Pues porque no tiene por qué ser necesariamente un error: podemos hacer

a = b
if (a > 2) ...

o bien

if ((a=b) > 2) ...

Es decir, en la misma orden asignamos el valor y comparamos (algo parecido a lo que hacíamos con “b = ++a”, por ejemplo). En este caso, la asignación dentro del “if” sería correcta.

Ejercicios resueltos:

> ¿Qué escribiría en pantalla este fragmento de código?

int x = 5; if (x==5) printf("%d", x);

Respuesta: x vale 5, luego se cumple la condición y se escribe un 5.

> ¿Qué escribiría en pantalla este fragmento de código?

int x = 5; if (x) printf("Si"); else printf("No");

Respuesta: x vale 5, luego la condición se evalúa como verdadera y se escribe Si.

> ¿Qué escribiría en pantalla este fragmento de código?

int x = 0; if (x=5) printf("Si"); else printf("No");

Respuesta: no hemos escrito una comparación dentro de “if”, sino una asignación. Por tanto, lo que hay escrito dentro del paréntesis se evalúa como verdadero (distinto de cero) y se escribe Si.

> ¿Qué escribiría en pantalla este fragmento de código?

int x = 5; if (x=0) printf("Si"); else printf("No");

Respuesta: de nuevo, no hemos escrito una comparación dentro de “if”, sino una asignación. Por tanto, lo que hay escrito dentro del paréntesis se evalúa como falso (cero) y se escribe No.

> ¿Qué escribiría en pantalla este fragmento de código?

int x = 0; if (x==5) printf("Si") else printf("No");

Respuesta: no compila, falta un punto y coma antes de “else”.

 

3.1.8. Introducción a los diagramas de flujo

A veces puede resultar difícil ver claro donde usar un “else” o qué instrucciones de las que siguen a un “if” deben ir entre llaves y cuales no. Generalmente la dificultad está en el hecho de intentar teclear directamente un programa en C, en vez de pensar en el problema que se pretende resolver.

Para ayudarnos a centrarnos en el problema, existen notaciones gráficas, como los diagramas de flujo, que nos permiten ver mejor qué se debe hacer y cuando.

En primer lugar, vamos a ver los 4 elementos básicos de un diagrama de flujo, y luego los aplicaremos a un caso concreto.

Diagrama de flujo 1

El inicio o el final del programa se indica dentro de un círculo. Los procesos internos, como realizar operaciones, se encuadran en un rectángulo. Las entradas y salidas (escrituras en pantalla y lecturas de teclado) se indican con un paralelogramo que tenga su lados superior e inferior horizontales, pero no tenga verticales los otros dos. Las decisiones se indican dentro de un rombo.

Vamos a aplicarlo al ejemplo de un programa que pida un número al usuario y diga si es positivo, negativo o cero:

Diagrama de flujo 2

El paso de aquí al correspondiente programa en lenguaje C (el que vimos en el ejemplo 19) debe ser casi inmediato: sabemos como leer de teclado, como escribir en pantalla, y las decisiones serán un “if”, que si se cumple ejecutará la sentencia que aparece en su salida “si” y si no se cumple (“else”) ejecutará lo que aparezca en su salida “no”.

Ejercicios propuestos:

3.1.9. Operador condicional: ?

En C hay otra forma de asignar un valor según se dé una condición o no. Es el “operador condicional” ? : que se usa

condicion ? valor1 : valor2;

y equivale a decir “si se cumple la condición, toma el valor v1; si no, toma el valor v2”. Un ejemplo de cómo podríamos usarlo sería

numeroMayor = (a>b) ? a : b;

que, aplicado a un programa sencillo, podría ser

/*---------------------------*/
/*  Ejemplo en C nº 23:      */
/*  C023.C                   */
/*                           */
/*  El operador condicional  */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main()
{
  int a, b, mayor;

  printf("Escriba un número: ");
  scanf("%d", &a);
  printf("Escriba otro: ");
  scanf("%d", &b);
  mayor = (a>b) ?  a : b;
  printf("El mayor de los números es %d.\n", mayor);
    
  return 0;
}

Un segundo ejemplo, que sume o reste dos números según la opción que se escoja, sería:

/*---------------------------*/
/*  Ejemplo en C nº 24:      */
/*  C024.C                   */
/*                           */
/*  Operador condicional - 2 */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main()
{
  int a, b, resultado;
  int operacion;

  printf("Escriba un número: ");
  scanf("%d", &a);
  printf("Escriba otro: ");
  scanf("%d", &b);
  printf("Escriba una operación (1 = resta; otro = suma): ");
  scanf("%d", &operacion);
  resultado = (operacion == 1) ?  a-b : a+b;
  printf("El resultado es %d.\n", resultado);
    
  return 0;
}

Ejercicios propuestos:

3.1.10. switch

Si queremos ver varios posibles valores, sería muy pesado tener que hacerlo con muchos “if” seguidos o encadenados. La alternativa es la orden “switch”, cuya sintaxis es

switch (expresión)
{
   case valor1: sentencia1;
     break;
   case valor2: sentencia2;
     sentencia2b;
     break;
   ...
   case valorN: sentenciaN;
     break;
   default:
     otraSentencia;
};


Es decir, se escribe tras “switch” la expresión a analizar, entre paréntesis. Después, tras varias órdenes “case” se indica cada uno de los valores posibles. Los pasos (porque pueden ser varios) que se deben dar si se trata de ese valor se indican a continuación, terminando con “break”. Si hay que hacer algo en caso de que no se cumpla ninguna de las condiciones, se detalla tras “default”.

Vamos con un ejemplo:

/*---------------------------*/
/*  Ejemplo en C nº 25:      */
/*  C025.C                   */
/*                           */
/*  La orden “switch”        */
/*                           */
/*  Curso de C,              */
/*    Nacho Cabanes          */
/*---------------------------*/

#include 

int main()
{
  char tecla;

  printf("Pulse una tecla y luego Intro: ");
  scanf("%c", &tecla);
  switch (tecla)
  {
    case ' ': printf("Espacio.\n");
              break;
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '0': printf("Dígito.\n");
              break;
    default:  printf("Ni espacio ni dígito.\n");
  }
      
  return 0;
}

Ejercicios propuestos: