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

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

0 Miembros y 1 Visitante están viendo este tema.

minari02

Hola que tal? desde hace rato me vengo preguntando como hacer un programa que, al introducir un dato, identifique que tipo de dato se ha introducido, alguien sabe como?? no tengo idea de como hacer eso... alguien puede?? pueden ir postenado sus ideas, por cierto, es solo una duda, que otros tambien tendran.

leosansan

Cita de: minari02 en  7 Febrero 2014, 20:59 PM
Hola que tal? desde hace rato me vengo preguntando como hacer un programa que, al introducir un dato, identifique que tipo de dato se ha introducido, alguien sabe como?? no tengo idea de como hacer eso... alguien puede?? pueden ir postenado sus ideas, por cierto, es solo una duda, que otros tambien tendran.

Antes de introducir cualquier dato habrás tenido que declararlo previamente como int, char o lo que sea. Ahí está la respuesta. :rolleyes:

¡¡¡¡ Saluditos! ..... !!!!



vangodp

Eso es lo que comenta leo.
El problema es que todo lo que vas usar tienes que declararlo antes.
Una cosa que puedes hacer es entrar los datos como string y después hacerles un cast a int o float por ejemplo, a la hora de hacer un calculo.
Pero no le veo la necesidad a eso.
Tu lo dirás para que lo quieras.
tal vez estés formulando mal la pregunta.   ;)

Yoel Alejandro

No 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. Recuerda que distintos tipos ocupan distinto espacio en memoria, así que el compilador debe saber previamente el tipo de cada variable para calcular correctamente cuántos bytes asignarle dentro de la memoria de datos del programa.

Si un usuario mete un valor por la consola (teclado), aún así debes declarar un tipo esperado en la cadena de control de formato de scanf (posiblemente distinto al que el usuario esperaba, pero aún así es un tipo fijo declarado previamente en el programa). Por otra parte, la variable a la que será asignado este valor tiene un tipo previamente declarado, por tanto será ese tipo y no otro.

Ten en cuenta algo muy importante. Si 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).
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

Gh057

Hola minari02, como muy bien te han contestado el control que tiene el C sobre las variables exige la declaración antes de utilizarlas, aunque  bien pudiera ser que lo que intentas preguntar es como "validar" un dato ingresado, que es otra cosa... lo más usual es encapsular la entrada en un "do-while...", ya que permite correr la sentencia al menos una vez (el cual usamos para el ingreso del dato) y lo aceptamos o rechazamos mediante la condiciones definidas al caso. Saludos.
4 d0nd3 1r4 3l gh057? l4 r3d 3s 74n v4s74 3 1nf1n1t4...

leosansan

#5
Cita de: yoel_alejandro en  8 Febrero 2014, 03:48 AM
No 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.
.............................................

* 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.


Cita de: yoel_alejandro en  8 Febrero 2014, 03:48 AM
..................................
.Por otra parte, la variable a la que será asignado este valor tiene un tipo previamente declarado, por tanto será ese tipo y no otro.

Ten en cuenta algo muy importante. Si 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).

Según como lo interpretes. Si has declarado una variable como int e introduces 1.23 tomará como int el 1. Y si introduces 12as como dato toma el 12 como int. Y si introduces un caracter o una cadena, tipo a o asdf, en el mejor de los casos el int toma un valor "extraño" que afectará al resto de código por quedarse en el buffer. Y en el peor se produce un bucle infinito si estas en un for,while o do-while.

Cita de: Gh057 en  8 Febrero 2014, 04:46 AM
Hola minari02, como muy bien te han contestado el control que tiene el C sobre las variables exige la declaración antes de utilizarlas, aunque bien pudiera ser que lo que intentas preguntar es como "validar" un dato ingresado, que es otra cosa... lo más usual es encapsular la entrada en un "do-while...", ya que permite correr la sentencia al menos una vez (el cual usamos para el ingreso del dato) y lo aceptamos o rechazamos mediante la condiciones definidas al caso. Saludos.


Ahí estamos más de acuerdo , amigo Gh057. Se trata en realidad de validar el valor introducido, cosa que por comodidad no suele hacerse pero que en un programa serio es indispensable.

Por ejemplo si estamos tratando de introducir un int y no queremos disgustos en el resto del código hay que asegurarse que el valor introducido sea efectivamente un int. Y esto se puede realizar de varias maneras.

Para 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:


Citar

Introduzca un numero entero:123.356

Introduzca un numero entero:12asd

Introduzca un numero entero:asd123

Introduzca un numero entero:a

Introduzca un numero entero:123456

numero= 123456


Código (cpp) [Seleccionar]

#include <stdio.h>

int main(){
 int i,numero,flag=0;
 char num [20];
 do{
   flag=0;
   printf ("\nIntroduzca un numero entero:");
   fflush(stdout);
   scanf ("%s",num);
   for (i=0;num[i];i++){
     if (num[i]<'0' || num[i]>'9'){
       flag=1;
     }
   }

 }while (flag!=0);
 numero=atoi(num);
  printf("\nnumero= %d\n",numero);
 return 0;
}


Como ves algo más complejo que un simple:

Código (cpp) [Seleccionar]

#include <stdio.h>

int main(){
 int numero;
 printf ("\nIntroduzca un numero entero:");
 fflush(stdout);
 scanf ("%s",numero);
 printf("\nnumero= %d\n",numero);
 return 0;
}


Pero como te comenté, este último se revienta introduciendo un simple caracter,12.36,etc.

¡¡¡¡ Saluditos! ..... !!!!



Yoel Alejandro

#6
Leosasan, estas discusiones sobre el comportamiento del compilador ante ciertas situaciones irregulares en los programas son sumamente enriquecedoras tanto para nosotros como para los usuarios menos experimentados de la comunidad  :)

Respecto a que no crees que el compilador informe un error siempre que encuentre una referencia a una variable que no se ha definido con anterioridad, ..... bueno dependerá del tipo de compilador, y lo estricto que éste sea.

Yo 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. Claro, esto quizá dependerá del tipo de compilador, a lo mejor algunos son más flexibles, o pueden ser configurados sobre cómo responder en situaciones como ésta.

En todo caso, creo que un compilador estricto es mejor (el de GNU lo es), porque te enseña desde el principio a programar como es debido, y ceñirte mejor a la norma ISO/IEC 9899:1999, mejor llamada ANSI C99 !!!

============================
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.

Ahora, SUPONEMOS que cadenas como "12as" se convertirán a 12, pero en general de la forma exacta de conversión yo no estoy seguro, pero eso debe estar claramente definido en la norma ANSI C99. Por algo C es un lenguaje que ha sido absolutamente normado, y al tener una duda sólo hay que consultar lo que dice la norma al respecto.

Yo no he investigado profundamente la conversión a entero de cadenas que incluyen caracteres no numéricos, preferiría validar el dato por mí mismo, tal como lo propone leosasan en su código.

Al usuario que inició este post le recuerdo que C tiene normas internas de conversión de tipo, y serán SÓLO esas, las que especifica el estándar oficial, y no las que tú creas, o las que crea el usuario. En tales situaciones "anómalas", nada te garantiza que el comportamiento de la función scanf será como tú supones que será. Pero como programador debes mantener tu programa siempre "bajo control", por eso debes confeccionar una rutina de validación de los datos que introduce el usuario según tus propias normas y preferencias. Eso te recomiendo  :) :)

======================
Continuando el tema, y para que minari02 te acostumbres a la buen práctica de validar los datos de entrada (nunca confíes en el buen juicio del usuario de tu programa) he aquí una humilde contribución que preparé hace tiempo. Esta función isnumeric recibe una cadena y devuelve True si corresponde a un número válido, y False si no. Admite los caracteres 0-9, además de +-., y el espacio. Los espacios al inicio y al final de la cadena serán despreciados, y además filtra la cadena de una forma más sofisticada que sólo ver si está compuesta de caracteres permitidos. Por ejemplo, permite el '+' o el '-', pero sólo uno de ellos, y antecediendo a cualquier carácter numérico. O sea, que por ejemplo rechazará expresiones como "++354", ó "3-456". El signo decimal '.' sólo podrá aparecer una vez.

Aquí el código, para que lo incluyas en tu programa. Se aceptan con agrado sugerencias y mejoras  ;-)

Código (cpp) [Seleccionar]

/* No cero si la cadena apuntada por s representa un número real decimal.
La cadena deberá contener sólo los caracteres "+-0123456789. ".

- El carácter de punto decimal es el punto '.', es opcional y sólo puede aparecer
  una vez en la cadena.
- El carácter de signo '+' o '-' es opcional, sólo puede aparecer una vez y como
  primer carácter no blanco de la cadena.
- Se admiten secuencias de espacios ' ' al principio o al final de la cadena, pero
  son ignoradas. No se admiten espacios en el medio de la cadena.

Esta definición es acorde con la configuración regional estándar en Español, pero
pudiera adaptarse para la configuración en Inglés (la coma ',' antes que el punto '.').

No admitimos en esta implementación representaciones en punto flotante con mantisa y
exponente, sólo mantisa.
*/
int isnumeric(const char *s) {

const char *allowed_chars = "0123456789."; /* caracteres permitidos */
char c;
int i, j, N;
bool exists_point = false, exists_sign = false;
bool pre_space = false, post_space = false;

N = strlen(allow_chars);
for (i = 0; i < INT_MAX && s[i]!='\0'; i++) {
c = s[i];

// sólo se admite un carácter opcional '+' ó '-' y como primer
// no blanco de la cadena
if (c == '+' || c == '-') {
if (exists_sign == true)
return 0;
else {
exists_sign = 1;
if (i>0)
if (s[i-1] != ' ') return 0;
}
continue;
}

if (c == ' ') {
if (pre_space == false) pre_space = 1;
if (i > 0 && s[i-1] != ' ') post_space = 1;
continue;
}
if (post_space == true && c != ' ') return 0;

// buscando caracteres permitidos
for (j=0; j<N; j++)
if (c == allowed_chars[j]) break;
if (j == N) return 0;

// no puede haber más de un carácter '.'
if (c == '.') {
if (exists_point == 1)
return 0;
else
exists_point = 1;
}
}

// si no detecta error, sale con valor 1
return 1;
}

Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

ivancea96

Me gusta la idea de yoel_alejandro.
Pero, aprobechendo que el tipo de retorno de "isNumeric" es int, podría retornarse un número según el tipo de dato. (float, double, int, long long int, etc)

Sería una función muy útil.

ivancea96

#8
Me pongo a esto:

Código (cpp) [Seleccionar]
enum type{
   type_signed = 1,
   type_bool = 2,
   type_int = 4,
   type_short = 8,
   type_float = 16,
   type_double = 32,
   type_char = 64
   /* ... */
}

int typeOf(string s){
   /** Esto retornará un entero compuesto de los números que pueda ser.
         Si es "12", por ejemplo, puede ser short, int, float, double y char. Entonces, retornaría: 4+8+16+32+64. (Puede ser más tipos, pero aun estoy empezando el enum jaja **/
}

Luego, la salida de typeOf se parsearía así:
Código (cpp) [Seleccionar]
if(typeOf(str)&type_double) double d = parse<double>(str);
la función parse podría tener un template para retornar el tipo indicado xD


EDITO: Como es diferente el tamaño de un signed al de un unsigned (el tamaño máximo), quitaré el type_signed, y pondré type_uchar, type_uint etc etc

EDITO 2: Finalmente:
Código (cpp) [Seleccionar]
enum type{
    /**    SIGNED TYPES    **/
    type_bool     = 0b0000000000000001,
    type_char     = 0b0000000000000010,
    type_short    = 0b0000000000000100,
    type_int      = 0b0000000000001000,
    type_llong    = 0b0000000000010000,
    type_float    = 0b0000000000100000,
    type_double   = 0b0000000001000000,
    type_ldouble  = 0b0000000010000000,

    /**    UNSIGNED TYPES    **/
    type_ubool    = 0b0000000100000000,
    type_uchar    = 0b0000001000000000,
    type_ushort   = 0b0000010000000000,
    type_uint     = 0b0000100000000000,
    type_ullong   = 0b0001000000000000,
    type_ufloat   = 0b0010000000000000,
    type_udouble  = 0b0100000000000000,
    type_uldouble = 0b1000000000000000,

    /**    OTHER    **/
    type_signed   = 0b0000000011111111,
    type_unsigned = 0b1111111100000000,
    type_all      = 0b1111111111111111
};



RE-EDITO: Ahora me dió pereza poner toodos los "if" para comprobar cada tipo jaja. Si alguien se anima, aunque sea para 1 tipo solo, que postée :3

minari02

bueno.... claro que ya habia pensado lo de que hay que iniciar la variables... pero... me he perdido... se puede hacer lo que le he preguntado??? lamento no comprender todo lo que han puesto!  :-(

Gracias!