1

我正在尝试编写一个程序,该程序接受十六进制、八进制和十进制的输入,将它们存储在整数变量中,并将它们与转换为十进制形式一起输出。例如:

用户输入:0x43、0123、65

程序输出:

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

所以很明显我需要一种方法来解释这些数字,但我不知道如何去做。我尝试了各种方法,例如将它们读入函数并将它们转换为字符串,反之亦然(参见此处的代码示例),但解释数字总是需要转换为某种格式,从而破坏原始输入。

我唯一能想到的就是重载一个一次读取一个字符的 >> 运算符,如果它在输入的开头看到 0x 或 0,那么它将整个输入存储到一个字符串中,然后再将其读入一个 int。然后程序将不得不在输出期间以某种方式确定正确的操纵器。

不知道是否有更简单的方法来做到这一点,任何帮助表示赞赏。

编辑:这已经解决了,但如果有人感兴趣,我决定发布代码。

#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();
}
4

5 回答 5

11

看一下 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);
}

输出:

0x43 converts to 67 decimal
0123 converts to 83 decimal
65 converts to 65 decimal
于 2009-07-28T18:47:24.427 回答
1

您总是可以将其存储为一个字符串开始,并查看前两个字符以查看它们是否为 0x:

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

if (num[0] == '0' && num[1] == 'x')
{ 
  //handle
}
于 2009-07-28T18:48:15.047 回答
1

我不确定是否有 C++ 方法可以做到这一点,但如果你不介意一点 C 风格,你可以将它读入一个char数组并使用类似sscanf(buffer, "%i", &output). %i就像您描述的那样,根据其格式将输入解释为十六进制、八进制或十进制。

编辑:啊,不知道也strtol可以这样做。不理我。

于 2009-07-28T18:49:46.417 回答
1

如果要保留基本信息(十六进制/八进制/十进制),则需要将该信息与整数值本身分开存储,并且至少需要解析输入字符串的前几个字符(sscanf ()、strtol() 等不会为您保留该信息)。

您可以使用自己的迷你解析器来保存输入库并进行转换(代码从我的脑海中浮出,未经测试):

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 */
}
于 2009-07-28T21:29:02.663 回答
0

如果您确实必须使用单个整数变量来存储显示最终输出所需的所有信息,那么您必须使用整数变量的一部分来存储输入所在的原始基数。否则不可恢复。

于 2009-07-28T18:48:01.303 回答