The C Programming Language, 2nd Edition, by Kernighan and Ritchie
Exercise 2.03 on page 46
Write the function htoi(s) , which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F .
Solutions by Richard Heathfield and Marshall S McLeish and Pilcrow
Here's my solution:
/* Write the function htoi(s), which converts a string of hexadecimal * digits (including an optional 0x or 0X) into its equivalent integer * value. The allowable digits are 0 through 9, a through f, and * A through F. * * I've tried hard to restrict the solution code to use only what * has been presented in the book at this point (page 46). As a * result, the implementation may seem a little naive. Error * handling is a problem. I chose to adopt atoi's approach, and * return 0 on error. Not ideal, but the interface doesn't leave * Richard Heathfield much choice. * * I've used unsigned int to keep the behaviour well-defined even * if overflow occurs. After all, the exercise calls for conversion * to 'an integer', and unsigned ints are integers! */ /* These two header files are only needed for the test driver */ #include <stdio.h> #include <stdlib.h> /* Here's a helper function to get Richard Heathfield around the problem of not * having strchr */ int hexalpha_to_int(int c) { char hexalpha[] = "aAbBcCdDeEfF"; int i; int answer = 0; for(i = 0; answer == 0 && hexalpha[i] != '\0'; i++) { if(hexalpha[i] == c) { answer = 10 + (i / 2); } } return answer; } unsigned int htoi(const char s[]) { unsigned int answer = 0; int i = 0; int valid = 1; int hexit; if(s[i] == '0') { ++i; if(s[i] == 'x' || s[i] == 'X') { ++i; } } while(valid && s[i] != '\0') { answer = answer * 16; if(s[i] >= '0' && s[i] <= '9') { answer = answer + (s[i] - '0'); } else { hexit = hexalpha_to_int(s[i]); if(hexit == 0) { valid = 0; } else { answer = answer + hexit; } } ++i; } if(!valid) { answer = 0; } return answer; } /* Solution finished. This bit's just a test driver, so * I've relaxed the rules on what's allowed. */ int main(void) { char *endp = NULL; char *test[] = { "F00", "bar", "0100", "0x1", "0XA", "0X0C0BE", "abcdef", "123456", "0x123456", "deadbeef", "zog_c" }; unsigned int result; unsigned int check; size_t numtests = sizeof test / sizeof test[0]; size_t thistest; for(thistest = 0; thistest < numtests; thistest++) { result = htoi(test[thistest]); check = (unsigned int)strtoul(test[thistest], &endp, 16); if((*endp != '\0' && result == 0) || result == check) { printf("Testing %s. Correct. %u\n", test[thistest], result); } else { printf("Testing %s. Incorrect. %u\n", test[thistest], result); } } return 0; }
And here's Marshall's:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> long hchartoi (char hexdig, int pos); /* converts a hex char to decimal knowing its 0 based place value */ long htoi (char hexstring[]); /* converts a string of hex bits to integer ... */ int main(void) { char *endp = NULL; char *test[] = { "F00", "bar", "0100", "0x1", "0XA", "0X0C0BE", "abcdef", "123456", "0x123456", "deadbeef", "zog_c" }; long int result; long int check; size_t numtests = sizeof test / sizeof test[0]; size_t thistest; for(thistest = 0; thistest < numtests; thistest++) { result = htoi(test[thistest]); check = strtol(test[thistest], &endp, 16); if((*endp != '\0' && result == -1) || result == check) { printf("Testing %s. Correct. %ld\n", test[thistest], result); } else { printf("Testing %s. Incorrect. %ld\n", test[thistest], result); } } return 0; } long htoi (char s[]) { char *p = &s[strlen(s)-1]; long deci = 0, dig = 0; int pos = 0; while (p >= s) { if ((dig = hchartoi(*p, pos)) < 0 ) { printf("Error\n"); return -1; } deci += dig; --p; ++pos; } return deci; } /* convert hex char to decimal value */ long hchartoi (char hexdig, int pos) { char hexdigits[] = "0123456789ABCDEF"; char *p = &hexdigits[0]; long deci = 0; int i; while (*p != toupper(hexdig) && deci < 16) { ++p; ++deci; } if (*p == toupper(hexdig)) { for (i = 0; i < pos; i++) deci *= 16; return deci; } return -1; }
Pilcrow's
/************************************************* Simple one. -- Pilcrow *************************************************/ #include <stdio.h> #define HEX_LO(N) ((N) >= 'a' && (N) <= 'f') #define HEX_HI(N) ((N) >= 'A' && (N) <= 'F') #define HEX_NU(N) ((N) >= '0' && (N) <= '9') #define IS_HEX(N) (HEX_LO(N) || HEX_HI(N) || HEX_NU(N)) unsigned long htoi(char []); int main(void) { int i; char *test[11] = { "F00", "bar", "0100", "0x1", "0XA", "0X0C0BE", "abcdef", "123456", "0x123456", "deadbeef", "zog_c" }; for(i =0; i < 11; ++i) { printf("%10s %10lu\n",test[i], htoi(test[i])); } return 0; } unsigned long htoi(char hexstr[]) { int i; long num; num = 0; i = 0; char j; if(hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] =='X')) i = 2; while(hexstr[i] != '\0') { j = hexstr[i]; if(! IS_HEX(j)) return 0; if(HEX_LO(j)) num = num * 16 + 10 + j - 'a'; else if(HEX_HI(j)) num = num * 16 + 10 + j - 'A'; else num = num * 16 + j - '0'; i++; } return num; }










