Search code examples
cstringbinaryitoa

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


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

Solution

  • 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.