【问题标题】:Convert an number with arbitrary length from decimal to hex in c++在c ++中将任意长度的数字从十进制转换为十六进制
【发布时间】:2013-03-14 11:15:05
【问题描述】:

我已经看到了几个将数字从十进制转换为十六进制(或以 10 为底数为 16 进制)的示例,但我对我正在尝试做的事情有一些限制。我需要能够将带有十进制数字的字符串转换为另一个字符串作为十六进制数字。该数字可能太大而无法容纳在任何原始数据类型中 - 即:不能使用整数、无符号整数、双精度数等...

这应该能够执行与此页面上列出的相同的计算。 http://www.kaagaard.dk/service/convert.htm

我试过这个,但对我没有用。

函数调用:

const int maxLen = 256;
char destination[maxLen];
int retVal = convertBase(destination, maxLen, "123487032174829820348320429437483266812812");

函数定义:

int convertBase(char* dest, int maxDestLength, const char* inputInBase10)
{
    const char lookUpTable[] = { "0123456789abcdef" };
    const std::string input = inputInBase10;
    const unsigned int inputSize = input.length();

    std::string output;
    output.reserve(2 * inputSize);

    for(unsigned int i = 0; i < inputSize; ++i)
    {
        const unsigned char c = input[i];
        output.push_back(lookUpTable[c >> 4]);  
        output.push_back(lookUpTable[c & 15]);
    }

    if(output.length() < maxDestLength)
        strcpy_s(dest, output.length(), output.c_str());
    else
        strcpy_s(dest, maxDestLength, output.c_str());

    cout << dest << endl;

    return strlen(dest);
}

预期的十六进制数:“16ae5514d07e120126dfbcb3073fddb2b8c”

生成的实际十六进制数:“313233343837303332313734383239383230333438333230343239343337343833323636383132383132”

另外,当传递回 char* 时,我不断收到一个错误,即缓冲区太小(在下面重复)

    if(output.length() < maxDestLength)
        strcpy_s(dest, output.length(), output.c_str());
    else
        strcpy_s(dest, maxDestLength, output.c_str());

【问题讨论】:

  • 您正在将输入字符串中数字的 ASCII 值转换为十六进制,而不是输入字符串表示的实际数字。
  • 这里有一个提示:你得到的输出 ("313233343837") 看起来像你输入数字字符的 ASCII 值(在字符串中编码为十六进制字节) - 例如0x38 == '8'
  • 这种东西一般需要做长除法,但是没有长除法的时候,可以通过一系列的加法来构建。这必须是最优的吗?我有一个非最优但简单的解决方案。
  • 最佳方案是首选,但欢迎任何解决方案。
  • 嗯,我的回答应该对你有所帮助。顺便说一句,它正确转换了您在示例中提供的号码,而您链接到的号码服务无法处理它。

标签: c++ string algorithm hex decimal


【解决方案1】:

因此,如果您急于获得任何东西,并且不太关心效率,请试试这个。我已经修改了我为以下 SO 问题编写的函数:c++ string (int) + string (int)

首先,我修改了Add 函数,使其适用于 2 到 36 之间的任何基数:

const int MIN_BASE = 2;
const int MAX_BASE = 36;

static bool tablesInitialised = false;
static char tblIntToChar[MAX_BASE] = {0};
static int tblCharToInt[256] = {0};

void InitTables()
{
    if( tablesInitialised ) return;

    for( int i = 0; i < 10; i++ ) {
        tblIntToChar[i] = '0' + i;
        tblCharToInt[tblIntToChar[i]] = i;
    }

    for( int i = 0; i < 26; i++ ) {
        tblIntToChar[i+10] = 'a' + i;
        tblCharToInt['a' + i] = i + 10;
        tblCharToInt['A' + i] = i + 10;
    }

    tablesInitialised = true;
}


// Adds two numbers using long addition.
string Add( const string& a, const string& b, int base=10 )
{
    InitTables();
    if( base > MAX_BASE || base < MIN_BASE ) return "";

    // Reserve storage for the result.
    string result;
    result.reserve( 1 + std::max(a.size(), b.size()) );

    // Column positions and carry flag.
    int apos = a.size();
    int bpos = b.size();
    int carry = 0;

    // Do long arithmetic.
    while( carry > 0 || apos > 0 || bpos > 0 )
    {
        if( apos > 0 ) carry += tblCharToInt[(unsigned char)a[--apos]];
        if( bpos > 0 ) carry += tblCharToInt[(unsigned char)b[--bpos]];
        result.push_back(tblIntToChar[carry%base]);
        carry /= base;
    }

    // The result string is backwards.  Reverse and return it.
    reverse( result.begin(), result.end() );
    return result;
}


// Converts a single value to some base, intended for single-digit conversions.
string AsBase( int number, int base )
{
    InitTables();
    if( number <= 0 ) return "0";
    string result;
    while( number > 0 ) {
        result += tblIntToChar[number%base];
        number /= base;
    }
    reverse( result.begin(), result.end() );
    return result;
}

并且,使用上述所有内容,这是一个从一个任意基数转换为另一个基数的函数:

// Converts a number from one base to another.
string ConvertBase( const string & number, int oldBase, int newBase )
{
    InitTables();
    string result;

    for( unsigned digit = 0; digit < number.size(); digit++ )
    {
        int value = tblCharToInt[(unsigned char)number[digit]];
        if( result.empty() )
        {
            result = AsBase( value, newBase );
        }
        else 
        {
            string temp = result;
            for( int i = 1; i < oldBase; i++ ) {
                temp = Add( result, temp, newBase );
            }
            result = Add( temp, AsBase(value, newBase), newBase );
        }
    }

    return result;
}

这只是我使用我在 StackOverflow 的“有趣”沙箱中经常使用的代码破解的东西。它执行oldBase 加法的方式非常笨拙,而不仅仅是一次乘法。如果你用Multiply 函数来做长乘法,这会好很多。

【讨论】:

    【解决方案2】:

    您无法通过单独检查每个字符来解决问题。原因是在决定使用哪个十六进制数字时需要考虑两个字符。

    例如,“12”将正确表示为“C”,而您的算法不会考虑到这一点。

    你也应该从右到左而不是从左到右阅读

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-31
      • 2013-07-20
      • 2012-06-17
      • 2018-11-18
      • 2021-06-26
      • 2018-01-03
      • 2015-01-26
      相关资源
      最近更新 更多