402y37
Sentencias de salto
Como vimos al hablar sobre las etiquetas, los programas C++ se ejecutan secuencialmente, pero existen formas de romper este orden secuencial, mediante el uso de sentencias de salto, que veremos a continuación.
Sentencia de ruptura
El uso de esta sentencia dentro de un bucle, una sentencia de selección o de un bloque, transfiere la ejecución del programa a la primera sentencia que haya a continuación. Esto es válido para sentencias switch, como vimos hace un rato, pero también lo es para sentencias while, do...while, for e if.
En general, una sentencia break transfiere la ejecución secuencial a la siguiente sentencia, abandonando aquella en que se ejecuta.
Sintaxis:
break |
Ejemplo:
int c = 0;
{
for(int x=0; x < 100; x++) c+=x;
break;
c += 100;
}
c /= 100; |
En este ejemplo, la sentecia c += 100; no se ejecutará, ya que la sentencia break transfiere la ejecución secuencial fuera del bloque.
Otro ejemplo:
y = 0;
x = 0;
while(x < 1000)
{
if(y == 1000) break;
y++;
}
x = 1; |
En este otro ejemplo el bucle no terminaría nunca si no fuera por la línea del break, ya que x no cambia. Después del break el programa continuaría en la línea x = 1.
Sentencia continue
El uso de esta sentencia dentro de un bucle ignora el resto del código de la iteración actual, y comienza con la siguiente, es decir, se transfiere la ejecución a la evaluación de la condición del bucle. Sintaxis:
continue |
Ejemplo:
y = 0;
x = 0;
while(x < 1000)
{
x++;
if(y >= 100) continue;
y++;
} |
En este ejemplo la línea y++ sólo se ejecutaría mientras y sea menor que 100, en cualquier otro caso el control pasa a la siguiente iteración, con lo que la condición del bucle volvería a evaluarse.
Sentencia de salto
Con el uso de esta sentencia el control se transfiere directamente al punto etiquetado con el identificador especificado.
Nota: El goto es un mecanismo que está en guerra permanente, y sin cuartel, con la programación estructurada. Las sentencias goto no se deben usar cuando se resuelven problemas mediante programación estructurada, se incluye aquí porque existe, pero siempre puede y debe ser eludido. Existen mecanismos suficientes para hacer de otro modo todo aquello que pueda realizarse con mediante goto.
En cualquier caso, nosotros somos los programadores, y podemos decidir que para cierto programa o fragmento de programa, las ventajas de abandonar la programación estructurada pueden compensar a los inconvenientes. A veces es imperativo sacrificar claridad en favor de velocidad de ejecución. Pero de todos modos, serán situaciones excepcionales. |
Sintaxis:
goto <identificador> |
Ejemplo:
x = 0;
Bucle:
x++;
if(x < 1000) goto Bucle; |
Este ejemplo emula el funcionamiento de un bucle for como el siguiente:
for(x = 0; x < 1000; x++); |
Sentencia de retorno
Esta es la sentencia de salida de una función, cuando se ejecuta, se devuelve el control a la rutina que llamó a la función.
Además, se usa para especificar el valor de retorno de la función. Sintaxis:
return [<expresión>] |
Ejemplo:
int Paridad(int x)
{
if(x % 2) return 1;
return 0;
} |
Este ejemplo ilustra la implementación de una función que calcula la paridad de un valor pasado como parámetro. Si el resto de dividir el parámetro entre 2 es distinto de cero, implica que el parámetro es impar, y la función retorna con valor 1. El resto de la función no se ejecuta. Si por el contrario el resto de dividir el parámetro entre 2 es cero, el parámetro será un número par y la función retornará con valor cero.
Es importante dejar siempre una sentencia return sin condiciones en todas las funciones. Esto es algo que a veces no se tiene en cuenta, y aunque puede no ser extrictamente necesario, siempre es conveniente. El ejemplo anterior se podría haber escrito de otro modo, sin tener en cuenta esto:
int Paridad(int x)
{
if(x % 2) return 1;
else return 0;
} |
En este caso, para nosotros está claro que siempre se ejecutará una de las dos sentencias return, ya que cada una está en una de las alternativas de una sentencia if...else. Sin embargo, el compilador puede considerar que todas las sentencias return están en sentencias de selección, sin molestarse en analizar si están previstas todas las salidas posibles de la función, con lo que puede mostrar un mensaje de error.
El primer ejemplo es mejor, ya que existe una salida incondicional. Esto no sólo evitará errores del compilador, sino que nos ayudará a nosotros mismos, ya que vemos que existe un comportamiento incondicional.
El único caso en que una sentencia return no requiere una expresión es cuando el valor de retorno de la función es void.
Existe un mal uso de las sentencias return, en lo que respecta a la programación estructurada. Por ejemplo, cuando se usa una sentencia return para abandonar una función si se detecta un caso especial:
int Dividir(int numerador, int denominador)
{
int cociente;
if(0 == denominador) return 1;
cociente = numerador/denominador;
return cociente;
} |
Esta función calcula el cociente de una división entera. Pero hemos querido detectar un posible problema, ya que no es posible dividir por cero, hemos detectado ese caso particular, y decidido (erróneamente) que cualquier número dividido por cero es uno.
Sin embargo, en este caso, el primer return se comporta como una ruptura de secuencia, ya que se abandona la función sin procesarla secuencialmente. Siendo muy puristas (o pedantes), podemos considerar que esta estructura no corresponde con las normas de la programación estructurada. Un ejemplo más conforme con las normas sería:
int Dividir(int numerador, int denominador)
{
int cociente;
if(0 == denominador) cociente = 1;
else cociente = numerador/denominador;
return cociente;
} |
Sin embargo, a menudo usaremos estos atajos para abandorar funciones en caso de error, sacrificando el método en favor de la claridad en el código.
Uso de las sentencias de salto y la programación estructurada
Lo dicho para la sentencia goto es válido en general para todas las sentencias de salto. En el caso de la sentencia break podemos ser un poco más tolerantes, sobre todo cuando se usa en sentencias switch, donde resulta imprescindible. En general, es una buena norma huir de las sentencias de salto.
Comentarios
Los comentarios no son sentencias, pero me parece que es el lugar adecuado para hablar de ellos. En C++ pueden introducirse comentarios en cualquier parte del programa. Su función es ayudar a seguir el funcionamiento del programa durante la depuración o en la actualización del programa, además de documentarlo. Los comentarios en C, que también se pueden usar en C++, se delimitan entre /* y */, cualquier cosa que escribamos en su interior será ignorada por el compilador.
Sólo está prohibido su uso en el interior de palabras reservadas, de identificadores o de cadenas literales. Por ejemplo:
int main(/*Sin argumentos*/void) |
está permitido, pero sin embargo:
int ma/*función*/in(void) |
es ilegal.
Esto no es una limitación seria, a fin de cuentas, se trata de aclarar y documentar, no de entorpecer la lectura del código.
En C++ existe otro tipo de comentarios, que empiezan con //. Estos comentarios no tienen marca de final, sino que terminan cuando termina la línea. Por ejemplo:
int main(void) // Esto es un comentario
{
return 0;
} |
El cuerpo de la función no forma parte del comentario.
Palabras reservadas usadas en este capítulo
break, case, continue, default, do, else, for, goto, if, return, switch y while.
Ir al Principio