Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Estas en el tema de ¿Es error mío?Si es así, ¿cómo puedo solucionarlo? en el foro de C/C++ en Foros del Web. Hola, me estoy iniciando en esto del C++ y me gustaría que me resolviéseis una duda. El programa en el que trabajo es bastante simple ...
  #1 (permalink)  
Antiguo 20/10/2015, 09:13
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Pregunta ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Hola, me estoy iniciando en esto del C++ y me gustaría que me resolviéseis una duda.
El programa en el que trabajo es bastante simple y consiste en codificar o decodificar una letra o un número respectivamente, no según ASCII, sino según una tabla que contiene del 0 al 51, haciendo coincidir 'A' con '0' y las demás letras por orden empezando por las mayúsculas y siguiéndoles las minúsculas para acabar con 'z' con '51'. El programa funciona a la perfección, pero al seleccionar 'D' para decodificar e introducir como número '%' el programa me interpreta que he introducido '0', cuando debería mostrar 'Opción no válida'. ¿Por qué pasa esto? Gracias por adelantado.

Os dejo el código:

#include <iostream>
using namespace std;


int main()
{
int a;
char opcion,b;

cout<<"D/d. Decodificar"<<endl;
cout<<"C/c. Codificar"<<endl;

cout<<"Seleccione una opcion"<<endl;
cin>>opcion;
switch(opcion)
{
case 'd':
case 'D': cout<<"Dime el numero: "<<endl;
cin>>a;
if (0<=a && a<=51)
{ //Del 65 al 122 en ASCII hay 6 numeros que no corresponden a letras//
if (0<=a && a<=25)
b='A'+a;
else
b='G'+a;
cout<<"El numero "<< a<<" decodificado es: "<<b<<endl;
}


else cout<<"Opcion no valida"<<endl; break;
case 'c':
case 'C': cout<<"Dime el caracter: "<<endl;
cin>>b;
if ('A'<=b && b<='z')
{
if ('A'<=b && b<='Z')
a=b-'A';
if ('a'<=b && b<='z')
a=b-'G';
cout<<"El caracter "<<b<<" codificado es: "<<a<<endl;
}

else cout<<"Opcion no valida"<<endl; break;


default: cout<<"Opcion no valida"<<endl;
}
return 0;
}
  #2 (permalink)  
Antiguo 20/10/2015, 09:44
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Buenas.

Lo primero bienvenido al foro.

Antes de comentar tu problema te aviso, el código tiene que ir decorado con la etiqueta del lenguaje correspondiente. Mira el combobox "Highlight" y verás la lista de lenguajes.

Vale, ahora tu problema.

Código C++:
Ver original
  1. int opcion;
  2. cin>>opcion;

Ese código va a almacenar un int en opción... si no se introduce un número válido, entonces almacenará un 0. Da igual lo que introduzcas... si cin no puede convertir la entrada a número almacenará un 0. ¿Cómo detectar esa situación?

Bueno, hay una sobrecarga que te indica si la operación ha podido completarse de forma correcta:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4.   std::cout << "ERROR";

El problema es que después de un error el buffer se queda con basura, lo que provocará que el programa empiece a funcionar raro. La solución pasa por limpiar el buffer de entrada cuando se produzca un error:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4. {
  5.   std::cout << "ERROR";
  6.   cin.clear();
  7.   cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  8. }

clear limpia los bits de error, la siguiente línea elimina caracteres del buffer de entrada hasta que encuentre un salto de línea '\n'. Si no encuentra un salto de línea borrará tantos caracteres como se indica en ese chorizo que te voy a detallar:

  • streamsize es un alias del tipo de dato empleado internamente por los buffers para indizar la información. Lo normal es que sea tipo int.
  • numeric_limits es un template que permite recuperar los límites para cada tipo de dato. En este caso se está llamando a max() que contiene el valor máximo que puede ser almacenado en un tipo de dato dado... ¿qué tipo? el que determine streamsize que, como hemos dicho, suele ser int.
Es decir, en la mayoría de los casos el ejemplo se podría simplificar a:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4. {
  5.   std::cout << "ERROR";
  6.   cin.clear();
  7.   cin.ignore(std::numeric_limits<int>::max(), '\n');
  8. }

¿Por qué no sustituir numeric_limits por un valor en concreto? pues porque si por ejemplo sustituyes esa llamada por 2^31-1 y compilas el programa en un entorno en el que int ocupa 2 bytes en vez de 4 acabarás teniendo problemas.

Por supuesto también tienes la opción de leer una cadena de caracteres. Entonces compruebas si la secuencia introducida se puede convertir a número y, en caso negativo mostrar un mensaje de error... hay más alternativas, pero creo que con estas dos te podrás manejar.

Un saludo.
  #3 (permalink)  
Antiguo 20/10/2015, 09:50
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Es culpa tuya. El carácter % su valor entero es 37 y entra en el rango válido. Lo que debes hacer es usar un char* y luego usas isdigit o atoi y si no es un número lo sabrás por el retorno de esas funciones.
  #4 (permalink)  
Antiguo 20/10/2015, 09:57
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por eferion Ver Mensaje
Buenas.

Lo primero bienvenido al foro.

Antes de comentar tu problema te aviso, el código tiene que ir decorado con la etiqueta del lenguaje correspondiente. Mira el combobox "Highlight" y verás la lista de lenguajes.

Vale, ahora tu problema.

Código C++:
Ver original
  1. int opcion;
  2. cin>>opcion;

Ese código va a almacenar un int en opción... si no se introduce un número válido, entonces almacenará un 0. Da igual lo que introduzcas... si cin no puede convertir la entrada a número almacenará un 0. ¿Cómo detectar esa situación?

Bueno, hay una sobrecarga que te indica si la operación ha podido completarse de forma correcta:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4.   std::cout << "ERROR";

El problema es que después de un error el buffer se queda con basura, lo que provocará que el programa empiece a funcionar raro. La solución pasa por limpiar el buffer de entrada cuando se produzca un error:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4. {
  5.   std::cout << "ERROR";
  6.   cin.clear();
  7.   cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
  8. }

clear limpia los bits de error, la siguiente línea elimina caracteres del buffer de entrada hasta que encuentre un salto de línea '\n'. Si no encuentra un salto de línea borrará tantos caracteres como se indica en ese chorizo que te voy a detallar:

  • streamsize es un alias del tipo de dato empleado internamente por los buffers para indizar la información. Lo normal es que sea tipo int.
  • numeric_limits es un template que permite recuperar los límites para cada tipo de dato. En este caso se está llamando a max() que contiene el valor máximo que puede ser almacenado en un tipo de dato dado... ¿qué tipo? el que determine streamsize que, como hemos dicho, suele ser int.
Es decir, en la mayoría de los casos el ejemplo se podría simplificar a:

Código C++:
Ver original
  1. int opcion;
  2. bool ok = std::cin >> opcion;
  3. if ( !ok )
  4. {
  5.   std::cout << "ERROR";
  6.   cin.clear();
  7.   cin.ignore(std::numeric_limits<int>::max(), '\n');
  8. }

¿Por qué no sustituir numeric_limits por un valor en concreto? pues porque si por ejemplo sustituyes esa llamada por 2^31-1 y compilas el programa en un entorno en el que int ocupa 2 bytes en vez de 4 acabarás teniendo problemas.

Por supuesto también tienes la opción de leer una cadena de caracteres. Entonces compruebas si la secuencia introducida se puede convertir a número y, en caso negativo mostrar un mensaje de error... hay más alternativas, pero creo que con estas dos te podrás manejar.

Un saludo.
Interesante lo que indicas. Yo he usado ignore () sin argumentos creo recordar ¿hay algún problema por usar ese?
  #5 (permalink)  
Antiguo 20/10/2015, 10:07
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por aguml Ver Mensaje
Es culpa tuya. El carácter % su valor entero es 37 y entra en el rango válido. Lo que debes hacer es usar un char* y luego usas isdigit o atoi y si no es un número lo sabrás por el retorno de esas funciones.
37 no está incluído en el rango de valores que puede tomar b, sí a, pero luego este se suma a otro y 37 no es una posible solución
  #6 (permalink)  
Antiguo 20/10/2015, 10:11
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Gracias a los 2 de todos modos chicos, pero básicamente lo que he usado en ese programa es lo que de momento he aprendido en clase y no creo que haya de darle a este pequeño inconveniente una solución que ni siquiera llego a comprender del todo. Lamento no haberlo especificado en el mensaje principal.Gracias
  #7 (permalink)  
Antiguo 20/10/2015, 10:15
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

No tienes claro lo que haces:
Código C++:
Ver original
  1. if (0<=a && a<=51)
  2. { //37 es mayor que 0 y menor que 51 así que entra
  3.    if (0<=a && a<=25)
  4.       //Cómo 37 es mayor que 25 ira al else
  5.    else
  6.       b='G'+a; //Aquí llega con el 37 por lo tanto nunca te dirá que % es inválido con tu metodo
  #8 (permalink)  
Antiguo 20/10/2015, 10:17
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por la_acheron Ver Mensaje
37 no está incluído en el rango de valores que puede tomar b, sí a, pero luego este se suma a otro y 37 no es una posible solución
Si tu introduces el símbolo del porcentaje '%' y cin lo intenta almacenar en un int, NO VA A PODER porque cin no está interpretando un valor ASCII que deba convertir a número, sino que está cogiendo un caracter literal y dicho caracter no se corresponde con un dígito numérico. En este caso, cin genera un error y te almacena un 0.

Cita:
Iniciado por aguml Ver Mensaje
Interesante lo que indicas. Yo he usado ignore () sin argumentos creo recordar ¿hay algún problema por usar ese?
Código C++:
Ver original
  1. istream& ignore (streamsize n = 1, int delim = EOF);

Si lo pones sin parámetros te borrará un único caracter por vez...

Un saludo.
  #9 (permalink)  
Antiguo 20/10/2015, 10:24
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por aguml Ver Mensaje
No tienes claro lo que haces:
Código C++:
Ver original
  1. if (0<=a && a<=51)
  2. { //37 es mayor que 0 y menor que 51 así que entra
  3.    if (0<=a && a<=25)
  4.       //Cómo 37 es mayor que 25 ira al else
  5.    else
  6.       b='G'+a; //Aquí llega con el 37 por lo tanto nunca te dirá que % es inválido con tu metodo
Puede que no, pero no veo lógico lo que me dices. ¿Qué más da que introduzca un 'a' con un valor no perteneciente al rango que me interesa si luego se lo sumo a 'A', que es 26??
  #10 (permalink)  
Antiguo 20/10/2015, 10:26
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por eferion Ver Mensaje
Si tu introduces el símbolo del porcentaje '%' y cin lo intenta almacenar en un int, NO VA A PODER porque cin no está interpretando un valor ASCII que deba convertir a número, sino que está cogiendo un caracter literal y dicho caracter no se corresponde con un dígito numérico. En este caso, cin genera un error y te almacena un 0.
Eso sí me cuadra, gracias por la explicación clara.
  #11 (permalink)  
Antiguo 20/10/2015, 10:30
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por la_acheron Ver Mensaje
Puede que no, pero no veo lógico lo que me dices. ¿Qué más da que introduzca un 'a' con un valor no perteneciente al rango que me interesa si luego se lo sumo a 'A', que es 26??
No entremos en discursiones que no llevan a nada.

la_acheron, el problema que tiene tu código es que es poco legible y es errático. Es normal porque estás aprendiendo, pero eso no quita para que te avisemos de ello. Al fin y al cabo si esperas vivir de esto en el futuro tienes que obligarte a mejorar.

Un código claro y legible es mucho más facil de mantener y da menos errores... además los errores en un código legible son más fáciles de detectar y de eliminar.

Tener, por ejemplo, código duplicado o que, directamente no hace nada te complica la existencia. Por ejemplo:

Código C++:
Ver original
  1. int valor;
  2. std::cin >> valor;
  3. if( valor > 0 )
  4. {
  5.   if( valor > 0 && valor < 50 )
  6.   {
  7.     if( valor > -100 || valor > -50 )
  8.        std::cout >> "BINGO!!!";
  9.   }
  10. }

¿Qué rango de valores hacen que salga la palabra BINGO!!!?

Hombre, yo casi preferiría encontrarme con algo tal que:

Código C++:
Ver original
  1. int valor;
  2. std::cin >> valor;
  3. if( valor > 0 && valor < 50 )
  4.   std::cout >> "BINGO!!!";

Seguro que es más dificil meter la pata con el segundo ejemplo.

Un saludo
  #12 (permalink)  
Antiguo 20/10/2015, 10:32
 
Fecha de Ingreso: febrero-2015
Mensajes: 404
Antigüedad: 9 años, 9 meses
Puntos: 3
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por la_acheron Ver Mensaje
Puede que no, pero no veo lógico lo que me dices. ¿Qué más da que introduzca un 'a' con un valor no perteneciente al rango que me interesa si luego se lo sumo a 'A', que es 26??
Bueno yo de c++ se muy poco porque me he centrado más en C y en este caso eferion te dio la solución. Si en vez de cin usarás scanf si que sucedería lo que te digo ya que si le indicas que será un entero y le metes un carácter lo leerá como un entero.
No me preguntes a mi que sentido tiene lo que programas tu jejeje.
  #13 (permalink)  
Antiguo 20/10/2015, 10:53
 
Fecha de Ingreso: octubre-2015
Mensajes: 6
Antigüedad: 9 años, 1 mes
Puntos: 0
Respuesta: ¿Es error mío?Si es así, ¿cómo puedo solucionarlo?

Cita:
Iniciado por eferion Ver Mensaje
No entremos en discursiones que no llevan a nada.

la_acheron, el problema que tiene tu código es que es poco legible y es errático. Es normal porque estás aprendiendo, pero eso no quita para que te avisemos de ello. Al fin y al cabo si esperas vivir de esto en el futuro tienes que obligarte a mejorar.

Un código claro y legible es mucho más facil de mantener y da menos errores... además los errores en un código legible son más fáciles de detectar y de eliminar.

Tener, por ejemplo, código duplicado o que, directamente no hace nada te complica la existencia. Por ejemplo:

Código C++:
Ver original
  1. int valor;
  2. std::cin >> valor;
  3. if( valor > 0 )
  4. {
  5.   if( valor > 0 && valor < 50 )
  6.   {
  7.     if( valor > -100 || valor > -50 )
  8.        std::cout >> "BINGO!!!";
  9.   }
  10. }

¿Qué rango de valores hacen que salga la palabra BINGO!!!?

Hombre, yo casi preferiría encontrarme con algo tal que:

Código C++:
Ver original
  1. int valor;
  2. std::cin >> valor;
  3. if( valor > 0 && valor < 50 )
  4.   std::cout >> "BINGO!!!";

Seguro que es más dificil meter la pata con el segundo ejemplo.

Un saludo

Cita:
Iniciado por aguml Ver Mensaje
Bueno yo de c++ se muy poco porque me he centrado más en C y en este caso eferion te dio la solución. Si en vez de cin usarás scanf si que sucedería lo que te digo ya que si le indicas que será un entero y le metes un carácter lo leerá como un entero.
No me preguntes a mi que sentido tiene lo que programas tu jejeje.
De acuerdo eferion, sé que he añadido líneas innecesarias, pero creí que aclararía mejor lo que intentaba hacer, de todas formas tienes razón y casi que lo elimino siendo pragmático.

Bueno aguml trabajo con lo que me dan, que es lo único que sé, y tampoco quiero profesionalizarme en ello, simplemente pasar la asignatura, y se me ocurrió que aquí me podías resolver la duda, aunque me has liado por un momento.

Gracias por responder con tanta celeridad y aclararme. Cierro tema.

Etiquetas: char, funcion, int, numero, programa
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 14:00.