How do I fix my `itoa` implementation so it doesn't print reversed output?

此生再无相见时 提交于 2020-01-24 12:36:47

问题


I want to convert an integer into a string of numeric characters in C.

I've tried using itoa, but it's non-standard and not provided by my C library.

I tried to implement my own itoa, but it's not working properly:

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

It gives reversed output.

For example, if c is 'A' and base is 2, the output is this: 0101101

The output I want it to be is this: 1011010

How do I fix this issue?


Similar questions


I've already seen this question: Is there a printf converter to print in binary format?

I do not want a printf format specifier to print an integer as binary, I want to convert the binary to a string.

I've already seen this question: Print an int in binary representation using C

Although the answer does convert an integer into a string of binary digits, that's the only thing it can do.


Restrictions


I want itoa to be able to work with other bases, such as 10, 8, etc. and print correctly (i.e. 12345 translates to "12345" and not to "11000000111001").

I do not want to use printf or sprintf to do this.

I do not care about the length of the string as long is the result is correct.

I do not want to convert the integer into ASCII characters other than numeric ones, with the exception of bases greater than 10, in which case the characters may be alphanumeric.

The answer must fit this prototype exactly:

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

There may be a function called nitoa that has this prototype and returns the number of characters required to hold the result of itoa:

size_t nitoa(int val, int base);

回答1:


How do I fix my itoa implementation so it doesn't print reversed output?

Rather than reverse the string, form it right-to-left. #4 of @user3386109


I recommend the helper function also receives in a size.

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

Then to provide memory, use a compound literal.

// 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))

Now you can call it multiple times.

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);
}

Output

-2147483648 -1 0 2147483647
-10000000000000000000000000000000 -ZIK0ZK

Note: sizeof(c)*8+1 is one too small for INT_MIN, base 2.




回答2:


This solution works for me:

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


来源:https://stackoverflow.com/questions/56402852/how-do-i-fix-my-itoa-implementation-so-it-doesnt-print-reversed-output

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!