Convert integer to string without access to libraries

Viewed 39560

I recently read a sample job interview question:

Write a function to convert an integer to a string. Assume you do not have access to library functions i.e., itoa(), etc...

How would you go about this?

13 Answers

The faster the better?

unsigned countDigits(long long x)
{
    int i = 1;
    while ((x /= 10) && ++i);
    return i;
}
unsigned getNumDigits(long long x)
{
    x < 0 ? x = -x : 0;
    return
        x < 10 ? 1 :
        x < 100 ? 2 :
        x < 1000 ? 3 :
        x < 10000 ? 4 :
        x < 100000 ? 5 :
        x < 1000000 ? 6 :
        x < 10000000 ? 7 :
        x < 100000000 ? 8 :
        x < 1000000000 ? 9 :
        x < 10000000000 ? 10 : countDigits(x);
}
#define tochar(x) '0' + x
void tostr(char* dest, long long x)
{
    unsigned i = getNumDigits(x);
    char negative = x < 0;
    if (negative && (*dest = '-') & (x = -x) & i++);
    *(dest + i) = 0;
    while ((i > negative) && (*(dest + (--i)) = tochar(((x) % 10))) | (x /= 10));
}

If you want to debug, You can split the conditions (instructions) into
lines of code inside the while scopes {}.

Convert integer to string without access to libraries

Convert the least significant digit to a character first and then proceed to more significant digits.


Normally I'd shift the resulting string into place, yet recursion allows skipping that step with some tight code.

Using neg_a in myitoa_helper() avoids undefined behavior with INT_MIN.

// Return character one past end of character digits.
static char *myitoa_helper(char *dest, int neg_a) {
  if (neg_a <= -10) {
    dest = myitoa_helper(dest, neg_a / 10);
  }
  *dest = (char) ('0' - neg_a % 10);
  return dest + 1;
}

char *myitoa(char *dest, int a) {
  if (a >= 0) {
    *myitoa_helper(dest, -a) = '\0';
  } else {
    *dest = '-';
    *myitoa_helper(dest + 1, a) = '\0';
  }
  return dest;
}

void myitoa_test(int a) {
  char s[100];
  memset(s, 'x', sizeof s);
  printf("%11d <%s>\n", a, myitoa(s, a));
}

Test code & output

#include "limits.h"
#include "stdio.h"

int main(void) {
  const int a[] = {INT_MIN, INT_MIN + 1, -42, -1, 0, 1, 2, 9, 10, 99, 100,
      INT_MAX - 1, INT_MAX};
  for (unsigned i = 0; i < sizeof a / sizeof a[0]; i++) {
    myitoa_test(a[i]);
  }
  return 0;
}

-2147483648 <-2147483648>
-2147483647 <-2147483647>
        -42 <-42>
         -1 <-1>
          0 <0>
          1 <1>
          2 <2>
          9 <9>
         10 <10>
         99 <99>
        100 <100>
 2147483646 <2147483646>
 2147483647 <2147483647>

I came across this question so I decided to drop by the code I usually use for this:

char *SignedIntToStr(char *Dest, signed int Number, register unsigned char Base) {
    if (Base < 2 || Base > 36) {
        return (char *)0;
    }
    register unsigned char Digits = 1;
    register unsigned int CurrentPlaceValue = 1;
    for (register unsigned int T = Number/Base; T; T /= Base) {
        CurrentPlaceValue *= Base;
        Digits++;
    }
    if (!Dest) {
        Dest = malloc(Digits+(Number < 0)+1);
    }
    char *const RDest = Dest;
    if (Number < 0) {
        Number = -Number;
        *Dest = '-';
        Dest++;
    }
    for (register unsigned char i = 0; i < Digits; i++) {
        register unsigned char Digit = (Number/CurrentPlaceValue);
        Dest[i] = (Digit < 10? '0' : 87)+Digit;
        Number %= CurrentPlaceValue;
        CurrentPlaceValue /= Base;
    }
    Dest[Digits] = '\0';
    return RDest;
}
#include <stdio.h>
int main(int argc, char *argv[]) {
    char String[32];
    puts(SignedIntToStr(String, -100, 16));
    return 0;
}

This will automatically allocate memory if NULL is passed into Dest. Otherwise it will write to Dest.

This is the shortest function I can think of that:

  • Correctly handles all signed 32-bit integers including 0, MIN_INT32, MAX_INT32.

  • Returns a value that can be printed immediatelly, e.g.: printf("%s\n", GetDigits(-123))

Please comment for improvements:

static const char LARGEST_NEGATIVE[] = "-2147483648";

static char* GetDigits(int32_t x) {
    char* buffer = (char*) calloc(sizeof(LARGEST_NEGATIVE), 1);

    int negative = x < 0;
    if (negative) {
        if (x + (1 << 31) == 0) { // if x is the largest negative number
            memcpy(buffer, LARGEST_NEGATIVE, sizeof(LARGEST_NEGATIVE));
            return buffer;
        }
        x *= -1;
    }

    // storing digits in reversed order
    int length = 0;
    do {
        buffer[length++] = x % 10 + '0';
        x /= 10;
    } while (x > 0);

    if (negative) {
        buffer[length++] = '-'; // appending minus
    }

    // reversing digits
    for (int i = 0; i < length / 2; i++) {
        char temp = buffer[i];
        buffer[i] = buffer[length-1 - i];
        buffer[length-1 - i] = temp;
    }
    return buffer;
}
//Fixed the answer from [10]

#include <iostream>

void CovertIntToString(unsigned int n1)
{
    unsigned int n = INT_MIN;
    char buffer[50];
    int i = 0;
    n = n1;

    bool isNeg = n<0;
    n1 = isNeg ? -n1 : n1;

    while(n1!=0)
    {
        buffer[i++] = n1%10+'0';
        n1=n1/10;
    }

    if(isNeg)
        buffer[i++] = '-';

    buffer[i] = '\0';

    // Now we must reverse the string
    for(int t = 0; t < i/2; t++)
    {
        buffer[t] ^= buffer[i-t-1];
        buffer[i-t-1] ^= buffer[t];
        buffer[t] ^= buffer[i-t-1];
    }

    if(n == 0)
    {
        buffer[0] = '0';
        buffer[1] = '\0';
    }

    printf("%s", buffer);
}

int main() {
    unsigned int x = 4156;
    CovertIntToString(x);
    return 0;
}
Related