1

I have been trying to write a recursive version of function itoa, the code is shown below.

void itoa(int n, char s[])
{
     static int i = 0;

     if(n / 10 != 0)
         itoa(n/10, s);
     else if(n < 0)
         i = 1; /* s[0] is allready taken by - sign */
     else 
         i = 0; /* reset i to 0 */

     if(n < 0) {
          s[0] = '-';
     }

     s[i++] = abs(n % 10) + '0';
     s[i] = '\0';
}

But the code is not ideal. It uses a static variable and probably is not executing as fast as it should be. I am trying to achieve a O(n) algorithm. Could anyone show me a better way? I also think that static variable is not necesary, but I'm not pretty sure how to avoid it. Should I break the function into two inorder to avoid the static variable?

Deepu
  • 7,592
  • 4
  • 25
  • 47
Tool
  • 12,126
  • 15
  • 70
  • 120
  • http://users.powernet.co.uk/eton/kandr2/krx4.html i blame them for having awful, and i mean AWFUL solutions to those exercises in K&R. Im actually planing on opening my own website with solutions. Just look at them! – Tool Jan 03 '10 at 02:00
  • 1
    Why exactly wouldn't this be in O(n)? I mean, n is divided by 10 in each iteration, so it's even O(log n). – thiton Sep 18 '11 at 15:41

4 Answers4

3

If you want to solve it recursively, an easier approach might be to return the last index:

int itoa(int n, char s[])
{
    int i =  0;         

    if(n / 10 != 0)
        i = itoa(n/10, s);
    else if(n < 0)
        s[i++] = '-';

    s[i++] = abs(n % 10) + '0';
    s[i] = '\0';

    return i;
}

You could also solve it using pointers:

char * itoa(int n, char * s)
{
    char * dest = s;

    if(n / 10 != 0)
        dest = itoa(n/10, dest);
    else if(n < 0)
        *dest++ = '-';

    *dest++ = abs(n % 10) + '0';
    *dest = '\0';

    return dest;
}

However on thing to note is that this implementation is prone to buffer overflows. You need to be certain that you have allocated a sufficiently large buffer to fit the entire ascii representation of the integer. A good idea would be to include some boundary checking.

Yannick Motton
  • 34,761
  • 4
  • 39
  • 55
  • in the first function you wrote. what is dest? – Tool Jan 03 '10 at 01:41
  • To your question "Shouldn't it be s + i": No, if the recursive function gets called, the returnvalue `i` will countain the last index of the buffer (the place where we need to append). So the innermost call to itoa will return 1 or 2 (depending on the sign of n), and as you go to the outer most call, i is incremented as digits get added to the buffer. – Yannick Motton Jan 03 '10 at 01:52
  • @YannickMotton Don't you return a pointer to the end of the string here ? – Fayeure Apr 13 '21 at 17:22
  • @Fayeure Yes. This was offered as a solution to the OP's question: how to implement itoa recursively. In order for the calling function to alter control flow, state needs to be passed between caller and callee. Typical way of doing this is via the return value of the function. This function injects state into the target buffer and the return value is indeed the end of the string. – Yannick Motton Apr 14 '21 at 14:38
2

itoa should return void.
I haven't tested this, but I believe it will work.
No static variables, no helper functions, no extra arguments.
The redundant integer division in the while loop may be a weakness.

void itoa(int n, char *s)  
{  
    char c;  
    if (n < 0)  
    {  
        *s++ = '-';  
        itoa(-n, s);  
        return;  
    }  
    c = '0' + n % 10;  
    itoa(n / 10, s);  
    while ( n /= 10 ) s++;  
    *s++ = c;  
    *s = '\0';  
}  
1
char* itoa(int n, char s[]) {
  if (n < 0) {
    s[0] = '-';
    return itoa(-n, s+1);
  }
  if (n/10 > 0) {
     s = itoa(n/10, s);
  }
  s[0] = '0' + (n%10);
  s[1] = '\0';
  return &s[1];
}

You also have the feature that itoa returns the address of the end of the string.

Oren
  • 2,767
  • 3
  • 25
  • 37
1

Amazing solution though one small problem. This code receives segmentation fault because the base case of recursion : when n==0 isn't handled properly. I made a small change to your program and now it works fine.

void itoa(int n,char *s)
{
    char c;
    if (n < 0)
    {
        *s++ = '-';
        itoa(-n, s);
        return;
    }
    if (n==0)
        return;
    c = '0' + n % 10;
    itoa(n/10,s);
    while ( n /= 10 ) s++;
    *s++ = c;
    *s = '\0';
}

Now for my own two-pence, I solved this without using division but instead using double pointers for the values to persist between function calls.

Only demerit of my solution is that we need to preserve the starting address of the character array.

void itoa(char**a,int i)
{
    int dig;
    if(i<10) //base case;
    {
        **a=i+48;
        *(++(*a))='\0';
        return;
    }
    dig=i%10;
    itoa(a,i/10);
    **a=dig+48;  //char value + 48 will give me the corresponding value
    *(++(*a))='\0';
    return;
}

int main()
{
    char* t=(char*)malloc(sizeof(char)*5);
    char* save=t;
    int ti=1234;
    itoa(&t,ti);
    printf("%s",save);
}
axel22
  • 32,045
  • 9
  • 125
  • 137