diff options
author | zlg <zlg@zlg.space> | 2013-04-20 07:33:45 -0500 |
---|---|---|
committer | zlg <zlg@zlg.space> | 2013-04-20 07:33:45 -0500 |
commit | d8c9ddf97c92d9dd3146a478c04b96b996d6d5c4 (patch) | |
tree | c4ad5a36e4803a0237c6ff0e875b02034ef4098e /ch3 | |
parent | Solve Exercise 3-4: itoa improved (diff) | |
download | knr-d8c9ddf97c92d9dd3146a478c04b96b996d6d5c4.tar.gz knr-d8c9ddf97c92d9dd3146a478c04b96b996d6d5c4.tar.bz2 knr-d8c9ddf97c92d9dd3146a478c04b96b996d6d5c4.tar.xz knr-d8c9ddf97c92d9dd3146a478c04b96b996d6d5c4.zip |
Solve Exercise 3-5: itob
Diffstat (limited to 'ch3')
-rw-r--r-- | ch3/3-05_itob.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/ch3/3-05_itob.c b/ch3/3-05_itob.c new file mode 100644 index 0000000..58066e5 --- /dev/null +++ b/ch3/3-05_itob.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <string.h> +#include <limits.h> + +/* The C Programming Language: 2nd Edition + * + * Exercise 3-5: Write the function itob(n,s,b) that converts the integer n + * into a base b character representation in the string s. In particular, + * itob(n,s,16) formats n as a hexadecimal integer in s. + * + * Answer: Retool the itoa() function written for 3-4 to take an additional + * argument, then add a few more checks and account for ASCII's 7-character + * distance between '9' and 'A', which makes bases higher than 16 function + * without a large switch statement. + */ + +void reverse(char s[]) { + int c, i, j; + + for (i = 0, j = strlen(s)-1; i < j; i++, j--) { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } +} + +void itob(int n, char s[], unsigned b) { + int i, sign, min, rem; // Add 'min' for later use + + if ((sign = n) < 0) { + /* Detect this and add one so it can properly be made positive */ + if (n == INT_MIN) { + n += 1; + min = 1; + } + n = -n; + } + i = 0; + if (b > 1) { + do { + /* If it's the first iteration of the loop and we've established + * that n == INT_MIN, we need to add one to the resulting string for it + * to be displayed properly. */ + rem = n % b; + if (rem > 9) { + rem += 7; + } + if (i == 0 && min == 1) { + s[i++] = rem + '1'; + } else { + s[i++] = rem + '0'; + } + } while ((n /= b) > 0); + /* This is annoying, but to make hex numbers right, you have to account + * for the +1 added to the final number causing bit flipping */ + if (min == 1) { + for (i = 0; s[i] != '\0'; i++) { + if (s[i] == '-') { + continue; + } + if (i != 0 && s[i - 1] == '0' + (b + 7)) { + s[i] += 1; + s[i - 1] = '0'; + } + } + } + } + if (sign < 0) { + s[i++] = '-'; + } + s[i] = '\0'; + reverse(s); +} + +int main() { + int tests[5] = {INT_MIN, INT_MAX, -300, 172, 38478235}; + char st[101] = ""; + int i; + + for (i = 0; i < 5; i++) { + itob(tests[i], st, 16); + printf("%12d in string form is %12s\n", tests[i], st); + } + return 0; +} |