You are on page 1of 27

4.

10 Sentencias C++
1 Sinopsis
Las sentencias ("Statements") especifican y controlan el flujo de ejecucin del programa. Si no
existen sentencias especficas de seleccin o salto, el programa se ejecuta de forma secuencial en
el mismo orden en que se ha escrito el cdigo fuente (es el que podramos considerar orden
"natural" de ejecucin).
En este captulo explicaremos los distintos tipos de sentencias que existen en C++, pero antes
ofreceremos una descripcin formal de las mismas sealando qu se entiende por sentencia.
2 Definicin
Una expresin es una secuencia de operadores; operandos; elementos de puntuacin y palabras
clave, que especifican una computacin. Tiene sentido computacional en s misma y equivale a
una frase en el lenguaje normal. Entre sus caractersticas distintivas estn las de poder producir un
resultado y posibles efectos laterales. Ejemplo:
extern x; // No produce un valor
y = 22; // Produce un valor
z = i++; // Valor + efectos laterales

Cualquier expresin finalizada en un punto y coma ; forma una sentencia:
< expresin >;
C++ ejecuta las sentencias evaluando la expresin. Todos los efectos colaterales de la evaluacin
son tenidos en cuenta antes de ejecutar la prxima sentencia. La mayora de sentencias C++ son
asignaciones o llamadas a funciones.
Un caso especial es la sentencia nula; consiste en un punto y coma (;) aislado. Una sentencia
nula no hace nada, pero puede ser necesaria en situaciones en que la sintaxis del lenguaje espere
una sentencia pero nuestro programa no necesita hacer nada.
Nota: como la mayora de las cosas de C++, la definicin anterior tiene su excepcin. Existe
un tipo especial de sentencia, las directivas de preproceso en las que el punto y coma
puede omitirse. Este tipo de sentencias no ejecuta una computacin de tiempo de ejecucin
sino de compilacin (realizan modificaciones sobre el fuente). Entre las que s ejecutan una
computacin en runtime tambin existe una, las etiquetas directas, que no terminan en punto y
coma sino en dos puntos : (ver a continuacin )
2 Clasificacin
Dada la definicin anterior, resulta evidente que pueden existir infinitas sentencias distintas, e
innumerables criterios para su clasificacin. Una de las posibles, que adems coincide con la
clasificacin del Estndar, distingue las siguientes clases de sentencia:
De etiqueta
De expresin
Compuestas
De seleccin
De iteracin
De salto
De declaracin
Bloques de intento
Adems de las anteriores, por sus caractersticas especiales podramos considerar las siguientes
clases adicionales:
Sentencias de preproceso
Sentencias ensamblador
2.1 Sentencias de etiqueta
En C++ existen tres clases de sentencias etiquetadas: las etiquetas directas ( 4.10.1a), las
sentencias case ( 4.10.1b) y las default ( 4.10.1c), estas ltimas se utilizan en conjuncin con
las sentencias switch.
2.2 Sentencias de expresin
Podramos decir que son las que no pertenecen a ninguno de los otros grupos y que, en la
prctica, son las ms abundantes. Generalmente son asignaciones o invocaciones de funciones.
Ejemplo:
pint = &x;
foo(c);
2.3 Sentencias compuestas
Las sentencias compuestas, tambin denominadas bloques ( 1.3.1) se utilizan en aquellas
situaciones en que la sintaxis espera una sentencia pero se necesita usar varias. Ejemplo:
if (first) ++x;
else {
--x; z = a;
}
En caso de cumplirse la condicin hay que incrementar x, lo que puede hacerse en una sola
sentencia, pero si la condicin resulta falsa, se precisan dos computaciones. Para que se
comporten como una sola frente a else, se recurre a englobarlas en un bloque entre llaves { ... }.
Las sentencias dentro del bloque se comportan como una sola y constituyen un mbito lxico. Los
identificadores definidos en su interior eclipsan a los exteriores y las variables automticas creadas
en l son destruidas al salir del mbito.
2.4 Sentencias de seleccin
Las sentencias de seleccin o de control de flujo, pueden decidir entre varios cursos de accin
distintos en funcin de ciertos valores. Existen dos tipos de estas sentencias de
seleccin: if...else ( 4.10.2) y switch ( 4.10.2).
Ejemplos:
switch ( foo() ) {
case 0: case 1:
if (first) break;
else ++x;
case 2:
...
default:
break;
}
2.5 Sentencias de iteracin
Las sentencias de iteracin permiten repetir un conjunto de sentencias ejecutando un bucle. En
C++ existen tres formas de iteraciones: los bucleswhile ( 4.10.3), dowhile ( 4.10.3) y for (
4.10.3).
Ejemplo:
while (first) {
...
for (int x = 1; x < y; ++x) {
...
do { // begin second
...
...
} while (second); // end second
...
} // end for
...
} // end first
2.6 Sentencias de salto
Las sentencias de salto permiten transferir el control del programa de forma incondicional. Existen
cuatro de estas sentencias: break ( 4.10.4),continue ( 4.10.4), ( 4.10.4) y return (
4.10.4).
Ejemplo:
while (foo) {
start:
if (some) break;
...
if (first) goto start;
...
if (second) continue;
...
if (! any) return;
...
}
Nota: en ocasiones es posible utilizar el mecanismo de excepciones C++ como mecanismo de
salto multinivel ( 1.6).
2.7 Sentencias de declaracin
Este tipo de sentencias introducen uno o ms identificadores en un bloque. Ejemplo:
void foo (int x, y z) {
float f = 3.14;
char c;
int x;
...
}
El asunto es tratado extensamente en el captulo "Declaraciones y definiciones" ( 4.1.2).
2.8 Bloques de intento
Estas sentencias deben estar seguidas de una sentencia catch y tienen la forma:
try {
...
}
Son utilizadas por el mecanismo de excepciones C++ y han sido expuestas con detalle en el
captulo correspondiente ( 1.6)
2.9 Sentencias de preproceso
Como se ha indicado, constituyen un tipo muy especial, tanto en su sintaxis como en su
comportamiento. No representan una computacin en tiempo de ejecucin (runtime), sino de
compilacin, ya que su efecto es realizar modificaciones sobre el cdigo fuente [1]. Su sintaxis
tambin es especial; no requieren el punto y coma de terminacin y comienzan siempre con el
smbolo # ( 4.9.10).
2.10 Sentencias ensamblador
C++ dispone de la opcin de poder escribir directamente instrucciones en lenguaje ensamblador
junto con el resto del cdigo fuente. Para esto dispone de una palabra clave especfica: asm.
La palabra asm indica que la cadena literal que sigue ser incluida en el cdigo objeto en la
posicin indicada.
La sintaxis empleada depende del compilador. En el caso de C++Builder, es la siguiente:
asm <opcode> <operandos> <; o NL>
Ejemplo
asm pop dx;
asm push ebx;
asm call @@std@%basic_ostream$c19std@%char_traits$c%%@put$qc;
asm add esp,8;
asm push ebx;
Se permite que varias instrucciones ensamblador pueden ser agrupadas en un solo bloque
precedido por el indicador asm. Ejemplo:
asm {
mov ax, 0x0e07;
xor bx, bx;
int 0x10;
}

La sintaxis empleada por el compilador C++ GNU para Windows utilizado por Dev-C++ no utiliza
la sintaxis de Intel, sino la de AT&T.
Ejemplo [2]:
int AdrIO; // variable global
static char ValIO; // variable global

void foo() {
__asm("mov _AdrIO, %dx") ; // cargar un registro de 16 bits
__asm("mov _ValIO, %al") ; // cargar un registro de 8 bits
__asm("mov %ax,%dx") ; // mover contenido registro AX a DX
}
Nota: no olvidar incluir el guin bajo ("underscore") precediendo los nombres de variables
globales.
Ni que decir tiene que cualquier cdigo ensamblador insertado mediante asm, es especfico, y por
tanto dependiente, de la plataforma sobre la que se ejecutar el programa. Este tipo de sentencias
deben reducirse al mximo si queremos facilitar la portabilidad del cdigo.
Temas relacionados
Estructura lgica de un programa: Sentencias y Expresiones ( 1.3.1)
Sintaxis de las sentencias C++ ( 1.3.1a)
Sintaxis de las expresiones C++ ( 1.3.1b)
4.10.1 Sentencias de etiqueta
1 Sinopsis
Recordemos ( 1.2.1) que en C++ las sentencias pueden estar provistas de un identificador
o etiqueta que sirve para identificarlas como destino de algunas sentencias de salto.
Las sentencias C++ pueden ser etiquetadas de dos formas:
a. Mediante una etiqueta directa:
etiqueta-identificativa:
b. Las sentencias case y default (que se utilizan en conjuncin con switch) en la forma:
case expresion-constante : sentencia
default : sentencia
2 Etiqueta directa
Una etiqueta ("Label") es un identificador seguido de dos puntos ( : ). Sigue las mismas reglas que
los identificadores del resto de entidades del programa ( 3.2.2) y su mbito es el de la funcin en
que ha sido definida. Sirve de destino para la sentencia goto ( 4.10.4) de salto incondicional.
Ejemplo
Destino: // esta es la etiqueta
;
...
goto Fin; // Ok la etiqueta estara ms adelante
...
goto Destino; // salta a la etiqueta
3 case
La sentencia case se utiliza en conjuncin con switch para determinar en que sentencia debe
continuar la ejecucin del programa de entre una serie de puntos posibles. Se trata por tanto de
una sentencia de salto condicionado.
3.1 Sintaxis
switch ( <variable switch> ){
case <expresion constante> : <sentencia>; [break;]
...
default : <sentencia>;
}
3.2 Descripcin
<expresion constante> debe evaluarse a un int y ser un valor nico dentro de los
posibles case del bloque switch (no deben existir valores duplicados).
Las diversas <expresion constante> del bucle son evaluadas, y sus valores comparados con
el de la <variable switch>. Si no existe ninguna concordancia la ejecucin sigue en la
sentencia default. En cambio, si se encuentra una coincidencia entre ambas, se ejecuta
la<sentencia> correspondiente y la ejecucin contina en este punto. Por esta razn, si no se
desea que se ejecuten el resto de las sentenciascase, a continuacin de la que propicia la
concordancia, deben incluirse instrucciones break ( 4.10.4) para saltar al final del bloque.
4 default
La sentencia default se utiliza en los bloques switch junto con los case. Si no existe concordancia
de la <variable switch> con ninguno de los valores case, se ejecuta la sentencia por defecto,
sealada por default.
4.1 Sintaxis
switch ( <variable switch> ){
case <expresion> : <sentencia>; [break;]
.
.
.
default : <sentencia>;
}
4.2 Descripcin
Los valores case y default pueden aparecer en cualquier orden, aunque lo usual es
colocar default al final. Ver ejemplo .
La sentencia default es opcional dentro del bloque switch. Si no existe concordancia con
ningn case y no existe sentencia default, entonces la ejecucin contina en la siguiente
sentencia despus del bloque switch. Es decir, no se ejecuta ninguna sentencia del mismo.
5 Ejemplo:
En este cdigo se muestra el uso de las palabras reservadas break, case, default y switch
#include <conio.h>
#include <iostream>
using namespace std;

int main(void) { // ===================
int ch;
cout << "Presione a, b, O c. Cualquier otra termina el programa" <<
endl
for ( /* BUCLE INFINITO */; ((ch = getch()) != EOF); )
switch (ch) {
case 'a' : // La seleccin 'a' tiene su propio caso
cout << "Seleccionado " << 'a' << endl;
break;
case 'b' : // Es lo mismo seleccionar 'b' o 'c'
case 'c' :
cout << "Seleccionado 'b' o 'c'" << endl;
break;
default :
cout << "SELECCION NO VALIDA! Adios..." << endl;
return(-1);
}
return(0);
}

Comentario
El bloque switch funciona como una sola sentencia para el bucle exterior for. Cada vez que se
pulsa una tecla, es el bucle switch el que decide el curso de la accin. Las sentencias break (
4.10.4) hacen saltar fuera del bucle switch, volviendo por tanto al bucle for, que espera hasta
la sigiente pulsacin en el teclado.
4.10.2 Sentencias de seleccin
1 Sinopsis
Las sentencias de seleccin, tambin llamadas de control de flujo, permiten decidir entre distintos
cursos de accin en funcin de ciertos valores. En C++ existen tres tipos de estas sentencias de
seleccin:
if...else .
else if .
switch .
Recuerde que de no ser por estas sentencias, el flujo de ejecucin del programa estara siempre
constreido a la ejecucin de sus sentencias en el orden en que estn colocadas en el fuente.
2 if else
En su forma abreviada, cuando no existe la clusula else, esta sentencia permite escoger entre
ejecutar o no una sentencia, en funcin del resultado de una expresin lgica. En su forma
ampliada, cuando la clusula else est presente, permite escoger entre dos opciones alternativas.
2.1 Sintaxis
if ( <condicin> ) <sentencia1>;
[ else <sentencia2>; ]
2.2 Descripcin
<condicin> debe ser una expresin relacional ( 4.9.12) que devuelve un valor lgico, es
decir, un bool ( 3.2.1b), y estar obligatoriamente entre parntesis. Pueden declararse variables
dentro de la <condicin>. Por ejemplo, la siguiente es una sintaxis vlida:
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 clusula 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 cdigo que se ejecuta si <condicion> se
evala como cierto (true != 0).
<sentencia2> es una sentencia o bloque de cdigo 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 ms 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 podra haber escrito de forma ms comprimida:
if (a > b) z = a;
else z = b;
Tambin:
a > b ? z = a : z = b ;
o mejor an:
z = (a > b ? a : b);
Otro ejemplo:
if (int val = func(count)) { /* sentencias */ }
else { // otra va de accin
cout << "val es falso";
}
Puesto que la clusula else es opcional, en los if... else anidados podra haber ambigedad sobre
a qu if corresponde un else; esto se evita asociando el else al if ms interno sin else. Por
ejemplo, en los dos trozos de cdigo siguientes, el primero tiene una indentacin que no se
corresponde con la realidad lgica 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 sucesin de if else anidados,
aunque de uso muy frecuente, por lo que haremos una consideracin 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 indentacin correcta sera:
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
cdigo <sentencia> correspondiente y acaba la evaluacin. 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 funcin de
un valor numrico entero de entre una serie de opciones posibles. Puede existir una clusula por
defecto o bien no adoptarse ninguna accin.
4.1 Sintaxis
switch ( <expresion> ) {
case <const1> : <sentencia1>; [break;]
case <const2> : <sentencia2>; [break;]
.
.
.
case <constN> : <sentenciaN>; [break;]
[default : <sentenciaD>; ]
}
4.2 Descripcin
La sentencia switch comprueba cuando una expresin <expresion> entre parntesis (que se
traduce en un valor numrico) coincide con alguno de una serie de valores
enteros constantes y diferentes (<constX>). En cuyo caso, se ejecuta un bloque de cdigo
especfico <sentencia>. En caso de estar presente la clusula 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 : despus 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 << "Dgito" << 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 carcter" << endl;
}

4.4 Despus de ejecutado el bloque de cdigo 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 ningn break despus de la ltima). Ver
ejemplo .

4.5 Es ilegal que la transferencia de control originada en alguna clusula case o default se salte
una declaracin que incluya un inicializador implcito o explcito. A menos que la declaracin 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 inicializacin
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;
}

Observacin: es posible que en estos casos, el error sealado por el compilador se produzca en
las sentencias responsables de que la transferencia de control se salte la declaracin. En el cdigo
del ejemplo, el Error-1 podra ser sealado 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
4.10.3 Sentencias de iteracin
1 Sinopsis
Las sentencias de iteracin permiten repetir una sentencia o conjunto de ellas. Es lo que se
denomina ejecutar un bucle. En C++ existen tres formas de iteraciones: los
bucles while; dowhile y for.
Observe que en todos los casos el bucle puede estar constituido por una sola sentencia o por
varias. En cuyo caso se trata de un bloque de cdigo delimitado por un par de corchetes { } (
3.2.6). Si se trata de una sola sentencia, los corchetes no son necesarios.
2 Bucle while
La sentencia while permite ejecutar repetidamente un bloque de cdigo mientras se cumpla una
determinada condicin que es chequeada antes de cada iteracin.
2.1 Sintaxis
while ( <condicion> ) <sentencia> ;
2.2 Descripcin
La sentencia while ejecuta iterativamente el bucle definido por el bloque de
cdigo <sentencia> siempre que el valor devuelto por la expresin<condicin> (que debe
estar entre parntesis) sea cierto.
Nota: recordemos que cierto (true) equivale numricamente a distinto de cero ( 3.2.1b),
mientras que falso (false) equivale al valor cero.
Puesto que la condicin se evala antes que cada ejecucin del bucle, si al
comienzo <condicion> devuelve falso, <sentencia> no se ejecuta ninguna vez, y el control
pasa a la siguiente sentencia. Si <condicin> devuelve cierto se ejecuta el
bucle <sentencia>, y a continuacin se vuelve a evaluar <condicion> con lo que se repite el
ciclo.
2.3 Ejemplos
while (*p == ' ') p++;
while ( i <= j) i++;
La sentencia puede estar vaca, realizndose entonces toda la computacin requerida en la
clusula <condicin>. Ejemplo:
while ( getchar() != 'Z' );
Aunque lo normal es que la <sentencia> sea un bloque de cdigo entre corchetes:
while (i < n) {
cout << i << endl;
++i;
}

Intente por s mismo la explicacin de las salidas del programa adjunto antes de leer el comentario
final (esta disposicin es muy utilizada en bucles que deben repetirse un nmero n de veces).
#include <iostream>
using namespace std;

int main() { // ==========
int x = 5, y = 5;

while ( x-- ) {
cout << "x = " << x << endl;
}

while ( --y ) {
cout << " y = " << y << endl;
}

cout << "Terminado!!" << endl;
}
Salida:
x = 4
x = 3
x = 2
x = 1
x = 0
y = 4
y = 3
y = 2
y = 1
Terminado!!
Comentario
En ambas iteraciones, la condicin indicada en el parntesis es chequeada antes de ejecutar la
iteracin (la salida en pantalla). La diferencia entre ambos es que el postdecremento (x--) se
realiza despus de la evaluacin del parntesis (comprobacin de que su contenido es cierto). En
consecuencia, el ciclo del primer bucle es como sigue:
1. comprobacin de que x es cierto (distinto de cero). El resultado, que denominaremos R,
es un bool.
2. decremento unitario de x
3. dos posibilidades:
1. R == true ejecutar el bucle (salida en pantalla) volver al punto 1.
2. R == false abandonar el bucle.
En cambio, en el segundo bucle, el predecremento (--x) se realiza antes de la evaluacin del
parntesis (comprobacin de la condicin del bucle). En consecuencia, el ciclo del segundo bucle
puede resumirse as:
1. decremento unitario de x
2. comprobacin de que x es cierto (distinto de cero). El resultado, que denominaremos R,
es un bool.
3. dos posibilidades:
1. R == true ejecutar el bucle (salida en pantalla) volver al punto 1.
2. R == false abandonar el bucle.
3 Bucle do...while
La sentencia do ... while permite ejecutar repetidamente un bloque de cdigo mientras se cumpla
una determinada condicin que es chequeadadespus de cada iteracin.
3.1 Sintaxis
do <sentencia> while ( <condicin> );
3.2 Descripcin
La sentencia do ejecuta repetidamente el bucle definido por el bloque de
cdigo <sentencia> hasta que la sentencia de control <condicin>devuelve el valor falso.
Puesto que el control se evala despus de cada ejecucin del bucle, resulta que este se
ejecuta al menos una vez, aunque <condicin>devuelva el valor falso desde el principio (si
requiere que el bucle no se ejecute ninguna vez, es mejor utilizar while).
La forma ms genrica de la expresin suele ser:
do {
<sentencia> ;
} while ( <condicin> );
3.3 Ejemplo
Este programa solicita una clave de acceso indefinidamente hasta que el usuario proporciona una
que coincide con el valor almacenado en la matriz checkword.
#include <stdio.h>
#include <string.h>

int main () { // ===================
char checkword[80] = "password";
char password[80] = "";
do {
printf ("Introducir clave: ");
scanf("%s", password);
} while (strcmp(password, checkword));
return 0;
}
Nota: C++ no dispone en ninguna de sus sentencias de bucle de la opcin loop (o similar),
como la ofrecida por otros lenguajes para saltar al principio desde cualquier punto de la
iteracin. No obstante, ofrece alternativas que pueden servir para el caso. Ver las
sentenciasgoto y continue en el siguiente captulo ( 4.10.4).

A continuacin se muestra un caso simtrico al presentado para los bucles while , que utiliza los
operadores unitarios de decremento. Intente explicar por s mismo las salidas obtenidas antes de
leer el comentario:
#include <iostream>
using namespace std;

int main() { // ========
int x = 5, y = 5;

do {
cout << "x = " << x << endl;
} while ( x-- );

do {
cout << "y = " << y << endl;
} while ( --y );

cout << "Terminado!!" << endl;
}
Salida:
x = 5
x = 4
x = 3
x = 2
x = 1
x = 0
y = 5
y = 4
y = 3
y = 2
y = 1
Terminado OK!!
Comentario
En este caso, las el bloque de cdigo (salida en pantalla) es ejecutado antes del chequeo de la
condicin expresada en el parntesis. La diferencia entre ambos bucles es que en el primero, el
postdecremento (x--) se realiza despus de la evaluacin del parntesis (comprobacin de que su
contenido es cierto). En consecuencia, el ciclo es como sigue:
1. ejecutar el bloque de cdigo (salida en pantalla)
2. comprobacin de que x es cierto (distinto de cero). El resultado, que denominaremos R,
es un bool.
3. decremento unitario de x
4. dos posibilidades:
1. R == true volver al punto 1.
2. R == false abandonar el bucle.
En cambio, en el segundo bucle, el predecremento (--x) se realiza antes de la evaluacin del
parntesis (comprobacin de la condicin del bucle). En consecuencia, su ciclo puede resumirse
as:
1. ejecutar el bloque de cdigo (salida en pantalla)
2. decremento unitario de x
3. comprobacin de que x es cierto (distinto de cero). El resultado, que denominaremos R,
es un bool.
4. dos posibilidades:
1. R == true volver al punto 1.
2. R == false abandonar el bucle.
4 Bucle for
Esta sentencia permite realizar un bucle repetidamente en base a una condicin, la cual suele
estar basada en el valor de un contador que se actualiza despus de cada ejecucin del bucle.
4.1 Sintaxis
for ( [<inicio>] ; [<condicion>] ; [<incremento>] ) <sentencia>
4.2 Descripcin
La sentencia for realiza un bucle iterativo, es equivalente al:
for <inicio> to <condicin> step <incremento>
<sentencia>
next
de otros lenguajes. <inicio> e <incremento> pueden ser llamadas a funciones o sentencias de
asignacin. <sentencia> es del cuerpo del bucle, y puede ser cualquier bloque de cdigo.
La utilizacin ms comn suele adoptar la forma:
for ( <inicio> ; <condicin> ; <incremento> ) {
<sentencia>;
}
Ejemplo
for(i=0; i<n; i++) { /* sentencias del bucle */ }
<inicio> inicia las variables para el bucle antes de la primera iteracin. Puede ser una
expresin o una declaracin. El ejemplo que sigue sera correcto en C++:
for (int i=0; i<10; i++) printf("i =%5.0d\n", i);
En cambio, para compilarlo en C sera necesario declarar i en una expresin anterior:
int i;
for (i=0; i<10; i++) printf("i =%5.0d\n", i);
El mbito de una variable definida en la expresin <inicio> es variable, depende del interruptor -
Vd del compilador .
<condicin> Debe ser una expresin relacional (devuelva un valor lgico). Es comprobada
antes de la primera ejecucin del bloque<sentencia>, que es ejecutado repetidamente hasta
que <condicin> sea falso, por lo que si <condicin> devuelve falso desde el principio, el
bucle no se ejecuta nunca.
<incremento>. Despus de cada iteracin del bucle, <incremento> incrementa un contador
de bucle; en consecuencia j++ es funcionalmente equivalente a ++j.
<sentencia> es el bucle de for; sentencia o bloque de cdigo que se ejecuta iterativamente.
El mbito de cualquier identificador declarado dentro l se limita al final de la sentencia de control.
Todas las expresiones son opcionales, pero los separadores ; no pueden faltar. Si
falta <condicin>, se supone que es siempre cierta, por lo que se trata de un bucle indefinido del
que se saldr por otro mecanismo externo al propio for, que pueden ser un break ( 4.10.4) o
un return ( 4.10.4). Es tpico utilizar este tipo de construcciones para construir bucles con una o
ms condiciones de salida:
for ( ; ; ) { // bucle infinito del que se sale con varias
// condiciones mediante diversas tcnicas
...
if ( C == 'f' ) break;
...
if ( C == 'd' ) break;
...
if ( C == 'x' ) return;
...
if ( C == 'z' ) throw (false);
}
4.3 Ejemplos
Funcin que lee una lnea (por teclado) y devuelve su longitud. Utiliza una
expresin <condicin> del for compuesta; lim es la longitud mxima que puede ser leda.
int getLine (char s[], int lim) {
int c, i;
for (i = 0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; i++) s[i]=c;
if (c == '\n') {
++i;
...
}
...
}

Bucle indefinido (de una sola sentencia) que espera la pulsacin de una tecla:
for( ; ; ) if(getch()!=0) break; // break sale del bucle
equivale a:
for( ; ; ) {
if(getch()!=0) break;
}
Tema relacionado
Sentencias de salto: break, continue, goto y return 4.10.4
Tener presente la advertencia sealada en 4.9.12.
5 Opcin de compilacin -Vd
El compilador C++Builder dispone de una opcin -Vd ( 1.4.3), que permite alterar el mbito de
las variables declaradas en la expresin<inicio>. Si est desconectado (por defecto), l mbito
se limita solo al interior del bloque <sentencia>. Si est activada (se compila con -Vd), el mbito
se extiende al interior del bloque que contiene al for.
Al compilar el ejemplo que sigue con las opciones por defecto, se obtiene un error: Smbolo
indefinido para el identificador i por la sentencia que est fuera del bucle. Si se compila con -
Vd, la compilacin se realiza sin problema.
int main(void) {
{ // comienzo del bloque que contiene al for.
for(int i=0; i<10; i++) {
cout << "Dentro del bucle, i = " << i << endl;
} //final del bloque <sentencia>
cout << "Fuera del bucle, i = " << i << endl; //error sin -Vd
} //final del bloque que contiene el for
}
4.10.4 Sentencias de salto
1 Sinopsis
Las sentencias de salto permiten transferir el control del programa de forma incondicional. Existen
cuatro de estas sentencias: break , continue , goto y return .
Nota: aunque en los textos no suele aparecer recogido en este epgrafe, existe una quinta
posibilidad de realizar saltos de forma incondicional utilizando el mecanismo de
excepciones throw/catch ( 1.6). Entiendo que est ah para utilizarlo (con las debidas
precauciones) cuando se considere necesario.
2 break
La sentencia break se usa para salir de forma incondicional de los bucles do, for y while, as
como de las sentencias switch de multi-dicisin. Hay que tener en cuenta que en el caso de
bucles anidados, break hace salir del bucle interior (ver nota a continuacin).
2.1 Sintaxis
break;
Ejemplo:
switch (c) {
case 0:
cout << "Falso" << endl;
break;
default:
cout << "Cierto" << endl;
}
Ver otro ejemplo ( 4.10.1)
Nota: al contrario que otros lenguajes, C++ no dispone de la opcin break (n) para definir el
nmero de niveles que se saltarn hacia fuera en el caso de bucles anidados.
3 continue
La sentencia continue se utiliza en los bucles for, while y do...while. En los primeros el control
salta al final del bucle, con lo que el contador se incrementa y comienza otra comprobacin. En
los while, el control pasa inmediatamente a la condicin de control.
3.1 Sintaxis:
continue;

3.2 Descripcin
continue suele utilizarse cuando la lgica del bucle es complicada, de forma que establecer una
nueva condicin y un nuevo nivel de indentacin puede volver esta demasiado profunda.
3.3 Ejemplo
void main () {
for (i = 0; i < 20; i++) {
if (array[i] == 0)
continue;
array[i] = 1/array[i];
}
}
4 goto
goto es una sentencia de salto incondicional dentro del mbito de una funcin.
4.1 Sintaxis
goto <etiqueta> ;
4.2 Descripcin
La sentencia goto permite transferir el control de ejecucin a la etiqueta especificada por el
identificador <etiqueta> (las etiquetas terminan siempre en dos puntos : 4.10.1). Recordar
que la etiqueta debe estar en la misma funcin que el goto (el mbito de las etiquetas se limita a la
funcin en que son declaradas).
4.3 Comentario
Aunque en tiempos fue muy popular y los programas estaban llenos de "gotos" con saltos cuyos
destinos eran la mayora de las veces etiquetas numricas (el nmero de lnea de la instruccin a
la que se quera saltar), podramos afirmar sin rubor que actualmente se trata de la sentencia
maldita. Ningn programador medianamente "elegante" emplear jams un goto. Incluso existen
lenguajes que simplemente no disponen de esta instruccin tan "hortera".
C++ y otros lenguajes disponen de esta sentencia aunque se considera que debe ser evitada.
Sobre todo porque la secuencia lgica del cdigo resulta difcil de entender ( Ejemplo), aunque a
veces es de utilidad para salir de bucles anidados en los que el break no es suficiente. Por
ejemplo en condiciones de error.
Como botn de muestra de la opinin que merece esta sentencia a algunos autores, adjuntamos
una de ellas respetando el original ingls. Aunque se refiere al lenguaje Perl, podra ser
perfectamente aplicable a C++:
"If you want to really mess around with the structure of your programs, you can use goto LABEL to
jump anywhere in your program. Whatever you do, don't do this. This is not to be used. Don't go
that way.
I'm telling you about it for the simple reason that if you see it in anyone else's Perl, you can laugh
heartily at them.... But goto with a label is to be avoided like the plague... Don't use it unless you
really, really, really understand why you shouldn't. And even then, don't use it. Larry Wall has never
used goto with a label in Perl, and he worte it. Don't. (He's watching)" [1].
4.4 Ejemplo
void foo() {
Again: // esta es la etiqueta
...
goto Again; // Ok. salto a la etiqueta
...
}
void faa() {
...
goto Final: // Ok. salto a la etiqueta
...
Final:
goto Again; // Error!! destino en otra funcin
...
}

4.5 Con los goto hay que observar las mismas precauciones sealadas para las sentencias de
seleccin ( 4.10.2). Es ilegal que la transferencia de control a la etiqueta se salte una
declaracin que incluya un inicializador implcito o explcito, a menos que la declaracin est
situada en el interior de un bloque que sea saltado completamente durante la transferencia.
Ejemplo:
void foo() {
...
goto Caso-1 // Salto a la etiqueta
int y; // Ok. no incluye inicializacin
C c; // Ok. no incluye inicializacin explcita [2]
{
int z = 0; // Ok. dentro de un bloque
}
int x = 3; // Error!!
for (int i=0; i<10; i++) // Error!!
...;
...
Caso-1: // Etiqueta
...
}

4.6 El salto a posiciones anteriores a la declaracin de un objeto automtico ( 4.1.5) implica la
destruccin del objeto en el sitio en que se origina el salto. En consecuencia, situaciones como la
que sigue implican la destruccin del objeto, lo que se realiza mediante una invocacin al
constructor incluida automticamente por el compilador.
void foo() {
Inicio:
X x;
...
goto Inicio; // invocacin del destructor de x!!
}
Ejemplo:
#include <iostream>
using namespace std;

int tot = 0;
struct E {
int x;
~E() { // destructor
cout << "Destruyendo objeto" << endl;
tot++;
}
};

int main() { // ================
int n = 2; // L1:
Inicio:
goto Evalua;
Sigue:
if (n <= 0) goto Termina;
E e1; // L6:
goto Inicio; // L7: invocacin al destructor e1.~E()
Evalua:
--n;
goto Sigue;
Termina:
cout << "Se han destruido " << tot << " objetos" << endl;
return 0;
}
Salida:
Destruyendo objeto
Destruyendo objeto
Destruyendo objeto
Se han destruido 3 objetos
Destruyendo objeto
Comentario
Desde luego, el resultado es sorprendente a primera vista. Para entender el (a mi entender
diablico ;-) comportamiento del compilador, puede hacerse n = 0 en la sentencia L.1 y ejecutar
el programa. El resultado no es menos sorprendente aunque revelador:
Destruyendo objeto
Se han destruido 1 objetos
Destruyendo objeto
En este caso estamos seguros que el programa no ha tenido ocasin de ejecutar las sentencias
L6/L7. Sin embargo, se han destruido (y por tanto creado previamente) dos objetos. Es fcil
deducir que la ltima salida corresponde a la destruccin que ocurre antes de salir de la
funcin main, cuando se invocan los destructores de todos los objetos automticos definidos en
dicho mbito. Sin embargo las dos construcciones (y la destruccin previa) no son tan evidentes.
La explicacin es que este tipo de saltos transfiere el control de la ejecucin, pero el compilador
supone que ha recorrido el mbito lxico de las sentencias atravesadas, y la creacin y destruccin
de objetos est relacionada con este recorrido. El esquema muestra grficamente el proceso (las
sentencias ejecutadas se han sealado con x):
int main() { // ================
int n = 0; // L1bis:
Inicio:
goto Evalua; -----|
Sigue: | ---------------------------
if (n <= 0) goto Termina; |R1 ^ x
E e1; | | |
goto Inicio; | |R2 |
Evalua: V | |R3
--n; x | |
goto Sigue; ------- |
Termina: V
cout << "Se han destruido " << tot << " objetos" << endl; x
return 0; x
}
El primer recorrido (R1) crea una instancia del objeto, que es destruida en el segundo (R2), ya que
este transfiere el control a una posicin anterior a la de declaracin. El tercer recorrido (R3) vuelve
a crear un objeto (es la misma situacin que en R1). Finalmente el objeto es destruido al salir el
programa del mbito de main.
Puede realizarse una ltima comprobacin encerrando la sentencia L6 en un bloque, de forma que
el recorrido lxico no incluya a su interior en el mbito:
{ E e1; } // L6bis:
En este caso la salida es:
Se han destruido 0 objetos
5 return
La sentencia return devuelve el control de ejecucin desde la funcin que contiene el return a la
rutina que la invoc; opcionalmente puede devolver un valor.
5.1 Sintaxis
return [ <expresion> ] ;
5.2 Descripcin
La sentencia return devuelve el control de ejecucin desde la funcin que contiene el return a la
rutina que la invoc. Adems, opcionalmente puede devolver un valor (contenido
en <expresion>).
<expresion> es opcional, as como el parntesis que se suele colocar, aunque no es necesario.
Si no se indica <expresion> la funcin no devuelve nada.
Ms informacin en: Funciones: "Valores devueltos" ( 4.4.7)
5.3 Ejemplo
double sqr(double x) {
return (x*x);
}
4.10.5 Sentencias de expresiones con coma
1 Sinopsis
En ocasiones las sentencias contienen expresiones con coma, que describimos a continuacin;
convirtindose as en bloques de cdigo, ya que cada subexpresin de la expresin con coma se
ejecuta como una entidad separada.
2 Expresiones con coma
Las expresiones con coma son conjuntos de subexpresiones separadas por coma, que aqu es
un operador ( 4.9.5), y agrupadas por parntesis. Cada subexpresin se evala una a
continuacin de otra empezando por la izquierda, el resultado es el valor de la ltima.
Ejemplos
sum = (i = 3, i++, i++); // sum = 4, i = 5
func(i, (j = 1, j + 4), k); // llama func con 3 argumentos (i,5,k) no 4
func(i, j); // llama func con dos argumentos
func((exp1, exp2), (exp3, exp4, exp5)); // dem con dos argumentos

Los siguientes pares de expresiones son equivalentes:
(a, b) += 12;
(a, b += 12);

&(a, b);
(a, &b);
Nota: no deben confundirse la expresiones con coma, de las que separan los parmetros de
las funciones (donde la coma se usa comopuntuador 3.2.6). Aunque es legal mezclar
ambos usos, para evitar ambigedades, es necesario emplear parntesis, como en los
ejemplos anteriores.
3 Comentario
Como una pincelada de los usos que pueden darse a estas expresiones, a continuacin
mostramos un ejemplo tomado de un caso real, encontrado en un programa Windows de un
reconocido autor. En el fuente leemos las siguientes sentencias (sin ninguna explicacin
adicional):
case WM_DESTROY: // Window is being destroyed
return HANDLE_WM_DESTROY (hwnd, wParam, lParam,
mainFrame_OnDestroy);
aqu los valores hwnd, wParam y lParam estn perfectamente identificados (son frecuentsimos
en los programas que utiliza la API de Windows), pero la expresin en s misma resulta un tanto
extraa, ya que aparenta ser la invocacin de una funcin cuyo nombre es inusual (parece una
constante), y en principio HANDLE_WM_DESTROY no aparece en ninguna otra parte del fuente ni en
la documentacin de la API de Windows. Por su parte, mainFrame_OnDestroy es una funcin
cuya definicin en el mismo fuente, tiene el siguiente aspecto:
static void mainFrame_OnDestroy (HWND hwnd) {
/* ... */
}
Una bsqueda ms concienzuda nos muestra que HANDLE_WM_DESTROY es un define situado en
el fichero de cabecera windowsx.h:
#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) ((fn)(hwnd), 0L)
En consecuencia, una vez que el pre-procesador ha realizado las sustituciones oportunas, las
sentencias originales se traducen en:
case WM_DESTROY: // Window is being destroyed
return (mainFrame_OnDestroy(hwnd), 0L);
La segunda lnea es una expresin con coma, cuya primera subexpresin es una invocacin
a mainFrame_OnDestroy, y la segunda es un longde valor cero (0L), que es el resultado (el
valor realmente devuelto). As pues, las sentencias originales equivalen a lo siguiente:
case WM_DESTROY: // Window is being destroyed
mainFrame_OnDestroy (hwnd);
return 0L;

4.11 Clases
1025

You might also like