2.3 Escriba la función htoi(s), que convierte una cadena de dígitos hexadecimales (incluyendo 0x ó 0X en forma optativa) en su valor entero equivalente. Los dígitos permitidos son del 0 al 9, de la a a la f, y de la A a la F.
___________________________________________________________________________________
Solución: Este programa convierte de hexadecimal a decimal. El programa está bien comentado y creo que es fácil de seguir y entender. Es posible realizar éste problema de otras maneras, ésta es una de ellas. El usuario puede introducir los numeros 0, 1, ....9 y las literales A, a, B, b,.....F, f. El uso de minúsculas hace el programa más largo. Cualquier otro dígito envía un mensaje de error. Tal vez le convenga leer la entrada Los números hexadecimales. Una tabla de equivalencias entre números binarios, octales, decimales y hexadecimales, aparece en Ésta página.
/*Este programa convierte de hexadecimal a decimal */ #include <stdio.h> #define Tamano 35 // La variable Tamano se fija en 35 // porque los enteros de dos bytes // ocupan 32 bits y la ultima entrada // de una cadena en un arreglo es \n /*Prototipo de funcion Recibe*/ /* Esta funcion recibe la cadena pero no verifica que sea valida */ void Recibe( int a[]); /*Prototipo de funcion Imprime*/ /* Si la cadena es valida se calcula e imprime su equivalente decimal, si no se manda un mensaje al usuario y se termina el programa */ void Imprime( int b[]); /*/////////////////////////////// // MAIN ////////////////////////////////*/ int main() { // Abre main int arreglo[Tamano]; // En este arreglo se recibiran los valores // de la cadena hexadecimal int evaluar; // La variable evaluar lleva el control // de la legalidad de la cadena, es decir // se introducen digitos validos como e, 1 // o se introducen valores invalidos como // s, z // Un mensaje que avisa al usuario que // hace el programa printf("\nEste programa recibe un numero " "hexadecimal y lo convierte a decimal.\n"); // Se invoca a la funcion Recibe y se le envia // la direccion de la primera posicion de arreglo Recibe(arreglo); // Se calcula e imprime el valor decimal, de // nuevo por referencia Imprime(arreglo); return 0; } // Cierra main /*//////////////////////////////////// // FUNCION RECIBE ////////////////////////////////////*/ void Recibe( int a[]) { // Abre Recibe /* En el arreglo a se guardaran las entradas de la cadena*/ int i = 0; /* La variable i sirve como contador en varios ciclos */ for( i = 0; i < Tamano; i++ ) a[i] = ' '; // Las entradas se inicializan a ' ' printf("\nIntroduzca un numero hexadecimal: \n"); /*El siguiente while recibe la cadena y la asigna al arreglo en una sola linea. Observe que al final hay un ; */ i = 0; // Se pone i = 0 while ( (a[i++] = getchar()) != '\n' && Tamano > i ); printf("\n"); } // Cierra Recibe /*///////////////////////////////////// // FUNCION IMPRIME /////////////////////////////////////*/ void Imprime( int b[] ) { // Abre Imprime int i; int potencia = 1; // La variable potencia lleva el valor de la // potencia de 16 por la cual se va a multiplicar // el digito almacenado dependiendo de su posicion int decimal = 0; // El equivalente decimal de la cadena hexadecimal // se inicia a 0 int inicio; // La variable inicio se encarga de registrar // en donde empieza el primer digito de la cadena. // Esta cadena debe leerse de izquierda a derecha. // Este ciclo for busca de atras para // adelante el primer digito distinto // de ' ' en el arreglo. A partir de // ahi se empieza a evaluar el numero // hexadecimal for ( i = Tamano - 1; i >= 0; i-- ) { // Abre for if ( ' ' != b[i] ) { // abre if inicio = i; break; // sale de for } // Cierra if } // Cierra for // Este ciclo for evalua cada una de las // entradas del arreglo que fueron introducidas // por el usuario, las multiplica por la potencia // de 16 correspondiente a su posicion y los // productos los va sumando. La suma total sera // el valor decimal del numero. int valido = 1; // Si el hexadecimal recibido no es valido, no // se puede calcular su valor decimal. Esta // variable controla eso. En principio se establece // en 1 o cierto, ya que se asume que el usuario // introdujo un numero valido for ( i = inicio; i >= 0; i-- ) { // Abre for switch( b[i] ) { // Abre switch case '0': decimal += 0*potencia; potencia *= 16; break; case '1': decimal += 1*potencia; potencia *= 16; break; case '2': decimal += 2*potencia; potencia *= 16; break; case '3': decimal += 3*potencia; potencia *= 16; break; case '4': decimal += 4*potencia; potencia *= 16; break; case '5': decimal += 5*potencia; potencia *= 16; break; case '6': decimal += 6*potencia; potencia *= 16; break; case '7': decimal += 7*potencia; potencia *= 16; break; case '8': decimal += 8*potencia; potencia *= 16; break; case '9': decimal += 9*potencia; potencia *= 16; break; case 'A': decimal += 10*potencia; potencia *= 16; break; case 'a': decimal += 10*potencia; potencia *= 16; break; case 'B': decimal += 11*potencia; potencia *= 16; break; case 'b': decimal += 11*potencia; potencia *= 16; break; case 'C': decimal += 12*potencia; potencia *= 16; break; case 'c': decimal += 12*potencia; potencia *= 16; break; case 'D': decimal += 13*potencia; potencia *= 16; break; case 'd': decimal += 13*potencia; potencia *= 16; break; case 'E': decimal += 14*potencia; potencia *= 16; break; case 'e': decimal += 14*potencia; potencia *= 16; break; case 'F': decimal += 15*potencia; potencia *= 16; break; case 'f': decimal += 15*potencia; potencia *= 16; break; default: if ( '\n' != b[i]) { // Abre if printf("\nERROR. LA CADENA NO ES VALIDA!\n"); valido = 0; // El hexadecimal recibido no // es valido printf("\nEste caracter no es valido: "); putchar(b[i]); printf("\n"); } // Cierra if break; } // Cierra switch } // Cierra for if ( 1 == valido ) printf("\nEl valor decimal es: %d\n", decimal); else printf("\nEl numero introducido no es valido.\n"); } // Cierra Imprime__________________________________________________________________________________________
Esta entrada es parte de los problemas resueltos del libro El Lenguaje de Programación C de B. Kernighan y D. Ritchie
Entrada Anterior
Entrada Siguiente
__________________________________________________________________________________________
no corre
ResponderEliminarHola. El programa está bien. Lo he revisado y no hay ningún problema. Si dices que no corre debes estar compilando mal o copiando mal. Copia y pega el programa, sólo ten cuidado copiarlo y pegarlo completo. Yo compilo en linux con cc o gcc y funciona.
ResponderEliminarHola, una consulta, porque cuando escribo un numero de 8 o mas digitos el resultado no es el correcto.. ejemplo ffffffff(8) es igual a -1
ResponderEliminarSaludos..
No entendi esto que escribiste..
ResponderEliminar// La variable Tamano se fija en 35
// porque los enteros de dos bytes
// ocupan 32 bits y la ultima entrada
// de una cadena en un arreglo es \n
No sera 16 bits¿?
¡Hola, Roberto! Tienes razon. Es 16 bits. Por otro lado, la razòn por la que si metes un nùmero muy grande, obtienes nùmeros negativos, es porque la variable decimal se declara del tipo int. Lo que pasa es que el tipo de datos es superado. Si quieres nùmeros màs grandes puedes usar un tipo double, por ejemplo. Checa Esta pàgina si te interesa un poco màs èsto.
EliminarMuchos saludos.
hola, disculpa, estoy tratando de escribir este programa y lo que quiero hacer es multiplicar el elemento de un arreglo por un entero, osea:
ResponderEliminarpot=2
num[i]*pot;
y lo que hace es multiplicarme el valor ascii del caracter en esa posicion del arreglo..
no se si me explique bien..
ejemplo, si en num[i] esta guardado el numero '2' lo que hace es 50*2, 2 en ASCII es 50..
¡Hola, Roberto!, perdón por contestarte hasta ahora, he estado un poco ocupado. ¿Estarás guardando tu variable i como tipo char?, incluso más bien parece que simplemente no la estás declarando como un tipo de datos, sino que el compilador la toma como si fuera un 'i'. Debes declararla como tipo int.
EliminarSaludos.
Hola, no lo declaraba como tipo INT, igualmente lo arregle realizando pot*(num[i]-'0') pero sinceramente no se porque funciona.. porque segun el libro al realizar num[i]-'0' esa expresion lo que hace es devolver el valor numerico del caracter almacenado..
EliminarLo que pasa es que si restas '0', estás restando el valor ASCII de 0. Lo de num[i] me sigue pareciendo extraño.
EliminarMira esta es mi version: http://codepad.org/SkJUjRjw
ResponderEliminarno use switch, break, case, porque no llegue hasta esa parte..
Y ahora si a num[j] NO le resto '0' anda bien, osea ahora anda bien de las dos formas, antes si multiplicaba num[j] por algo, me multiplicaba el valor en ASCII del caracter en esa direccion.. capas tenia algo mal porque modifique el codigo..
Creo que el codigo se podria achicar mas en la parte de las letras, pero no se me ocurre como.. o por lo menos con lo que vi por ahora en el libro..
Está muy compacto tu código. Me gustó mucho. Pongo el enlace: programa
EliminarGracias!!
ResponderEliminarGracias a ti por el comentario, anónimo.
EliminarYo aqui tengo mi versión de htoi, pensada como una función fuera del main:
ResponderEliminarint htoi(const char s[]){
int i,h;
h = i = 0;
if (s[i]=='0'){ /* Verifica si es un hexadecimal precedido por 0x o 0X*/
++i;
if (s[i]=='x'||s[i]=='X')
++i;
}
for (i; isHexa(s[i]); ++i)
h = (h * 16) + valHexa(s[i]);
return (h); /* Retorna 0 en caso de que el numero sea una entrada incorrecta o 0*/
}
int isHexa(int c){ /*verifica si es un digito hexadecimal*/
return (isdigit (c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') );
}
int valHexa (int c){ /*convierte un caracter hexadecimal a su valor decimal*/
if (isdigit (c))
c = c - '0';
else
c = tolower (c) - 'a' + 10;
return (c);
}
Utlizo la biblioteca para utilizar las funcion isDigit(int) que detecta si un caracter es un digito entre 0 y 9 y tolower(char) que convierte un caracter mayuscula a su equivalente en minuscula.
Lo unico que destaco es que la funcion devuelve 0 en caso de error y que convierte a hexadecimal cadenas que podrian ser numeros octales. Ej: "0562" ya que en el libro de C los numeros octales empiezan con un 0.
para probarlo hay que realizar una funcion main que invoque a la funcion htoi y pasarle una cadena de caracteres que contenga un numero hexadecimal.
aqui dejo la funcion junto a un programa que la utilice: http://codepad.org/5dADTDjs
ResponderEliminarDisculpen habia un error en cuanto a la deteccion de un error.
ResponderEliminarAqui te dejo una nueva pagina en la uqe esta el codigo de htoi: http://codepad.org/wgBJLtYe
¡Hola, Martín! Muchas gracias por tu aporte. Te agradezco la gentileza de compartir el código. Acabo de revisarlo y me parece muy bueno. El punto aquí es que yo no conocía la función isdigit, que, según me cuentas, se incluye en el encabezado ctype. En buena medida trato de utilizar para resolver estos problemas, los recursos que se conocen hasta ésta altura en el libro de Kernighan-Ritchie, porque luego me ha pasado que algunas personas dicen que utilizo cosas que no se han visto, y de alguna manera es "hacer trampa", Desde luego, creo que hay que utilizar las herramientas ya incluidas en el lenguaje.
ResponderEliminarTe agradezco de nuevo, y muchos saludos.