Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: m@o_614 en 19 Agosto 2013, 19:52 pm



Título: verificar numeros romanos
Publicado por: m@o_614 en 19 Agosto 2013, 19:52 pm
Saludos tengo el siguiente programa que me pide que le ingrese un numero romano cualquiera, pero tengo que verificar que si sea romano y que no contenga letras que no sean I, V, X, L, M y es ahi donde tengo el problema

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TAM 7
  4.  
  5. int main()
  6. {
  7.    char romano[TAM];
  8.    printf("Dame el primer numero: ");
  9.    fgets(romano,TAM,stdin);
  10.    while(*romano++ != '\0')
  11.    {
  12.        if(*romano!='I','V','X','L','C','M')
  13.            printf("Error!! no es numero romano\n");
  14.    }
  15.    return 0;
  16. }

el error esta en el if

de antemano gracias


Título: Re: verificar numeros romanos
Publicado por: amchacon en 19 Agosto 2013, 20:12 pm
Ese if no es correcto, no puedes intercalar condiciones con una ,.

Puedes crearte un array con todas las letras del alfabeto romano y recorrerlo.


Título: Re: verificar numeros romanos
Publicado por: fabianjsm en 19 Agosto 2013, 20:22 pm
Humilde consejo: K&R


Título: Re: verificar numeros romanos
Publicado por: m@o_614 en 19 Agosto 2013, 21:19 pm
gracias amchacon seria algo como esto???:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TAM 7
  4.  
  5. int main()
  6. {
  7.    char romano[TAM],letras[]={'I','V','X','L','C','M'},*ptr,*p;
  8.    printf("Dame el primer numero: ");
  9.    fgets(romano,TAM,stdin);
  10.    ptr = romano;
  11.    p = letras;
  12.    while(*ptr++ != '\0')
  13.    {
  14.        if(*ptr++ != *p++)
  15.            printf("Error!! no es numero romano\n");
  16.    }
  17.    return 0;
  18. }

y que significa k&r?


Título: Re: verificar numeros romanos
Publicado por: eferion en 19 Agosto 2013, 21:45 pm
Código
  1. while(*ptr++ != '\0')
  2.    {
  3.        if(*ptr++ != *p++)
  4.            printf("Error!! no es numero romano\n");
  5.    }

Esto está mal... solo te va a funcionar si el caracter introducido es I ( el primero ).

Si metes una X, en cuanto llegue a esta línea la primera vez comparará I con  X y al no ser igual te va a lanzar un mensaje de error.

Tienes que comprobar TODOS los caracteres de 'letras' y si no coincide con ninguno entonces mostrar el mensaje de error.

Otra opción más sencilla podría ser:

Código
  1. if ( strchr( letras, *ptr ) == NULL ) printf("Error!! no es numero romano\n");


Título: Re: verificar numeros romanos
Publicado por: amchacon en 19 Agosto 2013, 21:49 pm
No, seria un bucle anidado.

Te lo hago con fors que me gustan más:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define TAM 7
  5.  
  6. int main()
  7. {
  8.    int i,j;
  9.    char romano[TAM],letras[]={"IVXLCM"};
  10.    printf("Dame el primer numero: ");
  11.    fgets(romano,TAM,stdin);
  12.  
  13.    for (i = 0; romano[i] != '\n';i++)
  14.    {
  15.        for (j = 0;letras[j];j++)
  16.        {
  17.            if (romano[i] == letras[j]) break;
  18.        }
  19.  
  20.        if (!letras[j]) { printf("Error! No es un numero romano: %c \n",romano[i],i);}
  21.    }
  22.  
  23.    return 0;
  24. }


Título: Re: verificar numeros romanos
Publicado por: Alien-Z en 19 Agosto 2013, 21:58 pm
Cuando se inicializan las posiciones de un array de carácteres de este modo hay que añadir manualmente el fin de cadena:

Código
  1. char romano[TAM],letras[]={'I','V','X','L','C','M'},*ptr,*p; //Este es tu código
  2. char romano[TAM],letras[]={'I','V','X','L','C','M', '\0'},*ptr,*p; //Sería así

Si actualizas la variable de control en la condición del bucle (*ptr++) te estás saltando el primer elemento del array:

Código
  1. while(*ptr++ != '\0')

Debes de hacerlo antes de terminar el bucle:

Código
  1. while(*ptr != '\0') {
  2.   ...
  3.   ptr++;
  4. }

Con ese condicional lo único que estás haciendo es comprobando si la entrada es igual a lo que hay en el array "letras[]", no si se trata de un número romano:

Código
  1. if(*ptr++ != *p++)
  2.               printf("Error!! no es numero romano\n");

Si yo meto "IVXLM" sería correcto pero si introduzco "VII" me la daría por mala cuando si es un número romano.

El ejemplo de amchacon es genial para guiarte en tu código pero me parece que se la ha pasado indicar que solo es para que lo uses como esquema porque no se deben utilizar las instrucciones break/continue para modificar el curso de una iteración en los bucles.

Código
  1. if (romano[i] == letras[j]) break;

Un saludo.


Título: Re: verificar numeros romanos
Publicado por: m@o_614 en 20 Agosto 2013, 06:00 am
aqui tengo algunas mejoras que le hice al codigo, aunque cuando le ingreso un numero romano cualquiera como: XVI, me imprime error!no es numero romano y no tengo idea de por que, ya van varias veces que lo checo

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TAM 7
  4.  
  5. int main()
  6. {
  7.    int i,j,bandera;
  8.    char romano[TAM],letras[]={'I','V','X','L','C','M','\0'},*ptr,*p;
  9.    printf("Dame el primer numero: ");
  10.    fgets(romano,TAM,stdin);
  11.    ptr = romano;
  12.    p = letras;
  13.    for(i=*ptr;*ptr!='\0';*ptr++)
  14.    {
  15.        bandera = 0;
  16.        for(j=*p;((*p!='\0')&&(bandera==0));*p++)
  17.        {
  18.            if(*ptr == *p)
  19.               bandera = 1;
  20.        }
  21.        if(bandera!=1)
  22.        {
  23.            printf("Error!No es numero romano\n");
  24.            exit(1);
  25.        }
  26.    }
  27.    return 0;
  28. }


Título: Re: verificar numeros romanos
Publicado por: amchacon en 20 Agosto 2013, 08:10 am
aqui tengo algunas mejoras que le hice al codigo, aunque cuando le ingreso un numero romano cualquiera como: XVI, me imprime error!no es numero romano y no tengo idea de por que, ya van varias veces que lo checo
fgets coge también el retorno de carro en la cadena. Por eso puse != '\n en mi código.

Quizás lo más correcto sería:

Código
  1. *ptr != '\n' && *ptr!='\0'

Porque también puede pasar que no coja la cadena entera al ser muy larga, si no coje la cadena entera tampoco cogerá el retorno de carro.

El ejemplo de amchacon es genial para guiarte en tu código pero me parece que se la ha pasado indicar que solo es para que lo uses como esquema porque no se deben utilizar las instrucciones break/continue para modificar el curso de una iteración en los bucles.
Eso ya depende del profesor, pero break/continue son sentencias totalmente válidas en la vida real.

Generalmente suelen dejar códigos más claros que hacerlas con ellas.


Título: Re: verificar numeros romanos
Publicado por: Alien-Z en 20 Agosto 2013, 10:30 am
Eso ya depende del profesor, pero break/continue son sentencias totalmente válidas en la vida real.

Generalmente suelen dejar códigos más claros que hacerlas con ellas.

Ya veo, no sabía que hubieran otras opiniones respecto a su uso. En mi facultad los profesores nos prohibían estas instrucciones debido a que utilizar un break/continue es equivalante a la instrucción goto: estás "saltando" desde un punto del bucle a otro modificando el curso de ejecución del programa. Teniendo en cuenta que los paradigmas heredan unos de otros: El paradigma orientado a objetos hereda del estructurado que a su vez hereda del secuencial, C++ es OO y Secuencial a la vez, se deben ejecutar las instrucciones sin saltos de línea.

Tú código queda claro porque hay un único break, pero si estuvieramos hablando de una aplicación un poco más compleja en la que, al permitirse el uso de break/continue, cada bucle tuviera 3 o 4, haría casi imposible su comprensión.

Cualquier opinión o debate es bienvenido. Un saludo.


Título: Re: verificar numeros romanos
Publicado por: amchacon en 20 Agosto 2013, 11:03 am
break/continue representan saltos, pero son saltos estructurados y relativamente claros. Su mala fama se debe a que pongas un break donde no debes y se salte el bucle creando errores extraños. Eso hace que su abuso sea un gran problema, como programador debes decidir si queda claro o confuso su uso en el contexto actual. Como regla general, suelo poner un solo break/continue por bucle y intento que sea al principio, porque se ven más explícitos.

En el código que he propuesto, el uso de break me permite ahorrarme el uso de una variable bandera y se ve bastante claro. Por lo que lo considero adecuado.

Los continue me parecen bastante importantes, imaginate que estas usando un for anidado:

Código
  1. for (short i = 0; i < 100;i++)
  2.   for (short j = 0; j < 100;j++)
  3.   {
  4.        // Codigo...
  5.   }

Y quieres evitar que se haga una iteracion en la cual i = j. Podrías poner algo tal que asi:

Código
  1. for (short i = 0; i < 100;i++)
  2.   for (short j = 0; j < 100;j++)
  3.   {
  4.        if (i != j)
  5.        {
  6.            // Codigo...
  7.        }    
  8.   }

Pero eso implica más llaves y más bloques de codigo. El uso de continue te permite saltarse la iteracion de una forma bastante explícita y clara:

Código
  1. for (short i = 0; i < 100;i++)
  2.   for (short j = 0; j < 100;j++)
  3.   {
  4.        if (i == j) continue;
  5.  
  6.        // Codigo...
  7.   }

los profesores nos prohibían estas instrucciones debido a que utilizar un break/continue es equivalante a la instrucción goto: estás "saltando" desde un punto del bucle a otro modificando el curso de ejecución del programa.
Ojo con ese argumento, las llamadas a función también son saltos de ejecución del programa.


Título: Re: verificar numeros romanos
Publicado por: Alien-Z en 20 Agosto 2013, 12:53 pm
Citar
Ojo con ese argumento, las llamadas a función también son saltos de ejecución del programa.

Si, pero no son saltos desde el punto de vista del programador sino del programa, cuando hablamos de la prohibición de break/continue/goto no nos referimos a que sea ineficiente realizar estos saltos sino que no son claros a la hora de trabajar el código. Si en mi programa escribo la función "dividir(..)" tanto yo como cualquier otro informático comprenderá qué estamos diviendo X entre Y independientemente de las veces que llame a esta función; sin embargo si en un bucle pongo 3 o 4 break/continue, por lo general otra persona que intente leerlo le va a costar bastante comprenderlo.

Por tanto considero que el argumento citado por los catedráticos es válido.

¿Deberíamos dejarlo en un punto intermedio y usar estas instrucciones con cabeza?, en teoría no habría problema pero igual que con el famoso goto veríamos mucho abuso, por eso gran parte de los informáticos no recomiendan incluirlas en el programa; pero por supuesto la instrucción está ahi y cada uno puede darle el uso que crea conveniente.

Un saludo.


Título: Re: verificar numeros romanos
Publicado por: m@o_614 en 21 Agosto 2013, 04:56 am
amchacon ya le puse lo que me dijiste en la condicion *ptr!= '\n' && *ptr!='\0'
y no me funciona aun, sigo teniendo el mismo problema de que aunque le ponga un numero romano me imprime que no es

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define TAM 10
  4.  
  5. int main()
  6. {
  7.    int i,j,bandera;
  8.    char romano[TAM],letras[]={'I','V','X','L','C','D','M','\0'},*ptr,*p;
  9.    printf("Dame el primer numero: ");
  10.    fgets(romano,TAM,stdin);
  11.    ptr = romano;
  12.    p = letras;
  13.    for(i=*ptr;((*ptr!='\0')&&(*ptr!= '\n'));*ptr++)
  14.    {
  15.        bandera = 0;
  16.        for(j=*p;(((*p!='\0')&&(*ptr!='\n'))&&(bandera==0));*p++)
  17.        {
  18.            if(*ptr == *p)
  19.               bandera = 1;
  20.        }
  21.        if(!bandera)
  22.        {
  23.            printf("Error!No es numero romano\n");
  24.            exit(1);
  25.        }
  26.    }
  27.    return 0;
  28. }


Título: Re: verificar numeros romanos
Publicado por: Alien-Z en 21 Agosto 2013, 11:09 am
Tiene un par de errores, te lo pongo corregido:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. #define TAM 10
  5.  
  6. int main () {
  7.  
  8.    char alfRomano[] = {'I','V','X','L','C','D','M','\0'}, entrada[TAM], *pAlfRomano, *pEntrada;
  9.    bool encontrado;
  10.  
  11.    printf("Introduce un numero: ");
  12.    fgets(entrada, TAM, stdin);
  13.  
  14.    for(pEntrada = entrada; *pEntrada != '\n'; pEntrada++) { //Bucle exterior: recorre la entrada letra por letra
  15.  
  16.        encontrado = false;
  17.        for(pAlfRomano = alfRomano; ((*pAlfRomano != '\0') && !encontrado); pAlfRomano++) { //Bucle interior: comprueba si el siguiente carácter es romano
  18.            if(*pEntrada == *pAlfRomano) encontrado = true;
  19.        }
  20.  
  21.        if(!encontrado) {
  22.            printf("No es un numero romano.\n");
  23.            exit(1);
  24.        }
  25.    }
  26.  
  27.    printf("Es un numero romano.\n");
  28.  
  29.    return 0;
  30. }
  31.  

Casos especiales:

-Si introduces la cadena vacía te la da por correcta y eso no es un número romano.
-Si introduces un número romano correcto y al final un espacio te la da por incorrecta cuando si es válida.

Esto es muy sencillo de manejar pero ya corre por tu cuenta.

Además puedes mejorar el código y añadirle reglas de la sintáxis romana como por ejemplo que no se puedan escribir más de tres carácteres iguales consecutivos: VIIII -> mal

Saludos.


Título: Re: verificar numeros romanos
Publicado por: m@o_614 en 22 Agosto 2013, 01:19 am
Saludos Alien-Z ya por fin pude encontrar el error, estaba en el puntero del segundo for, cada vez que entraba de nuevo al 2do ciclo el puntero no se reiniciaba  a la primera posicion, pero ya lo pude corregir

Código
  1. int main()
  2. {
  3.    int i,j,bandera;
  4.    char romano[TAM],letras[]={'I','V','X','L','C','D','M','\0'},*ptr,*p;
  5.    printf("Dame el primer numero: ");
  6.    gets(romano);
  7.    ptr = romano;
  8.    p = letras;
  9.    for(i=*ptr;*ptr!='\0';*ptr++)
  10.    {
  11.        bandera = 0;
  12.        for(j=0;((j<7)&&(bandera==0));j++)
  13.        {
  14.            if(*ptr == *(p+j))
  15.               bandera = 1;
  16.        }
  17.        if(!bandera)
  18.        {
  19.            printf("Error!No es numero romano\n");
  20.            exit(1);
  21.        }
  22.    }
  23.    return 0;
  24. }

muchas gracias


Título: Re: verificar numeros romanos
Publicado por: rir3760 en 22 Agosto 2013, 08:46 am
por fin pude encontrar el error, estaba en el puntero del segundo for, cada vez que entraba de nuevo al 2do ciclo el puntero no se reiniciaba  a la primera posicion, pero ya lo pude corregir
Algunos comentarios sobre ese programa:

* Faltan los encabezados.
* Si vas a imprimir una cadena en la salida estándar y esta no termina con el carácter '\n' debes vaciar su bufer de forma explicita mediante la llamada "fflush(stdout);".
* No utilices gets, la razón de ello se explica en el tema |Lo que no hay que hacer en C/C++. Nivel basico| (http://foro.elhacker.net/programacion_cc/lo_que_no_hay_que_hacer_en_cc_nivel_basico-t277729.0.html).
* Para terminar la función principal no es necesario llamar a la función exit, puedes utilizar la sentencia "return N;" con el mismo efecto.

Por ultimo como ya comento eferion se puede utilizar la función strchr (prototipo en <string.h>) para acortar el programa a un solo bucle. Mas o menos así:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. #define NUM_CHARS  7
  6.  
  7. int main(void)
  8. {
  9.   char num[NUM_CHARS];
  10.   int i;
  11.  
  12.   printf("Dame el primer numero: ");
  13.   fflush(stdout);
  14.   if (fgets(num, NUM_CHARS, stdin) == NULL)
  15.      return EXIT_FAILURE;
  16.  
  17.   for (i = 0; strchr("IVXLCDM", num[i]) != NULL; i++)
  18.      ;
  19.   if (i > 0 && (num[i] == '\n' || num[i] == '\0'))
  20.      puts("OK");
  21.   else
  22.      puts("Entrada no valida");
  23.  
  24.   return EXIT_SUCCESS;
  25. }
Con la limitante de indicar una entrada no valida si la linea empieza con espacio blanco.

Otra opción consiste en sustituir el bucle basado en strchr por una llamada a strspn.

Un saludo