Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


4.10.2  Sentencias de selección

§1  Sinopsis

Las sentencias de selección, también llamadas de control de flujo, permiten decidir entre distintos cursos de acción en función de ciertos valores.  En C++ existen tres tipos de estas sentencias de selección:

  • if...else  .
  • else if    .
  • switch   .

Recuerde que de no ser por estas sentencias, el flujo de ejecución del programa estaría siempre constreñido a la ejecución de sus sentencias en el orden en que están colocadas en el fuente.

§2  if … else

En su forma abreviada, cuando no existe la cláusula else, esta sentencia permite escoger entre ejecutar o no una sentencia, en función del resultado de una expresión lógica.  En su forma ampliada, cuando la cláusula else está presente, permite escoger entre dos opciones alternativas.

§2.1  Sintaxis

if ( <condición> )  <sentencia1>;

[ else  <sentencia2>; ]

§2.2  Descripción

  <condición> debe ser una expresión relacional ( 4.9.12) que devuelve un valor lógico, es decir, un bool ( 3.2.1b), y estar obligatoriamente entre paréntesis.  Pueden declararse variables dentro de la <condición>.  Por ejemplo, la siguiente es una sintaxis válida:

if (int val = func(arg))

   val = z ;

else  val = y;

El ámbito de la variable val incluye toda la sentencia if,  incluyendo, en su caso, el bloque <sentencia2> de else.  La cláusula else es opcional, pero no puede haber sentencias entre el if y else  Recuerde las precauciones indicadas respecto de las expresiones relacionales ( 4.9.12), ya que son motivo frecuente de error en este tipo de sentencias.

  <sentencia1>. Es una sentencia o bloque de código que se ejecuta si <condicion> se evalúa como cierto (true  !=  0).

  <sentencia2> es una sentencia o bloque de código que se ejecuta si existe un else y <condicion> resulta falso (false  ==  0)


Puesto que el if simplemente chequea el valor resultante de <condicion> (igual o desigual a cero), las dos expresiones siguientes son equivalentes:

if ( expresion )  <sentencia> ;

if ( expresion !=0 ) <sentencia> ;

La forma más general es:

if (<condicion>) {

   <sentencia1>;

}

else  {

   <sentencia2>;

}

§2.3  Ejemplos

Uno sencillo:

if (salida == 'S') break;

Otro ejemplo:

if (a > b)

   z = a;

else

   z = b;

Se podría haber escrito de forma más comprimida:

if (a > b) z = a;

else z = b;

También:

a > b ? z = a : z = b ;

o mejor aún:

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

Otro ejemplo:

if (int val = func(count)) { /* sentencias */ }

else {                     // otra vía de acción

   cout << "val es falso";

}

Puesto que la cláusula else es opcional, en los if... else anidados podría haber ambigüedad sobre a qué if corresponde un else;  esto se evita asociando el else al if más interno sin else.   Por ejemplo, en los dos trozos de código siguientes, el primero tiene una indentación que no se corresponde con la realidad lógica del programa.

// mal indentado: ------------

if ( n > 0 )

   if ( a > b )

      z = a;

else

   z = b;


// bien indentado: -----------

if ( n > 0 )

   if ( a > b )

      z = a;

   else

      z = b;

§3  else if

Estas sentencias no representan en realidad nada nuevo, solo una sucesión de if  else anidados, aunque de uso muy frecuente, por lo que haremos una consideración especial de este caso.

if ( <expresion1> )

   <sentencia1> ;

else if ( <expresion2> )

   <sentencia2> ;

else if ( <expresion3> )

   <sentencia3> ;

else

   <sentencia4> ;

En realidad, a la luz de lo expuesto en el apartado anterior, su indentación correcta sería:

if ( <expresion1> )

   <sentencia1> ;

else

   if ( <expresion2> )

      <sentencia2> ;

   else

      if ( <expresion3> )

         <sentencia3> ;

      else

         <sentencia4> ;

Las expresiones <expresion> son evaluadas correlativamente hasta que se encuentra la primera que devuelve un valor cierto ( != 0 ), en cuyo caso se ejecuta el bloque de código <sentencia> correspondiente y acaba la evaluación. En caso de que ninguna de las <expresion> sea cierta, se ejecuta la <sentencia> correspondiente al else (si existe).

§4 switch

Se trata de una sentencia condicional multi-salida en la que las decisiones se toman en función de un valor numérico entero de entre una serie de opciones posibles.  Puede existir una cláusula por defecto o bien no adoptarse ninguna acción.

§4.1  Sintaxis

switch ( <expresion> ) {

  case <const1> : <sentencia1>; [break;]

  case <const2> : <sentencia2>; [break;]

    .

    .

    .

  case <constN> : <sentenciaN>; [break;]

 [default : <sentenciaD>; ]

}

§4.2  Descripción

La sentencia switch comprueba cuando una expresión <expresion> entre paréntesis (que se traduce en un valor numérico) coincide con alguno de una serie de valores enteros constantes y diferentes  (<constX>). En cuyo caso, se ejecuta un bloque de código específico <sentencia>.  En caso de estar presente la cláusula opcional default y no existir concordancia con ninguno de los valores anteriores, se ejecuta una sentencia por defecto (<sentenciaD>).

Los valores case y default pueden aparecer en cualquier orden, aunque lo usual es colocar default al final.  Los dos puntos : después de <constX> son imprescindibles.


§4.3
  Las expresiones <constX> son expresiones constantes ( 3.2.3a) que se resuelven en un entero.  Pueden ser simples o compuestas, como se muestra en el ejemplo.

switch (c - 48) {
   case 0: case 1: case 2: case 3: case 4:

   case 5: case 6: case 7: case 8: case 9:
      cout << "Dígito" << endl;
      break;
   case 17: case 21: case 25: case 31: case 37:

   case 49: case 53: case 57: case 63: case 69:
      cout << "Vocal" << endl;
      break;
   default:
      cout << "Otro carácter" << endl;
}


§4.4   Después de ejecutado el bloque de código correspondiente a una concordancia, siguen las comprobaciones, por lo que puede ser conveniente incluir un break para abandonar el control del switch (no es necesario ningún break después de la última).  Ver ejemplo .


§4.5
  Es ilegal que la transferencia de control originada en alguna cláusula case o default se salte una declaración que incluya un inicializador implícito o explícito. A menos que la declaración esté situada en el interior de un bloque que sea saltado completamente durante la transferencia.  Ejemplo:

switch (n) {
   case 1: case 10:
      int y;            // L-3: Ok. no incluye inicialización
      cout << "Caso-1" << endl;
      break;
   case 2:
     {
      int z = 0;        // L-8: Ok. dentro de un bloque
      cout << "Caso-2" << endl;
      break;
     }
   case 3:
      int x = 3;        // L-13: Error-1
      cout << "Caso-3" << endl;
      break;
   case 4:              // L-16:
      for (int i = 0; i<4; i++)   // L-17: Error-2
      cout << "Caso-4" << endl;
      break;
   default:             // L-20:
      cout << "Resto de casos" << endl;
}


Observación: es posible que en estos casos, el error señalado por el compilador se produzca en las sentencias responsables de que la transferencia de control se salte la declaración. En el código del ejemplo, el Error-1 podría ser señalado en las sentencias L.16 y L.20, mientras que el Error-2 en la sentencia L.20. Como muestra se incluyen los mensajes obtenidos en el caso anterior con los dos compiladores:

MS Visual C++ 6.0:

xxx.cpp(16) : error C2360: initialization of 'x' is skipped by 'case' label
xxx.cpp(13) : see declaration of 'x'
xxx.cpp(20) : error C2361: initialization of 'x' is skipped by 'default' label
xxx.cpp(13) : see declaration of 'x'
xxx.cpp(20) : error C2361: initialization of 'i' is skipped by 'default' label
xxx.cpp(17) : see declaration of 'i'

GNU g++ para Windows (MinGW) anuncia:

16 ...\xxx.cpp jump to case label