Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - eferion

#901
Programación C/C++ / Re: Invertir numeros con ciclos
30 Septiembre 2013, 20:27 PM
Hay opciones más óptimas y sencillas para copiar el valor de una variable en otra y viceversa:

Opcion 1:


int a = 5;
inb b = 24;

a = a^b;
b = a^b;
a = a^b;


Opcion 2: igual que la uno pero simplificando el código

int a = 5;
inb b = 24;

a ^= b;
b ^= a;
a ^= b;


Opcion 3:


int a = 5;
inb b = 24;

a = a + b;
b = a - b;
a = a - b;


Y seguro que no son las únicas.
#902
El caso que has expuesto es hasta peligroso.

Cuando una función recibe un parámetro como referencia puedes modificar el valor de la variable referenciada desde la propia función... cuando retornas una referencia permites que desde fuera de la función se modifique el valor de la variable almacenada en la función o en la clase.

Código (cpp) [Seleccionar]


class A
{
  int valor;

  public:
    A( ) : valor( 0 ) { }

    int& Valor( )
    { return valor; }
};

void main( )
{
  A clase;

  cout << clase.Valor( ) << std::endl; // imprime 0
  clase.Valor( ) = 4;
  cout << clase.Valor( ) << std::endl; // imprime 4
}


En el ejemplo que tú has puesto, tanto a como b se pasan por valor, es decir, se crean dos int dentro de la función y se les asignan los valores que se pasen como parámetros. El problema es que estas dos variables creadas dentro de la función solo existen durante la ejecución de la función... una vez que se produce un return las dos variables ya no son válidas en memoria... te puedes imaginar que intentar un acceso al valor retornado ( o una modificación de su valor ) puede desembocar en un fallo de la aplicación.

Un ejemplo que no debería dar problemas podría ser este:

Código (cpp) [Seleccionar]

int& max( int& a, int& b )
{
  if ( a >= b ) return a;
  return b;
}


En este caso estás pasando los dos parámetros por referencia, luego el return devolverá una de esas dos referencias y, claro, una vez fuera de la función las variables a y b originales seguirán existiendo.

Personalmente pasar por referencia tipos básicos, salvo que se requiera su modificación dentro de una función, es un poco una tontería. Cuando tu declaras una referencia, se crea un puntero implícito... el acceso a un puntero es más lento que el acceso a una variable por valor... y al programa le cuesta lo mismo copiar una variable de un tipo básico que copiar una dirección en memoria. Total, no se gana nada.
#903
Programación C/C++ / Re: Duda funciones C++
30 Septiembre 2013, 13:00 PM
Usa las etiquetas GeSHi para que el código sea más legible.

Cita de: javiherro en 30 Septiembre 2013, 12:14 PM

static double CalculaPrecioContrato(contrato){
extraeInfo(contrato);
modificaDatos(contrato);
calculaPrecio(contrato);
}


Estas 3 funciones estarían declaradas antes...¿no?

Efectivamente, una función no puede ser llamada si no se ha declarado y/o implementado previamente.

Es por eso que las cabeceras de las aplicaciones escritas en c están plagadas de declaraciones de funciones.

Cita de: javiherro en 30 Septiembre 2013, 12:14 PM
Ahora mi duda es, si yo hago el método para extraer datos, algo asi:


static void extraerInfo(contrato){
int param A = contrato.dameA;
int param B = contrato.dameB;
int param C = contrato.dameC;
}


Los valores de paramA, paramB, y paramC, ¿se pueden usar luego dentro de la función "general" CalculaPrecioContrato o de la función modificaDatos?

Si es que no, ¿cómo podría hacerlo?

Una aclaración previa, int param A está mal o bien pones int paramA o bien param A ( depende de si param es un tipo o es parte del nombre. El nombre de una variable no puede incluir espacios.

Y respondiendo a tu pregunta, paramA, paramB y paramC puedes usarlas en extraerInfo, pero no fuera de dicha función. Si necesitas usarlas en la función que ha llamado a extraerInfo tienes que idear un mecanismo que permita que los valores almacenados en estas variables pueda llegar a la función "padre".

Una posibilidad, dado que es más de un valor lo que tienes que devolver, es usar una estructura que agrupe todos los valores y hacer un return sobre dicha estructura:


struct params
{
  int paramA;
  int paramB;
  int paramC;
};

static struct params extraerInfo(contrato){
  struct params parametros;
  parametros.paramA = contrato.dameA;
  parametros.paramB = contrato.dameB;
  parametros.paramC = contrato.dameC;

  return parametros;
}


Otra opción es que extraerInfo requiera el paso de 3 punteros para poder almacenar en dichos punteros los valores devueltos por las tres funciones:


void extraerInfo( contrato, int* paramA, int* paramB, int* paramC )
{
  *paramA = contrato.dameA;
  *paramB = contrato.dameB;
  *paramC = contrato.dameC;
}

void funcionQueLlamaAExtraerInfo( contrato )
{
  int paramA, paramB, paramC;

  extraerInfo( contrato, &paramA, &paramB, &paramC );
}


Notas finales:

* No es necesario declarar static a las funciones de C. Ponerles ese modificador permite que haya funciones con el mismo nombre en distintos archivos... pero eso te puede generar otros problemas si no controlas el tema, así que mejor quita ese modificador.

* El código de los ejemplos no va a compilar porque "contrato" no se de qué tipo es: tipo básico, estructura, puntero
#904
Cuando tu cifras un código... solamente tú sabes lo que contiene el paquete cifrado, para los demás no es más que un conjunto de bytes sin sentido. Claro, cuando me refiero a que solamente tú sabes lo que contiene me refiero en el sentido estricto de la palabra, es decir, ni tan siquiera el ordenador sabe qué contiene ese código y, obviamente, es incapaz de ejecutarlo.

Ese código cifrado no sirve de nada mientras siga en ese estado, para que se pueda ejecutar es necesario descifrarlo antes.

Sin embargo, aún con el código descifrado, este sigue sin hacer nada hasta que se ejecuta... es aquí donde empiezan a actuar la mayoría de los antivirus cuando aún no tienen la firma de tu virus... en el momento en el que tu aplicación intente instalar los hooks necesarios para capturar las pulsaciones de todas las teclas, por ejemplo, al usuario le va a saltar una bonita alerta avisándole... y contra esto no puedes hacer gran cosa salvo que anules de alguna forma el antivirus.

Moraleja: cifrando el código te puedes llegar a saltar una barrera del antivirus... pero la segunda barrera ya es más complicada
#905
Programación C/C++ / Re: Switch con cadena
30 Septiembre 2013, 08:29 AM
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.

Como dice Xiruko, practica comprensión lectora... y te lo digo más que nada por esto ( lo he aislado para que te sea más sencillo de localizar ):

Cita de: eferion en 29 Septiembre 2013, 21:57 PM
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.

Resumido: si el programa que te pasa los parámetros no es tuyo, te tienes que adaptar, no hay otra. Sin embargo yo sigo pensando que el mecanismo empleado es malo con ganas.

Y tranquilo, procuraré no responderte en el futuro, al menos hasta que no aprendas a leer lo que la gente se molesta en escribirte.
#906
Programación C/C++ / Re: Switch con cadena
29 Septiembre 2013, 21:57 PM
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.
#907
Programación C/C++ / Re: Switch con cadena
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.

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.
#908
Programación C/C++ / Re: Switch con cadena
29 Septiembre 2013, 00:14 AM
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:
  ...
}


#909
No veo problemas en tu forma de destruir la lista.

En cualquier caso, si quieres verificar que se libera toda la memoria haz la prueba de crear X nodos y después destruir la lista... si en la consola aparecen X nodos destruidos entonces no queda memoria sin liberar.

Además, si rebuscas un poco con google hay librerías que te ayudan a evitar lagunas de memoria... básicamente te avisan cuando se te ha olvidado algún delete.
#910
Programación C/C++ / Re: Switch con cadena
28 Septiembre 2013, 20:19 PM
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" );