K&Rを読もう(37) 演習3-4 - 3-6 itoa

今回は数値を文字列に変換する問題。

演習 3-4

サンプルのitoaはINT_MINの値が正しく処理出来ない。何故か&修正せよ。

まず、INT_MAX,INT_MINの値を確認する。

INT_MAX  2147483647 01111111111111111111111111111111
INT_MIN -2147483648 10000000000000000000000000000000

すると、INT_MIN * -1をすると、数値がオーバーフローしてしまう事がわかる。知らなかった・・・。

正しく表示させるには、正の処理、負の処理は別々に処理する必要がある。

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

    if (n >= 0) {
        do
            s[i++] = n % 10 + '0';
        while ((n /= 10) > 0 && size - 1);
    } else {
        do
            s[i++] = -(n % 10) + '0';
        while ((n /= 10) < 0 && size - 1);
        s[i++] = '-';
    }
    s[i] = '\0';
    reverse(s);
}

演習 3-5

符号なし整数を任意の基数変換をする。36進数まで対応してみた。

void itob (unsigned int n, char s[], int size, int b)
{
    int i = 0;
    int c;

    if (b > 'Z' - 'A' + 1 + 10)
        exit(EXIT_FAILURE);
    do {
        c = (n % b);
        s[i++] = c + ((c < 10) ?  '0' : 'A' - 10);
    } while ((n /= b) > 0 && i < size - 1);
    s[i] = '\0';
    reverse(s);
}

演習 3-6

itoaを右詰めにする。

void itoa2(int n, char s[], int size, int field)
{
    int i, len;

    itoa(n, s, size);
    len = strlen(s);
    if (len > field || field > size)
        exit(EXIT_FAILURE);
    s[field + 1] = '\0';
    for (i = len; i >= 0; i--)
        s[field - len + i] = s[i];
    for (i = 0; i < field - len; i++)
        s[i] = ' ';
}

itoaを利用して文字列を作って、地道に右に詰めてみた。

フィールド幅が足りないときはエラーにした。