You know, your version of itoa is really bad. There is no limit on the array "s" given to the function, so no way to limit the number of writes into the array. Beyond what kzinti pointed out, writing to memory twice is just fundamentally bad. And you are giving a variable base to the function, but then end up not using it in two places. Using abs() in the loop is also unnecessary, you can factor that out.
Indeed writing a version that works under all circumstances is an interesting challenge. You can't necessarily turn a negative number positive, but you can always do it the other way around. That does mean working with negative numbers. The C standard allows two ways integer division can work with negative numbers (essentially, rounding the quotient towards zero or towards negative infinity), but in practice I have only ever seen the former. So I would likely do it like this:
Code: Select all
#if -5 % 3 != -2
#error "Your compiler is not using symmetric modulo. Adjust this code."
#endif
#include <stddef.h>
#include <assert.h>
int itoa(int a, int base, char *s, size_t len)
{
int sgn = 0;
if (a >= 0) a = -a;
else sgn = 1;
assert(base - 2u < 34u);
size_t num_dig = 0;
int x = a;
do {
num_dig++;
x /= base;
} while (x);
if (sgn) num_dig++;
if (num_dig >= len) return -1;
s[num_dig--] = 0;
do {
s[num_dig] = '0' - a % base;
if (s[num_dig] > '9') s[num_dig] += 'a' - '9' + 1;
num_dig--;
a /= base;
} while (a);
if (sgn) *s = '-';
return 0;
}
Yes, the code assumes an ASCII machine. It also assumes symmetric modulo. Adjusting for mathematical modulo is not easy. In that case, repeated division would raise the number to -1 rather than 0, and the modulo would return the exact opposite digit, except if it returns zero. Thankfully that case is rare.