Pregunta

Estoy tratando de escribir un programa que toma la entrada de - hexadecimales, octales, decimales y -, los almacena en variables enteras, y las salidas junto con su conversión a la forma decimal. Por ejemplo:

Las entradas del usuario: 0x43, 0123, 65

Los resultados del programa:

0x43 hexadecimal converts to 67 decimal
0123 octal converts to 83 decimal
65 decimal converts to 65 decimal

Así que, obviamente, necesito una manera de interpretar los números, pero no estoy seguro de cómo ir haciendo sobre él. He intentado varios métodos tales como leerlos en una función y su conversión en una cadena, y viceversa (ver aquí de ejemplos de código), pero la interpretación de los números siempre se requiere la conversión a un formato que destroza la entrada original.

Lo único que se me ocurre es la sobrecarga de un operador >> que lee un carácter a la vez y si ve 0x ó 0 al comienzo de la entrada y luego se almacena toda la entrada en una cadena antes de que se lee en la un int. A continuación, el programa de alguna manera tiene que determinar el manipulador de la derecha durante la salida.

No estoy seguro si hay una manera más sencilla de hacer esto, cualquier ayuda se agradece.

Editar:. Esto ha sido resuelto, pero he decidido publicar el código en si alguien está interesado

#include "std_lib_facilities.h"

void number_sys(string num, string& s)
{
  if(num[0] == '0' && (num[1] != 'x' && num[1] != 'X')) s = "octal";
  else if(num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) s = "hexadecimal";
  else s = "decimal";
}

int main()
{
    cout << "Input numbers in hex, dec, or oct. Use 0xx to cancel.\n";
    string a;

    while(cin >> a){
    if(a == "0xx")break;
    string atype;
    number_sys(a, atype);

    int anum = strtol(a.c_str(), NULL, 0);

    cout << a << setw(20-a.length()) << atype << setw(20) << "converts to" << setw(10)
         << anum << setw(10) << "decimal\n";
                 }

    keep_window_open();
}
¿Fue útil?

Solución

Tome un vistazo a la función strtol.

char * args[3] = {"0x43", "0123", "65"};
for (int i = 0; i < 3; ++i) {
  long int value = strtol(args[i], NULL, 0);
  printf("%s converts to %d decimal\n", args[i], value);
}

Salidas:

0x43 converts to 67 decimal
0123 converts to 83 decimal
65 converts to 65 decimal

Otros consejos

Siempre se puede almacenar como una cadena para empezar, y mirar a los dos primeros caracteres para ver si son 0x:

std::string num;
std::cin >> num;

if (num[0] == '0' && num[1] == 'x')
{ 
  //handle
}

No estoy seguro de si hay una forma de C ++ de hacer esto, pero si no te importa un poco de C-ishness, se puede leer la cosa en una matriz char y usar algo como sscanf(buffer, "%i", &output). El %i interpreta la entrada como hexadecimal, octal o decimal en función de su formato, al igual que lo describe.

Edit: Ah, no sabía que strtol también podría hacerlo. No me hagas caso.

Si desea conservar la información de la base (hex / oct / DEC), que tendrá que almacenar esa información por separado del valor entero en sí, y se le requerirá para analizar al menos los dos primeros caracteres de la entrada string (sscanf (), strtol (), etc., no conservar esa información para usted).

Se puede rodar su propio mini-analizador que guarda la base de entrada y realiza la conversión (código de la parte superior de mi cabeza, no probado):

char inputStr[MAX_INPUT_LENGTH+1];
char *p;
int result = 0;
char values[128];

/**
 * This enumeration serves double duty; it keeps track of what
 * base the input was entered in, and it controls the state machine 
 * used to parse the input; from a didactic POV, this is probably bad form
 */
enum {
  eStart, 
  eHexOrOctal, 
  eOctal, 
  eDecimal, 
  eHexadecimal, 
  eError
} eBase = eStart;


/**
 * Use the values array as a table to map character constants to their corresponding 
 * integer values.  This is safer than using an expression like *p - '0', in 
 * that it can work with character encodings where digits are not consecutive.
 * Yes, this wastes a little space, but the convenience makes
 * up for it IMO.  There are probably better ways to do this.
 */
values['0'] = 0; values['1'] = 1; values['2'] = 2; values['3'] = 3; 
values['4'] = 4; values['5'] = 5; values['6'] = 6; values['7'] = 7; 
values['8'] = 8; values['9'] = 9; values['a'] = 10; values['b'] = 11; 
values['c'] = 12; values['d'] = 13; values['e'] = 14; values['f'] = 15;

/**  
 * Insert code to get input string here 
 */

for (p = inputStr; *p != 0; p++)
{
  /**
   * Cycle through each character in the input string, adjusting the state
   * of the parser as necessary.  Parser starts in the eStart state.
   */
  switch(eBase)
  {
    /**
     * Start state -- we haven't parsed any characters yet
     */
    case eStart:
      if (*p == '0') eBase = eHexOrOctal; // leading 0 means either hex or octal
      else if (isdigit(*p))
      {
        eBase = eDecimal;    // leading non-0 digit means decimal
        result = values[*p];  
      }                    
      else eBase = eError;    // no other character may start an integer constant
      break;
    /**
     * HexOrOctal -- we've read a leading 0, which could start either a hex or
     * octal constant; we need to read the second character to make a determination
     */
    case eHexOrOctal:      
      if (tolower(*p) == 'x')  base = eHexadecimal;
      else if (isdigit(*p) && *p != '8' && *p != '9')
      {
        base = eOctal;   
        result = values[*p];
      }
      else eBase = eError;
      break;
    /**
     * Octal -- we are parsing an octal constant
     */
    case eOctal:
      if (isdigit(*p) && *p != '8' && *p != '9')
      {
        result *= 8;
        result += values[*p];
      }
      else eBase = eError;
      break;
    /**
     * Decimal -- we are parsing a decimal constant
     */
    case eDecimal:
      if (isdigit(*p))
      {
        result *= 10;
        result += values[*p];
      }
      else eBase = eError;
      break;
    /**
     * Hexadecimal -- we are parsing a hex constant
     */
    case eHexadecimal:
      if (isxdigit(*p))
      {
        result *= 16;
        result += values[tolower(*p)];
      }
      else eBase = eError;
      break;
    /**
     * String is not a properly formatted integer constant in 
     * any base; once we fall into the error state, we stay there.
     */
    case eError:
    default:
      break;
  }
}
if (eBase != eError)
{
  printf("input: %s ", inputStr); fflush(stdout);
  switch(eBase)
  {
    case eOctal: printf("octal "); break;
    case eHexadecimal: printf("hexadecimal "); break
    default: break;
  }
  fflush(stdout);
  printf("converts to %d decimal\n", result);
}
else
{
  /** Print a suitable error message here */
}

Si literalmente Tienes para utilizar una sola variable entera para el almacenamiento de toda la información que necesita con el fin de visualizar el resultado final, entonces usted tiene que utilizar una parte de la variable entera para almacenar el base original que la entrada era. de lo contrario no es recuperable.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top