代码之家  ›  专栏  ›  技术社区  ›  S.S. Anne

如何修复'itoa'实现,使其不打印反向输出?

  •  0
  • S.S. Anne  · 技术社区  · 7 年前

    我想用C语言把一个整数转换成一个数字字符串。

    我试过使用 itoa ,但它是非标准的,不是我的C库提供的。

    我试着实现我自己的 伊托亚 ,但它不能正常工作:

    #include <stdlib.h>
    #include <stdio.h>
    
    char *itoa(int val, char *buf, int base)
    {
        size_t ctr = 0;
        for( ; val; val /= base )
        {
            buf[ctr++] = '0' + (val % base);
        }
        buf[ctr] = 0;
        return buf;
    }
    
    int main(void)
    {
        unsigned char c = 201;
        char *buf = malloc(sizeof(c)*8+1);
        itoa(c, buf, 2);
        puts(buf);
        free(buf);
    }
    

    它提供反向输出。

    例如,如果 c 'A' base 2 ,输出如下: 0101101

    我希望它的输出是: 1011010

    如何解决此问题?


    类似的问题


    我已经看到了这个问题: Is there a printf converter to print in binary format?

    我不想要一个 printf 格式说明符要将整数打印为二进制,我想将二进制转换为字符串。

    我已经看到了这个问题: Print an int in binary representation using C

    虽然答案确实能将一个整数转换成一串二进制数字,但这是它唯一能做的事情。


    限制


    我想要 伊托亚 能够与其他人一起工作 基础 s、 比如 10 , 8 ,并正确打印(即。 12345 "12345" 而不是 "11000000111001" ).

    我不想用 printf sprintf 这样做。

    我不在乎字符串的长度,只要结果是正确的。

    我不想将整数转换为除数字字符以外的ASCII字符,除了 基础 s大于10,在这种情况下,字符可能是字母数字。

    答案必须完全符合这个原型:

    char *itoa(int val, char *buf, int base);
    

    可能有一个函数名为 nitoa 它有这个原型,并返回保存结果所需的字符数 伊托亚 :

    size_t nitoa(int val, int base);
    
    1 回复  |  直到 7 年前
        1
  •  4
  •   chux    7 年前

    我该如何修复我的手机 itoa 这样就不会打印反向输出了?

    不要颠倒字符串,而是从右向左排列#第四 @user3386109


    我建议helper函数也接收一个大小。

    #include <limits.h>
    
    char* itostr(char *dest, size_t size, int a, int base) {
      // Max text needs occur with itostr(dest, size, INT_MIN, 2)
      char buffer[sizeof a * CHAR_BIT + 1 + 1]; 
      static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
      if (base < 2 || base > 36) {
        fprintf(stderr, "Invalid base");
        return NULL;
      }
    
      // Start filling from the end
      char* p = &buffer[sizeof buffer - 1];
      *p = '\0';
    
      // Work with negative `int`
      int an = a < 0 ? a : -a;  
    
      do {
        *(--p) = digits[-(an % base)];
        an /= base;
      } while (an);
    
      if (a < 0) {
        *(--p) = '-';
      }
    
      size_t size_used = &buffer[sizeof(buffer)] - p;
      if (size_used > size) {
        fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
        return NULL;
      }
      return memcpy(dest, p, size_used);
    }
    

    然后使用 复合文字 .

    // compound literal C99 or later
    #define INT_STR_SIZE (sizeof(int)*CHAR_BIT + 2)
    #define MY_ITOA(x, base) itostr((char [INT_STR_SIZE]){""}, INT_STR_SIZE, (x), (base))
    

    现在你可以多次调用它。

    int main(void) {
      printf("%s %s %s %s\n", MY_ITOA(INT_MIN,10), MY_ITOA(-1,10), MY_ITOA(0,10), MY_ITOA(INT_MAX,10));
      printf("%s %s\n", MY_ITOA(INT_MIN,2), MY_ITOA(INT_MIN,36));
      return (0);
    }
    

    输出

    -2147483648 -1 0 2147483647
    -10000000000000000000000000000000 -ZIK0ZK
    

    注: sizeof(c)*8+1 是不是太小了 INT_MIN ,基地2。

        2
  •  1
  •   S.S. Anne    7 年前

    这个解决方案适合我:

    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define itoa lltoa
    #define utoa ulltoa
    #define ltoa lltoa
    #define ultoa ulltoa
    #define nitoa nlltoa
    #define nutoa nulltoa
    #define nltoa nlltoa
    #define nultoa nulltoa
    
    #define BASE_BIN 2
    #define BASE_OCT 8
    #define BASE_DEC 10
    #define BASE_HEX 16
    #define BASE_02Z 36
    
    __extension__
    char *ulltoa(unsigned long long val, char *buf, int base)
    {
        int remainder;
        char c, *tmp = buf;
    
        if(base < BASE_BIN)
        {
            errno = EINVAL;
            return NULL;
        }
    
        do {
            remainder = val % base;
            if(remainder >= BASE_DEC) c = 'a' - BASE_DEC;
            else c = '0';
            *tmp++ = remainder + c;
            val /= base;
        } while(val);
    
        *tmp = 0;
        return strrev(buf);
    }
    
    __extension__
    size_t nulltoa(unsigned long long val, int base)
    {
        size_t size = 0;
    
        if(base < BASE_BIN)
        {
            errno = EINVAL;
            return 0;
        }
    
        if(!val) size++;
    
        for( ; val; val /= base, size++ );
    
        return size;
    }
    
    __extension__
    char *lltoa(long long val, char *buf, int base)
    {
        if(val < 0 && base > BASE_BIN)
        {
             val = -val;
             *buf++ = '-';
        }
    
        return ulltoa(val, buf, base);
    }
    
    __extension__
    size_t nlltoa(long long val, int base)
    {
        size_t size = 0;
    
        if(val < 0 && base > BASE_BIN)
        {
            val = -val;
            size++;
        }
    
        return size + nulltoa(val, base);
    }