Switch con cadena

Iniciado por Xedrox, 28 Septiembre 2013, 20:07 PM

0 Miembros y 2 Visitantes están viendo este tema.

Xedrox

Buenas gente, tengo que hacer un programa que reciba por consola los siguientes parametros:

1: - Campo
2: - Otro valor sin importancia para el problema que tengo..

Parte del codigo del programa va ser con un switch de acerdo al valor del campo, pero este es un string y no puedo ponerlo en un switch alguna idea? No puedo usar if/else ya que hay mas de 500 opciones y volveria muy ineficiente el programa. Trate de hacer una funcion que dado el string devuelva un valor entero, pero no puedo hacer lo siguiente


switch(strToInt(campo))
{
        case strToInt("Opcion1"):   //Aca no me deja poner un metodo a pesar que el mismo devuelve int
                      ....
                      break;
             
         ....

}



Muchas gracias
Saludos!

eferion

Normalmente cuando se hace programa un menú no se le obliga al usuario a introducir "opcion 1"... sino simplemente "1" o "C", por ejemplo.

Además tienes varias incoherencias o malos diseños:

* switch(strtoint(campo)) : internamente, switch se va a codificar como varios ifs en serie, luego poner dentro del switch una instrucción va a obligar al compilador a llamar a esa función una vez por cada case que pongas. es mejor ponerlo así:

int valor = strToInt( campo );
switch ( valor )
{
  ...
}


* case strToInt("Opcion1"): En el case sólo se pueden poner valores estáticos, es decir:


switch ( valor )
{
  case 1:
    ...
  case 2:
    ...
}


* strToInt("Opcion1"); Esto directamente no funciona. strtoint recibe una cadena de texto que contiene caracteres numéricos y lo convierte a su representación en binario... pero como es fácil ver, "opcion1" no es una cadena con caracteres numéricos... eso no es un número. ejemplos de llamadas correctas:


char* numero1 = "123";

int valor1 = strToInt( numero1 );
int valor2 = strToInt( "456" );

Xedrox

Para para para, tratemos de no irnos del foco del programa. Si necesito que me pasen una opcion por parametro tengo que resolverlo asi y punto. Ahora, switch es lo mismo que una secuencia de if/else???? No es mas eficiente switch para evitar todo el procesamiento previo que requiere if/else????

eferion

A ver... cuando tu pones:

switch(valor)
{
  case 0:
    acccion0( );
    break;
  case 1:
    accion1( );
    break;
  case2:
    accion2( );
    break;
}


el compilador lo traduce a algo parecido a:


if ( valor == 0 )
  accion0( );
else if ( valor == 1 )
  accion1( );
else if ( valor == 2 )
  accion2( );


Obviamente la opción del switch es más limpia... por eso se usa. Por tanto, switch es exactamente igual de óptimo que if-elseif ... el compilador no hace milagros y el flujo del programa tendrá que comparar la variable con todos los valores para saber por qué opción ha de entrar. Si puedes conseguir que el switch sea más óptimo si pones las opciones más posibles al principio... así el código se ahorra comprobaciones de más.

Si quieres que el código sea más rápido puedes evitar el switch creándote un array de punteros a funciones... de tal forma que el puntero de la posición 0 apunte al código que se ha de ejecutar en el case 0, en la posición 1 el código del case 1 y así... es más rápido pero el código es algo menos legible.

Cita de: Xedrox en 28 Septiembre 2013, 20:24 PM
Si necesito que me pasen una opcion por parametro tengo que resolverlo asi y punto.

No te pongas gallito o te buscas la solución en otra parte... es un consejo. Entre otras cosas un problema se puede solucionar de muchas formas diferentes... es por eso que la programación es más un arte que algo mecánico.

Para empezar, como te he dicho en mi primer mensaje, lo más lógico es que tu en tu aplicación tengas un menú tal que:


printf( "Menu\n" );
printf( "1. Hacer una cosa\n" );
printf( "2. Hacer otra\n" );
printf( "3. Mostrar algo\n" );
printf( "4. Salir\n" );
printf( "Introduce una opción: \n" );


Con esto el usuario no va a introducir "opcion1" ... introducirá simplemente un "1", luego tú lo que necesitas hacer es utilizar ese "1" ... así que deja de inventarte lo de "opcion1". En primer lugar porque el usuario no lo va a introducir así... y segundo porque ESO NO ES UN NÚMERO y la instruccion strToInt no va a hacer milagros.

Y para terminar te lo repito, los case no admiten variables, tienes que pasarle un valor fijo:


switch ( valor )
{
  case 1: // 1... no una variable ni una cadena ni una funcion, un valor fijo.
  ...
  case 2: // Otro valor fijo... nada mas
  ...
}


Ah bueno sí, si defines constantes también las puedes usar en un case... al fin y al cabo se acaban traduciendo en valores fijos:


#define UNO 1
#define DOS 2

switch ( valor )
{
  case UNO:
  ...
  case DOS:
  ...
}



Xedrox

Hola, no sabia que la performance del switch era igual a la del if/else, tendré que buscar en los manuales si es así. Con respecto a lo del programa, no me gasto en explicar la solución de porque se pasa por parámetro porque solo necesitaba lo del switch, y para no desviar la discucion puse "y punto", pero para que no te quedes con la duda, es un programa llamado por un programa externo (el cual no es de mi propiedad), por lo tanto no tenia que ser interactivo. De todas maneras , gracias y saludos.

eferion

Aunque reciba parámetros de un programa externo... estos parámetros tendrán que estar previamente identificados... no pueden ser aleatorios.

Si el programa externo envía un parámetro que diga "opcion1"... realmente me parece un poco absurdo, pero necesitarías que la función strToInt fuese capaz de interpretar esa cadena para devolver un int coherente ( por ejemplo un 1 para la opción planteada )... pero en los case tienes que poner valores fijos como te he indicado...

Tu piensa que los programas son algo estático, no son capaces de razonar, tú eres el que le dicta lo que ha de hacer y ellos simplemente te obedecen... tu tienes que saber que "opcion1" se ha de convertir en un int valido y eso te obliga a saber de antemano el formato de los parámetros que ha de recibir tu programa.

Xedrox

Cita de: eferion en 29 Septiembre 2013, 17:30 PM
Aunque reciba parámetros de un programa externo... estos parámetros tendrán que estar previamente identificados... no pueden ser aleatorios.

Y por supuesto que no van ser aleatorios..

Cita de: eferion en 29 Septiembre 2013, 17:30 PM
Si el programa externo envía un parámetro que diga "opcion1"... realmente me parece un poco absurdo, pero necesitarías que la función strToInt fuese capaz de interpretar esa cadena para devolver un int coherente ( por ejemplo un 1 para la opción planteada )... pero en los case tienes que poner valores fijos como te he indicado...

No entiendo que es lo que te parece que es absurdo, como he comentado anteriormente, el programa es externo, no es de mi propiedad y la necesidad de resolver el problema se dio así y esta fuera de discusión.

Cita de: eferion en 29 Septiembre 2013, 17:30 PM
Tu piensa que los programas son algo estático, no son capaces de razonar, tú eres el que le dicta lo que ha de hacer y ellos simplemente te obedecen... tu tienes que saber que "opcion1" se ha de convertir en un int valido y eso te obliga a saber de antemano el formato de los parámetros que ha de recibir tu programa.

Eres Charles Xavier que sabes lo que pienso? Se perfectamente que puedo hacer eso, pero era mucho laburo obtener el resultado de 500 opciones posibles previamente para ponerlo en un swtch case. Ya lo resolvi con un Excel que me escriba el if/else.

Saludos..

eferion

Si te molestan las respuestas no se por qué te molestas en exponer tus dudas... sinceramente.

Cita de: Xedrox en 29 Septiembre 2013, 19:06 PM
No entiendo que es lo que te parece que es absurdo, como he comentado anteriormente, el programa es externo, no es de mi propiedad y la necesidad de resolver el problema se dio así y esta fuera de discusión.

Pues mira, me parece absurdo porque es un formato que no aporta nada... es como si me dijeses que la forma de codificar los parámetros fuese del tipo : "ejecuta_la_opcion_X", donde X es la opción concreta... es absurdo porque implica una redundancia que no aporta nada en absoluto.

Tu mírate los sistemas estándar para enviar información a través de red ( XDR, ASN.1, XML, etc ) todos intentan minimizar la redundancia ( hay que tener en cuenta que cada uno está pensado para un uso más o menos concreto )... básicamente porque no aporta nada y es proclive a provocar fallos tontos en los programas.

Y volviendo a lo de tu programa... me parece lógico que si tienes que aprovechar la salida de un programa ajeno tengas que adaptarte a sus salidas, pero eso no implica que yo no pueda pensar que el que programó eso podía haberlo hecho mejor. Es mi opinión y es tan respetable como la tuya.

Cita de: Xedrox en 29 Septiembre 2013, 19:06 PM
Eres Charles Xavier que sabes lo que pienso? Se perfectamente que puedo hacer eso, pero era mucho laburo obtener el resultado de 500 opciones posibles previamente para ponerlo en un swtch case. Ya lo resolvi con un Excel que me escriba el if/else.

Si tienes 500 opciones posibles ( por ejemplo, no te vayas a enfadar ) obviamente un switch no es la mejor opción posible. Cuando tratas con tantas posibilidades hay opciones muchísimo más limpias las cuales seguro que conoces ( o no, porque no soy Charles Xavier y no se lo que piensas ). Pero vamos que tener en un programa un if else o un case con más de 20 - 30 casos es un mal diseño de base y un caldo de cultivo perfecto para que el programa falle en el futuro cuando se le planteen ampliaciones... da igual si esos casos se generan automáticamente con un excel... puede que en algún momento el que tenga que manejar eso no disponga del excel... simplemente es un mal diseño.

Es ya famosa, por ejemplo ( entre los que han tenido que sufrirla ) una sentencia switch en una aplicación de telefónica que ocupaba unas 10k o 20k líneas... la cosa empezó con unos pocos casos y al final acabó siendo algo monstruoso... funcionaba? si, por supuesto, pero el mantenimiento era francamente costoso... conclusión, es un mal diseño.

Xedrox

Mira deja de contestar porque pareces que no entiendes, el programa externo no lo puedo tocar y punto, no es parte de la solución que estoy otorgando y esta fuera de mi alcance.

xiruko

Cita de: Xedrox en 30 Septiembre 2013, 01:56 AM
Mira deja de contestar porque pareces que no entiendes, el programa externo no lo puedo tocar y punto, no es parte de la solución que estoy otorgando y esta fuera de mi alcance.

Quizás antes de programar deberías practicar un poco de comprensión lectora...

Para intentar ayudar, si el formato de las opciones siempre es de la misma manera como "opcionX" u "OpcionX" o lo que sea, puedes pasarle un puntero al inicio del número en la cadena a la función atoi() de esta manera:

#include <stdlib.h>
char cadena[]="opcion123";
printf("%d\n", atoi(cadena+6));


output: 123

Claro que si el formato entre opciones cambia entonces ya no sirve. Si no cambia, podrías hacer lo que dijo eferion para ahorrarte un switch-case tan grande y usar punteros a función. Por ejemplo:

// prototipos de las funciones
int funcion_1(void);
int funcion_2(void);

//...

// dentro de main
int (*f[])(void)={funcion_1, funcion_2};    // array de funciones
char cadena[]="opcion2";
int index=atoi(cadena+6);                   // index de la funcion a ejecutar segun la opcion
f[index]();                                 // se ejecuta la funcion


Y bueno, de esta manera ganarías bastante rapidez aunque se perdería algo de legilibilidad en el código.

Saludos.