Programa que identifique que tipo de dato se introduce C++

Iniciado por minari02, 7 Febrero 2014, 20:59 PM

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

ivancea96

#10
Se puede hacer, pero tendrías que comprobar la cadena a ver si se puede convertir. Despues de saber si se puede convertir, tendrías que convertirla.

Aquí te pongo un par de códigos:

Saber a que tipos de dato se puede transformar:
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

enum type{
   /**    TYPES    **/
   type_bool     = 0b000000000001,
   type_char     = 0b000000000010,
   type_uchar    = 0b000000000100,
   type_short    = 0b000000001000,
   type_ushort   = 0b000000010000,
   type_int      = 0b000000100000,
   type_uint     = 0b000001000000,
   type_llong    = 0b000010000000,
   type_ullong   = 0b000100000000,
   type_float    = 0b001000000000,
   type_double   = 0b010000000000,
   type_ldouble  = 0b100000000000,

   /**    OTHER    **/
   type_signed   = 0b111010101011,
   type_unsigned = 0b000101010100,
   type_all      = 0b111111111111
};

bool allNumeric(string s){
   for(int i=0; i<s.size(); i++)
       if(s[i]<48 || s[i]>57)
       return false;
   return true;
}

bool minorEqual(string a, string b){
   if(a.size()<b.size()) return true;
   if(a.size()>b.size()) return false;
   if(a==b) return true;
   for(int i=0; i<a.size(); i++)
       if(a[i]<b[i]) return true;
       else if(a[i]>b[i]) return false;
   return true;
}

int typeOf(string s){
   if(s=="") return 0;
   int type = 0;
   bool sign = false;
   /** BOOL **/
   if((s.size()==1 && (s[0]=='0'||s[0]=='1'))||(s.size()==4 &&s.substr(0, 4)=="true")||(s.size()==5 &&s.substr(0, 5)=="false"))
       type+=type_bool;

   /** CHAR && UCHAR **/
   if(s.size()==1)
       type+=type_char+type_uchar;
   else{
       if(s[0]=='-')
           sign=true;
       if(s.size()<4+sign && allNumeric(s.substr(sign, s.size()))){
           if(sign){
               if(minorEqual(s.substr(1, s.size()), "128"))
                   type+=type_char;
           }else{
               if(minorEqual(s.substr(0, s.size()), "127"))
                   type+=type_char;
               if(minorEqual(s.substr(0, s.size()), "255"))
                   type+=type_uchar;
           }
       }
   }

   /** SHORT && USHORT **/
   if(s[0]=='-')
       sign=true;
   if(allNumeric(s.substr(sign, s.size()))){
       if(sign){
           if(minorEqual(s.substr(1, s.size()), "32768"))
               type+=type_short;
       }else{
           if(minorEqual(s.substr(0, s.size()), "32767"))
               type+=type_short;
           if(minorEqual(s.substr(0, s.size()), "65535"))
               type+=type_ushort;
       }
   }

   /** INT && UINT **/
   if(s[0]=='-')
       sign=true;
   if(allNumeric(s.substr(sign, s.size()))){
       if(sign){
           if(minorEqual(s.substr(1, s.size()), "2147483648"))
               type+=type_int;
       }else{
           if(minorEqual(s.substr(0, s.size()), "2147483647"))
               type+=type_int;
           if(minorEqual(s.substr(0, s.size()), "4294967295"))
               type+=type_uint;
       }
   }

   /** LONG && ULONG **/
   if(s[0]=='-')
       sign=true;
   if(allNumeric(s.substr(sign, s.size()))){
       if(sign){
           if(minorEqual(s.substr(1, s.size()), "9223372036854775808"))
               type+=type_llong;
       }else{
           if(minorEqual(s.substr(0, s.size()), "9223372036854775807"))
               type+=type_llong;
           if(minorEqual(s.substr(0, s.size()), "18446744073709551615"))
               type+=type_ullong;
       }
   }
   double b=atof(s.c_str());
   float a=(float)b;
   bool is=false;
   if(b==0.0 && (s=="0"||s=="0.0")){
       type+=type_float+type_double;
   }else if(b!=0.0){
       type+=type_double;
       if(a==b)
           type+=type_float;
   }
   return type;
}

int main(){
   string s;
   getline(cin, s);
   if(typeOf(s)&type_int)
       cout << "Se puede transformar en un entero (signed)." << endl;
   cin.get();
   return 0;
}



Ejemplo de como transformar string a int:
Código (cpp) [Seleccionar]

int potencia(int n, int b){
  int temp=1;
  for(int i=0;i<b;i++) temp=temp*n;
  return temp;
}

int parseString(string s){
string a;
int num = 0;
for(int i=s.length()-1;i>=0;i--){
 if(!((int)s[i]>=48 && (int)s[i]<=57)) return 0;
 num+=((int)s[i]-48)*(potencia(10, s.length()-i-1));
}
return num;
}


Bueno, aún no acabé con las funciones para transformar de string a numérico.
Igualmente, puedes usar las funciones atol(string) Retorna un LONG, atof() Retorna un DOUBLE, atoi() Retorna un INT


EDITO: Me olvidé decir, que el FLOAT, de la función typeOf(string), no funciona. Pero funciona para double.

minari02


Yoel Alejandro

Interesante la solución de minari!!!

Como lo que se introduce es una cadena, un programa personalizado podría decidir si se intentó introducir un short, int, long, float, etc. Al estilo quizá de VisualBasic.

Aunque yo sólo añadiría que en el código se usan algunas características C++ no indispensables, uno podría intentar ---como ejercicio---, traducir todo a C puro. Porque si no es esencial usar clases, ¿por qué C++ u no C?

De hecho, leí una vez que supuestamente el código compilado "tipo C" se ejecuta más rápida y eficientemente que el código compilado como "tipo C++". ¿Qué saben de esto?
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

minari02

me parece muy interesante... aunque, complicado! yoel_alejandro en el titulo he especificado C++ porque es el que estoy aprendiendo pero teniendo lo que  ivancea96 si sabes C puedes pasarlo de C++ a C supongo yo...

vangodp

C es lineal, c++ pega muchos mas saltos.
C también se desvía cuando creas funciones no inline, pero a cambio un programa en c++ puede ser un plato de macarrón. XD
La programación orientada a objetos pasa mayor factura.
Pero siempre puedes optimizar lo máximo :D
Si haces un programa que no salte de una función a otra esta claro que va ser mas eficiente.



rir3760

Cita de: yoel_alejandro en  8 Febrero 2014, 03:48 AMSi por ejemplo declaras:
Código (cpp) [Seleccionar]

int x;


y luego haces algo como
Código (cpp) [Seleccionar]

scanf( "%d", &x);


pues ya dijiste que se esperaba un tipo entero. No importa que el usuario meta un valor decimal a través del teclado, el valor será convertido forzosamente a un entero (según las reglas implícitas de conversión de C).
No hay que confundir los temas porque se corre el riesgo de terminar con una confusión espantosa.

Las conversiones (promoción de enteros y conversiones aritméticas usuales) se realizan tomando un tipo compatible y pasando este a otro. Por ejemplo "(unsigned int) - 1" resulta en el valor máximo que puede almacenarse en una variable de tipo unsigned int.

En el caso que nos ocupa (obtener un valor en base a una cadena de caracteres) lo único que aplica es la definición de la función utilizada ya sea atoi, strtol, scanf, etc..

----

Cita de: yoel_alejandro en  8 Febrero 2014, 03:48 AMNo se puede!!. C es un lenguaje "tipado", al contrario de otros lenguajes donde una variable puede alegremente cambiar de un tipo a otro.

Como te contestó otro usuario, esto significa que a cada variable que uses en C debes haberle definido previamente un tipo, de lo contrario el compilador te informará un error.

+

Cita de: leosansan en  8 Febrero 2014, 08:23 AM* Eso de que informa del error suena a broma. ¡Ojalá fuese siempre así!.

* Aunque previamente se haya definido un tipo para una variable siempre existe la posibilidad de cambiar el tipo mediante el correspondiente casting o mediante el uso de funciones tipo atoi, itoa,atof, etc.
Aqui se están mezclando dos temas:

A) Obtener el valor de una variable de tipo T y convertir ese valor a otro tipo U mediante una conversión explicita o implícita. Esto aplica a C.

B) Lenguajes sin tipos donde las operaciones dependen del contexto, esto usualmente aplica con lenguajes de scripts, mas o menos así:
a = 111         // Valor numerico 111
b = 222         // Valor numerico 222
Imprimir a + b  // Imprime 333

// ...

a = "111"       // La cadena 111
b = "222"       // La cadena 222
Imprimir a + b  // Imprime 111222


Cita de: leosansan en  8 Febrero 2014, 08:23 AMPara que veas minari02 como funciona, observa la salida del código que te propongo como validación de un int en el que no admite cosas como 1.23, 12as, asd12, o un simple caracter. Ante tales situaciones te vuelve a pedir que introduzcas un int:
Ya que la validación consiste en verificar que los caracteres sean solo dígitos el bucle lo puedes acortar a:
do {
   puts("Introduzca un numero entero:");
   scanf("%s", num);
   
   for (i = 0; isdigit(num[i]); i++)
      ;
}while (num[i] != '\0');

Y falta incluir el encabezado <stdlib.h> antes de utilizar atoi. Por ultimo como validación ambos programas (el tuyo y el mio) solo sirven para practicar ya que tienen agujeros (por ejemplo no se verifica el valor de retorno de la función scanf).

----

Cita de: yoel_alejandro en  8 Febrero 2014, 15:30 PMYo uso gcc de GNU para Linux y siempre me informa esta situación y lo cataloga como error (no Warning). Ello significa que el proceso de compilación se detiene y no genera un ejecutable. Por ejemplo, quise poner la sentencia de asignación x = 1 sin antes haber declarado la x y aquí el mensaje obtenido:
test1.c: In function 'main':
test1.c:18: error: 'x' undeclared (first use in this function)
test1.c:18: error: (Each undeclared identifier is reported only once
test1.c:18: error: for each function it appears in.)


Ni siquiera (considerando que C99 define "int por defecto") se le ocurrió tomar la variable x como int y seguir con la compilación.
Es al revés. En el estándar C90 si se declara una variable y se omite el tipo este es, de forma predeterminada, int. A partir de C99 no indicar el tipo en una declaración es un error.

Cita de: yoel_alejandro en  8 Febrero 2014, 15:30 PM
Por otra parte, respecto a lo de convertir "1.23" en 1, y "12as" como 12, a eso precisamente me refiero con "las reglas de conversión implícita de tipo de C". Ya que es un lenguaje tipado, él posee protolocos internos que le dicen cómo convertir un valor dado a otro tipo esperado.
Sin ofender y sin temor a repetir: las conversiones de tipos compatibles no aplican en este caso, lo único que aplica es la especificación de la función utilizada.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Yoel Alejandro

#16
Sólo para comentar, considérese que la propuesta:

Código (cpp) [Seleccionar]

   do {
     puts("Introduzca un numero entero:");
     scanf("%s", num);
   
     for (i = 0; isdigit(num[i]); i++)
        ;
   }while (num[i] != '\0');

no admite números negativos. Los números "negativos" también son enteros. Y por cierto que isdigit requiere <ctype.h> !!!

Y un poco aparte del tema, moderador una pregunta, ¿Hay alguna manera que solicitar que mis mensajes no sea citados o mencionados por cierto usuario en particular? Porque en este foro hay gente que en vez de venir a aportar soluciones propias, se dedica a examinar y poner epítetos a los aportes de los demás.
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

rir3760

Cita de: yoel_alejandro en 10 Febrero 2014, 20:55 PMSólo para comentar, considérese que la propuesta:
Código (cpp) [Seleccionar]
    do {
      puts("Introduzca un numero entero:");
      scanf("%s", num);
     
      for (i = 0; isdigit(num[i]); i++)
         ;
    }while (num[i] != '\0');

no admite números negativos. Los números "negativos" también son enteros.
Por supuesto que no los procesa ya que como comente el programa de leosansan solo intenta validar verificando que todos los caracteres sean dígitos.

Cita de: yoel_alejandro en 10 Febrero 2014, 20:55 PMY por cierto que isdigit requiere <ctype.h>!
Ouch! Gracias por la corrección.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language