5

我知道'strtoll',但它将任何基数(2到36之间)转换为十进制,我需要通过将十进制转换为任何基数来做相反的事情,

一个例子是十进制 130 基数 12 = AA

4

3 回答 3

6

以下代码使用临时缓冲区来构建字符串,然后返回一个副本。该字符串是通过从末尾向后工作并通过索引到另一个字符串来设置每个数字来构建的。这应该比所有重复的短字符串复制和附加 Java 版本更有效。您需要在使用完返回的字符串后释放它们,并检查是否返回 NULL 如果基数可能超出范围......以避免一直分配新字符串,您可能希望对其进行调整以使用您为结果提供的缓冲区。

/* return string representation of num in base rad as new string (or NULL) */
char *toBaseWhatever(int num, int rad)
{
    char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    int i;
    char buf[66];   /* enough space for any 64-bit in base 2 */

    /* bounds check for radix */
    if (rad < 2 || rad > 62)
        return NULL;
    /* if num is zero */
    if (!num)
        return strdup("0");

    /* null terminate buf, and set i at end */
    buf[65] = '\0';
    i = 65;

    if (num > 0) {  /* if positive... */
        while (num) { /* until num is 0... */
            /* go left 1 digit, divide by radix, and set digit to remainder */
            buf[--i] = digits[num % rad];
            num /= rad;
        }
    } else {    /* same for negative, but negate the modulus and prefix a '-' */
        while (num) {
            buf[--i] = digits[-(num % rad)];
            num /= rad;
        }
        buf[--i] = '-';
    }   
    /* return a duplicate of the used portion of buf */
    return strdup(buf + i);
}
于 2013-09-29T00:29:03.593 回答
2

如果不需要您自己创建,“strtoll”或“strtoull”将为您进行转换:

   long long           i64 = 0x8000000000000000LL;
    unsigned long long  u64 = 0xFFFFFFFFFFFFFFFFULL;

    printf("Signed long long:   %lld\n", i64);
    printf("Unsigned long long: %llu\n", u64);
    printf("\n");

    char buffer[30];
    sprintf(buffer, "%lld", i64);
    i64 = atoll(buffer);
    i64 = strtoll(buffer, NULL, 10);
    u64 = strtoull(buffer, NULL, 10);  

[编辑] 这个编辑是为了回应(纯粹是为了好玩)@willus 关于他和@dmitri 的解决方案之间的时间安排的评论,并增加了三分之一。
就纯粹的速度而言,Dmitri 的产品胜出,但包括内存泄漏。它以不释放内存的方式使用 strdup() 函数。strdupa() 是一种释放其分配内存的替代方法,在这里将是一个很好的替代方法。而且,如果strdup()strdupa()根本不使用,@Dmitri 的代码(正如@willus 所指出的)将运行得更快。

归功于 AnyRadixConvert函数的此实现。

以下是通过整数 0 - 5001 运行的三个中每一个的结果:
在此处输入图像描述

以下是产生这些结果的代码:(_note:存在细微变化,例如,我没有strdup(),但有StrDup()

#include "toolbox.h" //StrDup(), delete otherwise
#include <ansi_c.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAXLEN_127 127

void delaySome(void);  //test the timers...

int AnyRadixConvert(const char* oldNumber, int oldRadix,
                           char* newNumber, int newRadix);

///Willus
static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen);
static void insert_char(char *s,int c,int maxlen);
static int digit(int x);

////Dmitri
char *dmitri_toBaseWhatever(int num, int rad);


int main(void)
{
   char dataIn[66]="5001";
   char dataOut[66];
   int radixFrom = 10;
   int radixTo = 2;
   long long int i=0;

   //support willus_decimal_to_radix_base
    int x;

    //support Dmitri
   char demitri_result[66];
   demitri_result[0]=0;
   int dataInNum;
   int maxInAll = 5001;

    /*Converts from base x to base y*/  //values from 2 to 36 for either parameter
    //time it
    // Delay(1);
    clock_t start, end;
    long double elapsed1, elapsedWillus, elapsedDimitri;
    start = clock();
    //end time it

    for(i=0;i<=maxInAll;i++)
    {
        sprintf(dataIn, "%lld", i);
        AnyRadixConvert(dataIn,radixFrom,dataOut,radixTo);
    }
    //end timeit
    end = clock();
    elapsed1 = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("AnyRadixConvert:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n"             ,radixFrom,dataIn,radixTo, dataOut, elapsed1);

//willus_decimal_to_radix_base

    x=atol(dataIn);
    dataOut[0]=0;
    start = clock();
    for(i=0;i<=maxInAll;i++)
    {
        willus_decimal_to_radix_base(dataOut,(int)i,radixTo,MAXLEN_127);
    }
    end = clock();
    elapsedWillus = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("willus_decimal_to_radix_base:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n",radixFrom,dataIn,radixTo, dataOut, elapsedWillus);

//dimitri_toBaseWhatever    

    dataInNum = atol("123123132");
    start = clock();
    for(i=0;i<=maxInAll;i++)
    {
        strcpy(demitri_result, dmitri_toBaseWhatever((int)i, radixTo));
    }

    end = clock();
    elapsedDimitri = ((double) (end - start)) / CLOCKS_PER_SEC;
    printf("dimitri_toBaseWhatever:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n"      ,radixFrom,dataIn,radixTo, demitri_result, elapsedDimitri);

   //////////////////////////
    getchar();
    return 0;
}

int AnyRadixConvert(const char* oldNumber, int oldRadix, char* newNumber, int newRadix)
{
    long dataIn = 0L;
    char digit = 0;
    int i = 0;
    int size=strlen(oldNumber);
    char* reverseNew = NULL;

    /*Checks if base if within bounds*/
    if((oldRadix<=1 || oldRadix>36)||(newRadix<=1 || newRadix>36))
    {
        return 0;
    }
    /*Convert to base 10 from old base*/
    for(i=0;i<size;i++)
    {
        if(oldNumber[i]>='0' && oldNumber[i]<='9')
        {
            dataIn+=(oldNumber[i]-'0')*pow(oldRadix,size-i-1);
        }
        else if(oldNumber[i]>='A' && oldNumber[i]<='Z')
        {
            dataIn+=(oldNumber[i]-'A' + 10)*pow(oldRadix,size-i-1);
        }
        else
        {
            return -1;
        }
    }
    i=0;
    /*Convert from base 10 to new base*/
    while(dataIn>0)
    {
        digit = dataIn % newRadix;
        (digit<10)?(newNumber[i] = digit + '0')
                  :(newNumber[i] = digit + 'A' -10);
        dataIn=dataIn/newRadix;
        i++;
    }
    newNumber[i]='\0';
    /*Reverses newNumber*/
    reverseNew = (char*)(malloc(sizeof(char)*strlen(newNumber)+1));
    reverseNew[0]=0;
    size = strlen(newNumber);
    for(i=size-1; i>=0; i--)
    {
        reverseNew[i] = newNumber[size-1-i];
    }
    reverseNew[size]='\0';
    strcpy(newNumber,reverseNew);
    free(reverseNew);
    return 1;
}


static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen)

    {
    int sign;

    sign= (x<0) ? -1 : 1;
    if (x<0)
        x=-x;
    s[0]='\0';
    if (x==0)
        {
        if (maxlen > 0)
            strcpy(s,"0");
        return;
        }
    while (x>0)
        {
        int r;
        r=x%base;
        insert_char(s,digit(r),maxlen);
        x /= base;
        }
    if (sign<0)
        insert_char(s,'-',maxlen);
    }

static void insert_char(char *s,int c,int maxlen)

    {
    int len;

    len=strlen(s);
    if (len>=maxlen)
        memmove(&s[1],s,len-1);
    else
        memmove(&s[1],s,len+1);
    s[0]=c;
    }


static int digit(int x)

    {
    if (x<10)
        return('0'+x);
    return('A'+x-10);
    }

////Dimitri
/* return string representation of num in base rad as new string (or NULL) */
char *dmitri_toBaseWhatever(int num, int rad)
{
    char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    int i;
    char buf[66];   /* enough space for any 64-bit in base 2 */
    buf[0]=0;

    /* bounds check for radix */
    if (rad < 2 || rad > 62)
        return NULL;
    /* if num is zero */
    if (!num)
        return StrDup("0");
        //return strdup("0");

    /* null terminate buf, and set i at end */
    buf[65] = '\0';
    i = 65;

    if (num > 0) {  /* if positive... */
        while (num) { /* until num is 0... */
            /* go left 1 digit, divide by radix, and set digit to remainder */
            buf[--i] = digits[num % rad];
            num /= rad;
        }
    } else {    /* same for negative, but negate the modulus and prefix a '-' */
        while (num) {
            buf[--i] = digits[-(num % rad)];
            num /= rad;
        }
        buf[--i] = '-';
    }   
    /* return a duplicate of the used portion of buf */
    return StrDup(buf + i);
    //return strdup(buf + i);
}

void delaySome(void) //test the timer
{
    time_t x = clock();
    while ((clock() - x)<1000); 
}
于 2013-09-28T22:39:49.677 回答
2

尝试这个。

#include <stdio.h>
#include <string.h>

static void decimal_to_radix_base(char *s,int x,int base,int maxlen);
static void insert_char(char *s,int c,int maxlen);
static int digit(int x);


void main(void)

    {
    int x,base;
    char s[128];

    x=130;
    base=12;
    decimal_to_radix_base(s,x,base,127);
    printf("%d base %d = %s\n",x,base,s);
    }


static void decimal_to_radix_base(char *s,int x,int base,int maxlen)

    {
    int sign;

    sign= (x<0) ? -1 : 1;
    if (x<0)
        x=-x;
    s[0]='\0';
    if (x==0)
        {
        if (maxlen > 0)
            strcpy(s,"0");
        return;
        }
    while (x>0)
        {
        int r;
        r=x%base;
        insert_char(s,digit(r),maxlen);
        x /= base;
        }
    if (sign<0)
        insert_char(s,'-',maxlen);
    }


static void insert_char(char *s,int c,int maxlen)

    {
    int len;

    len=strlen(s);
    if (len>=maxlen)
        memmove(&s[1],s,len-1);
    else
        memmove(&s[1],s,len+1);
    s[0]=c;
    }


static int digit(int x)

    {
    if (x<10)
        return('0'+x);
    return('A'+x-10);
    }
于 2013-09-29T00:20:35.130 回答