Sei sulla pagina 1di 19

UNIVERSIDAD DE EL SALVADOR

FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA


CÁTEDRA DE INFORMÁTICA

CARRERA : LICENCIATURA EN INFORMÁTICA EDUCATIVA


ASIGNATURA : INTRODUCCIÓN A LA PROGRAMACIÓN
CICLO : II–2018
GUÍA DE LABORATORIO #6 : MANEJO DE EXCEPCIONES
FECHA DE REALIZACIÓN : Domingo 1 de diciembre de 2018
LUGAR DE REALIZACIÓN : CENTRO DE CÓMPUTO DE LAS SEDES

OBJETIVOS
Que el estudiante al finalizar el laboratorio #6 pueda:

• Conocer qué son las excepciones y cómo se manejan en C++.


• Conocer el funcionamiento de las Excepciones en C++.
• Saber en qué momento se pueden aplicar las Excepciones en C++.
• Tener la capacidad de manejar el comportamiento anómalo en programas
realizados en C++, haciendo uso de las Excepciones.

Introducción
Uno de los aspectos que con más dificultad se abordan en los distintos lenguajes de programación, es
el correcto tratamiento de los errores. Es decir, el funcionamiento normal de un algoritmo o programa
contiene la dificultad inherente del problema que se quiere resolver y como consecuencia se generará
un flujograma más o menos complicado. Sin embargo, todo ello se incrementa en complejidad de
forma notable en el momento en que se pretende verificar y comprobar los posibles errores o
situaciones “no nominales” durante el proceso de ejecución.

Este problema no es solo específico de la ingeniera de software, sino que a menudo es el mayor
quebradero de cabeza en la mayoría de los proyectos de diseño y en particular aquellos en los que la
seguridad es importante. Lo complicado empieza por predecir las situaciones que pueden provocar

Página 1 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

errores a la hora de ejecutar el programa. Luego, diseñar el método para tratar a cada una de estas
situaciones.
Al conjunto de situaciones imprevistas se le denomina “excepción”, y al mecanismo dispuesto para
reaccionar ante estas situaciones, se le denomina “manejo de excepciones”. Existen muchos tipos
de excepciones, por ejemplo: error para grabar en un archivo por disco lleno, memoria insuficiente,
operaciones no validas como división por cero, abrir un archivo sobre el que no se tiene permisos
suficientes, entre otros.

En este laboratorio abordaremos el capítulo 9: Manejo de excepciones. Veremos 8 ejemplos que


pretenden mostrar el tratamiento de los distintos tipos de errores que se pueden dar en la ejecución
de un programa y el lugar desde donde es lanzada la excepción. Al final encontrará un ejercicio
propuesto para ser desarrollado y presentado 8 días después de realizado el laboratorio.

Comportamiento anómalo del programa


En general, todo programa fue creado para hacer algo específico y el programador es responsable
directo de que así sea, a través de la creación, compilación y depuración del código. No obstante, a
veces, los programas se comportan de forma errónea bajo ciertas circunstancias. Por ejemplo, si el
programa pide la introducción de un dato positivo y el usuario escribe un valor negativo, éste hecho
tan sencillo no invalida el funcionamiento del programa, pero sí la validez de sus resultados. En
consecuencia, dejar que el programa se ejecute a pesar de que los resultados van a ser erróneos no
tiene ningún sentido, por lo tanto, es tarea del programador prever en qué ocasiones se puede
producir un hecho anómalo.

El comportamiento anómalo se identifica con errores en tiempo de ejecución. Cada programa es


diferente y tiene sus problemas particulares, pero, en general, aquellas ocasiones en que un programa
puede conducir a un comportamiento anómalo y es conveniente tener en cuenta y acotar son:

1. Errores en la introducción de datos


Este tipo de error es muy común entre los usuarios de un programa, sobre todo si los datos
se leen de un archivo con un formato específico. Puede suceder en un porcentaje muy alto
Página 2 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

de casos que no existan suficientes campos con datos, o bien que el orden no sea el correcto,
incluso que las magnitudes sean incorrectas; en cualquiera de estas situaciones el programa
debe ser capaz de detenerse e informar al usuario del error en la lectura de los datos. En
ocasiones y para ciertos tipos de programas, es recomendable establecer un valor por defecto
de todas las variables para evitar que el programa se detenga, aunque siempre se debe avisar
de que algunos valores se han inicializado por defecto.

2. Errores de división entre cero


Lógicamente es una situación que hará estallar el programa deteniendo su ejecución. Para
evitar este inconveniente se deberá siempre comprobar que el divisor es distinto de cero
antes de realizar la operación. Si éste fuera el caso, el programador puede avisar del error,
evitar la operación y continuar el programa, o bien detenerlo si fuera imprescindible dicha
operación. En este último caso se debe avisar al usuario de los motivos por los cuales se
produce el error, tal vez una introducción de datos incorrecta, etc.

3. Errores con punteros


Este tipo de errores es muy problemático y difícil de detectar. Por ello la programación de
punteros es un arma de doble filo; mejoran la velocidad, pero si están mal programados el
error cuesta mucho de detectar. Posibles fuentes de error con punteros son: mala asignación,
no inicialización y sin reserva de memoria dinámica. Es importante gestionar bien la memoria
dinámica y evitar punteros innecesarios incluyendo funciones ya definidas en la librería.

4. Errores de salida en un bucle


Este error es responsabilidad directa del programador, ocurre cuando el incremento del
contador está mal gestionado, o bien cuando existe una condición lógica imposible. En este
caso el programa suele quedarse ‘colgado’ ejecutando la misma sentencia. No son errores
peligrosos porque el compilador o el sistema siempre permite cortar los bucles infinitos
mediante una tecla especial, sin embargo, son de difícil gestión por parte del mismo
programa.
Página 3 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

5. Errores en condicionales
Este error también depende de una mala programación, en general alguna condición lógica
no contemplada. Por ello siempre es conveniente utilizar un else para hacer algo en cualquier
otro caso. Es importante que los if, switch o while condicionales cierren todas las puertas.

6. Conversiones
A veces se realizan comparaciones lógicas de igualdad entre tipos diferentes, por ejemplo, int
y double. También se puede ejecutar una función pasando un argumento que no es del tipo
prototipado. En general estos problemas se pueden manejar definiendo conversiones entre
los tipos creados por el usuario. En cualquier caso, se debe tener constancia de que una
conversión se realiza y de verificar su correcta ejecución.

El buen diseño de un programa pasa por detectar y evitar el funcionamiento anómalo. En general, un
buen programador tiene en cuenta las posibles aberraciones que pueden darse: no inicialización de
variables o punteros, datos erróneos, etc. y da un tratamiento a cada uno de ellos. Una buena
estrategia pasa por programar cada función de manera que detecte sus errores, haga algo y retorne
un código con información del estado en el que se ha acabado una determinada operación. En función
del error será conveniente detener el programa o, por el contrario, continuar con su ejecución.

El retorno de un código de error significa que se tendrá que clasificar y tratar a través de alguna
estrategia tipo switch y, dado que los programas suelen ser largos, normalmente habrá muchos
códigos de error diferentes, por lo que la complejidad del tratamiento puede ser grande. En cualquier
caso, se deben de tener estrategias que tengan una lista de códigos de error y salidas difíciles de
controlar.

Excepciones
En C++ se define excepción como un mensaje de anomalías en tiempo de ejecución, es decir, algo
para avisar al propio programa de una posible fuente de error como la división entre cero, el
direccionamiento incorrecto, entre otros. Un programa fiable debe controlar estas excepciones y

Página 4 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

actuar en consecuencia para evitar errores en los resultados. El C++ (a partir de la versión 3.0) dispone
de un manejador de excepciones.

Tratamiento de excepciones.
El concepto de excepción, ligado al del comportamiento anómalo o no deseable del programa, tiene
una clara metodología de tratamiento en C++. Básicamente, hay que seguir el siguiente
procedimiento:

• En primer lugar, detectar el posible error y, una vez que se produce, lanzar la excepción.
• En segundo lugar, una vez se ha lanzado, se debe recoger en alguna parte del programa y
darle un tratamiento.

El tratamiento de excepciones C++ sigue un proceso estructurado, por lo que a la hora de diseñarlo
se diferencian tres conceptos básicos:

1. El bloque de prueba: try


La definición de un bloque try sirve para delimitar la zona de código donde se puede producir una
situación anómala (excepción). El bloque try va a intentar algo; si sale bien el código continúa, si no
se lanza una excepción.

2. El lanzamiento de la excepción: throw


Cuando se detecta una circunstancia extraña o anómala (una excepción), se informa al proceso,
función, o programa que ha ocurrido algo imprevisto, y se interrumpe el curso normal de ejecución.
Para realizarlo se "lanza" una excepción (throw). Esa excepción es un objeto que contiene información
sobre el error para que el que la recoja sea capaz de reaccionar ante esta situación.

3. La recogida: catch
La sentencia catch permite recoger la excepción lanzada en la zona de intento y darle un tratamiento.
Si el error es muy grande, el bloque catch cerrará todos los archivos, liberará memoria, etc., antes de

Página 5 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

terminar el programa y escribir el último mensaje de error. Si el error es pequeño, únicamente


escribirá un aviso y continuará con el proceso. A veces, dentro del bloque no se puede resolver el
problema, entonces se deberán realizar otros lanzamientos o dejar que otro bloque capture la
excepción. De hecho, cuando definimos un catch estamos indicando que en ese nivel se recogerá
cualquier error que se haya producido por debajo de él.

Dependiendo del tipo de throw, se entra en el catch apropiado; si hubiera diferentes tipos de error se
realizarían diferentes capturas. Para ello, se siguen las mismas normas que las definidas para la
sobrecarga de funciones y, por lo tanto, se empieza a comparar en el orden en el que están puestos
los catch. Cuando uno coincide con el tipo de throw, se ejecuta y se obvian todos los demás hasta el
siguiente bloque ejecutable que no sea un catch.

En el fondo el mecanismo es un mecanismo de salto controlado. Al código encargado de reaccionar


ante una determinada excepción se lo denomina "manejador" de la excepción.

Hay que destacar que no puede haber más de un error en curso en un momento dado, ya que cuando
se hace un lanzamiento se va subiendo de nivel hasta que se trata y en último caso hasta salir del
main ( ).

// Ejemplo de un programa que dará error sin identificarlo


#include <iostream>
using namespace std;

int main() {
int *x = NULL;
int y = 1000000000000;

x = new int[y];
x[10] = 0;
cout << "Puntero: " << (void *) x << endl;
delete[] x;

return 0;
}

Página 6 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #1:
Solución al problema anterior mediante al uso de manejo de excepciones, específicamente sobre el
uso del try, throw y catch.

// Ejemplo anterior utilizando manejo de excepciones


#include <iostream>

using namespace std;

int main() {
int *x;
int y = 1000000000000;

try {
x = new int[y];
x[0] = 10;
cout << "Puntero: " << (void *) x << endl;
delete[] x;
}
catch(std::bad_alloc&) {
cout << "Memoria insuficiente" << endl;
}

return 0;
}

Página 7 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #2:
Realizar un programa que permita poder realizar una notificación de una excepción desde una función
fuera del bloque try.

// Notificacion de una excepcion desde una funcion fuera del bloque try.

#include "iostream"
using namespace std;

void Xtest(int test)


{
cout << "Dentro de la Funcion Xtest, la prueba es: " << test << "\n";
if(test)
{
throw test;
}
}

int main()
{
cout << "Inicio\n";
try
{
cout << "Estamos dentro del bloque try \n";
Xtest(0);
Xtest(0);
Xtest(10);
Xtest(0);
Xtest(0);
Xtest(0);
}
catch (int i)
{
cout << "Error capturado --su valor es: ";
cout << i << "\n";
}
cout << "Fin";
return 0;
}

Página 8 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #3:
Realizar un programa que permita el uso del try/catch desde una misma función.

#include "iostream"

using namespace std;

// try/catch pueden estar en una funcion.


void Xhandler(int test)
{
try
{
if(test)
{
throw test;
}
}
catch(int i)
{
cout << "Capturada exepcion numero: " << i << '\n';
}
}

int main()
{
cout << "Inicio\n";
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
Xhandler(0);
Xhandler(0);
Xhandler(0);
Xhandler(0);
Xhandler(0);
Xhandler(10);
cout << "Fin";
return 0;
}

Página 9 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #4:
Realizar un programa que permita el uso de varias sentencias catch; o sea, la captura de distintos tipos
de excepciones.

#include <iostream>
using namespace std;
void Xhandler(int test)
{
try
{
if(test)
{
throw test;
}
else
{
throw "El valor es cero";
}
}
catch(int i)
{
cout << "Capturada excepcion numero: " << i << '\n';
}
catch(const char *str)
{
cout << "Capturada un string: ";
cout << str << '\n';
}
}

int main()
{
cout << "Inicio\n";
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << "Fin";
return 0;
}

Página 10 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #5:
Realizar un programa que mediante el uso de una sola sentencia catch, permita la captura de todas
las excepciones.

// Capturando todas las excepciones.


#include "iostream"

using namespace std;

void Xhandler(int test)


{
try
{
if(test==0) throw test; // throw int
if(test==1) throw 'a'; // throw char
if(test==2) throw 123.23; // throw double
}
catch(...)
{
cout << "- Excepcion capturada!!!\n";
}
}

int main()
{
cout << "Inicio\n";
Xhandler(0);
Xhandler(1);
Xhandler(2);
cout << "Fin";
return 0;
}

Página 11 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #6:
Realizar un programa que mediante el uso de una sola sentencia catch, identifique que se ha
capturado un entero; así mismo, que mediante el uso de una sola sentencia catch permita la captura
de todas las demás excepciones.

// Usando catch(...) como defecto


#include "iostream"
using namespace std;

void Xhandler(int test)


{
try
{
if(test==0) throw test; // throw int
if(test==1) throw 'a'; // throw char
; if(test==2) throw 123.23; // throw double
}

catch(int i)
{ // catch an int exception
cout << "Capturado un entero\n";
}
catch(...)
{ // catch all other exceptions
cout << "- Excepcion capturada!!!\n";
}
}

int main()
{
cout << "Inicio\n";
Xhandler(0);
Xhandler(1);
Xhandler(2);
cout << "Fin";
return 0;
}

Página 12 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #7:
Realizar un programa que permita poder realizar la división de dos números, y que cuando su
denominador sea igual a cero (0) le haga saber al usuario a través de un mensaje: “No se puede dividir
entre cero”, utilice Excepciones y Funciones para resolver dicho problema. Así mismo, que el
programa finalice cuando el usuario ingrese un cero (0) al numerador.

#include "iostream"

using namespace std;

void dividir(double a, double b);

int main()
{
double i, j;

do
{
cout << "Numerador (Digite 0 para parar): ";
cin >> i;
cout << "Denominador: ";
cin >> j;
dividir(i, j);
} while(i != 0);

return 0;
}

void dividir(double a, double b)


{
try
{
if(!b) throw b;
cout << "Resultado: " << a/b << endl;
}

catch (double b)
{
cout << "No se puede dividir entre cero.\n";
}
}

Página 13 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #8:
Suponga el caso de un programa para resolución de ecuaciones de segundo grado del tipo ax2+bx+c=0.
Se desean controlar dos tipos de posible error: que el coeficiente del término de segundo grado (a)
sea 0, y que la ecuación tenga soluciones imaginarias (b2-4ac<0). Para ello, se realiza la llamada a la
función de resolución raíces dentro de un bloque try y al final de éste se define catch que se activará
si el programa pasa por alguna de las sentencias throw que están incluidas en la función raíces. Realice
un programa que resuelva el planteamiento anterior para los valores a, b y c introducidos por el
usuario.

#include "iostream"
#include <math.h>

using namespace std;


//prototipos de funciones

void raices(const double a, const double b, const double c);

enum error{NO_REALES,PRIMERO};

main()

{
double a, b, c;

try
{
cout << "\nIngrese el valor de a: " ; cin >> a;
cout << "\nIngrese el valor de b: " ; cin >> b;
cout << "\nIngrese el valor de c: " ; cin >> c;
raices(a, b, c); //dentro de raices se lanza la excepcion

}
catch(error e)
{//e es una variable enum de tipo error
switch(e)
{
case NO_REALES:
cout<<"\nRaices no reales"<<endl;
break;
Página 14 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

case PRIMERO:
cout<<"\nPrimero nulo"<<endl;
break;
}
}
}
void raices(const double a, const double b, const double c)
{
double disc, r1,r2;
if(b*b<4*a*c)
throw NO_REALES; //se lanza un error
if(a==0)
throw PRIMERO;
disc=sqrt(b*b-4*a*c);
r1 =(-b-disc)/(2*a);
r2 = (-b+disc)/(2*a);
cout<<"\nLas raices son:"<<r1<<" y "<<r2<<endl;
}

Página 15 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejemplo #9:
Realizar un programa que haga uso del manejo de excepciones y obtenga el logaritmo de un número
cualquiera, tanto el número como la base deben ser introducidos por el usuario.
Tenga en cuenta lo siguiente:
a) La función logaritmo está definida solo para los reales positivos.
b) La base del logaritmo debe ser mayor que 0 y distinta de 1.
c) Puede aplicar la técnica del “cambio de base” para la obtención de logaritmos de base
arbitraria (para ello deberá hacer uso de la función log de la librería matemática de C++)
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h> // Libreria para utilizar la funcion matematica "log()"

using namespace std;

enum error{NO_REALES, NO_BASE}; // Declaracion de tipo de errores

int main()
{
int base;
double numero, resultado;

try
{
cout<<"INGRESE EL NUMERO PARA CALCULAR EL LOGARITMO: ";
cin >>numero;
cout<<endl;
cout<<endl;
cout<<"INGRESE LA BASE DEL LOGARITMO: ";
cin >>base;
cout<<endl;
cout<<endl;
if(numero <=0 ) throw NO_REALES; // Lanza error en caso que el número no sea real positivo
if(base <=0 or base==1) throw NO_BASE; // Lanza error en caso que la base no sea mayor que cero y
diferente de uno

resultado = log(numero)/log(base); // Calcula logarimo con la tecnica "Cambio de base"


}
catch(error e)
{
switch(e)
Página 16 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

{
case NO_REALES:
// Captura error
cout<<"\nEl valor del numero debe ser positivo"<<endl; // Imprime mensaje
return 0;
// Finaliza programa
break;

case NO_BASE:
cout<<"\nEl valor de la base debe ser positiva diferente de uno"<<endl;
return 0;
break;
}
}

cout << "EL LOGARITMO DE "<<numero<<" EN BASE "<<base<<" ES: "<<resultado; // Imprime
Resultado
return 0;
}

Página 17 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Ejercicios propuestos:
Desarrolle correctamente los ejercicios que se plantean a continuación. Recuerde que el objetivo es
poner en práctica lo visto en este laboratorio y que usted aprenda a programar; en ese sentido, le
sugerimos que se esmere en resolverlos por cuenta propia y le haga saber a su tutor cualquier
inquietud que se presente. ¡¡¡Buena suerte!!!

Ejercicio #1: Realice un programa que haga uso del manejo de excepciones para determinar si tres
lados ingresados por él usuario pueden formar un triángulo.
Utilice el siguiente código (haciendo las modificaciones respectivas).

#include <iostream>
#include <cmath>

using namespace std;

int main(){
double a, b, c;

cout<< "Ingrese el primer lado"<< endl;


cin>>a;
cout<< "Ingrese el segundo lado"<< endl;
cin>>b;
cout<< "Ingrese el tercer lado"<< endl;
cin>>c;

if(a<= b+c && b<= a+c && c<= a+b && a>= abs(b-c) && b>= abs(a-c) && c>= abs(a-b))

cout<<"Los valores ingresados si pueden construir un triangulo."<<endl;

else
cout<<"Los valores ingresados no pueden construir un triangulo."<<endl;
}

Tome en cuenta las siguientes salidas:

Página 18 de 19
UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS NATURALES Y MATEMÁTICA
CÁTEDRA DE INFORMÁTICA

Nota: El documento a subir será una carpeta con su número de carné, en dicha carpeta colocará todos los
códigos de los ejercicios y el documento del reporte en Word, a continuación, comprima la carpeta en zip
y súbala al link correspondiente en la plataforma virtual. Por favor lea la rúbrica completa para saber que
debe llevar el documento del reporte.

Página 19 de 19

Potrebbero piacerti anche