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
.
Solution by Vidhan Gupta
/* Write the function htoi(s), which converts a s tring of hexadecimal digits (including an option 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a throught f, and A through F. */ #include <stdio.h> #include <string.h> int htoi(char s[]); int powerOfHex(int n); int toUpperCase(int c); int main() { printf("%d\n", htoi("0x43F2Abc")); return 0; } int htoi(char s[]) { int n = 0, i, j = 0; for (i = strlen(s) - 1; i >= 0; --i) { if (s[i] >= '0' && s[i] <= '9') n += (s[i] - '0') * powerOfHex(j); else if ((s[i] >= 'A' && s[i] <= 'F') || (s[i] >= 'a' && s[i] <= 'f')) { if ((s[i] >= 'a' && s[i] <= 'f')) n += (toUpperCase(s[i]) - '7') * powerOfHex(j); else n += (s[i] - '7') * powerOfHex(j); } else i = 0; j++; } return n; } int powerOfHex(int n) { int p; for (p = 1; n > 0; --n) p = p * 16; return p; } int toUpperCase(int c) { if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; return c; }
OUTPUT: 71248572
Solution by Richard Heathfield
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; }
Solution by Marshall S McLeish
#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; }
Solution by Pilcrow
/************************************************* 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; }
Solution by seankndy
#include <stdio.h> #include <ctype.h> unsigned long htoi(const char s[]); int main(void) { printf("%ld\n", htoi("0xFA9C")); printf("%ld\n", htoi("0xFFFF")); printf("%ld\n", htoi("0x1111")); printf("%ld\n", htoi("0xBCDA")); return 0; } unsigned long htoi(const char s[]) { unsigned long n = 0; for (int i = 0; s[i] != '\0'; i++) { int c = tolower(s[i]); if (c == '0' && tolower(s[i+1]) == 'x') i++; else if (c >= '0' && c <= '9') n = 16 * n + (c - '0'); else if (c >= 'a' && c <= 'f') n = 16 * n + (c - 'a' + 10); } return n; }
Solution by Octavian
#include <stdio.h> #include <math.h> int upperToLower(int character); int main(void){ char hexString[10]; int i, j, c, input, integer; char hexadecimals[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; i = 0; while ((c = getchar()) != EOF) { if (c >= 'A' & c <= 'Z') { c = upperToLower(c); } hexString[i] = c; ++i; } hexString[i] = '\0'; integer = 0; for (j = i - 1; j >= 0; --j) { if(hexString[j] >= 'a' && hexString[j] <= 'z') { for(int k = 0; k < 16; ++k) { if(hexString[j] == hexadecimals[k]) { integer = integer + k * pow(16, i-1-j); } } } else integer = integer + (hexString[j] - '0') * pow(16, i-1-j); } printf("\nThe integer value of the hexadecimal string %s is ", hexString); printf("d.\n", integer); } int upperToLower(int input){ int lower; lower = input + 'a' - 'A'; return lower; }
Solution by Luke Panayi
#include <stdio.h> #include <ctype.h> #define BUFFER 1000 int power(int b, int p) { int r=b; if (p == 0) return 1; for (; p > 1; --p) r = r*b; return r; } int ctoi(char c) //take character string of hex number and convert each number into it's respective integer { if (isdigit(c)) return c - '0'; else return 10 + ((tolower(c) - '0') - 49); //ASCII value of 'a' is 49, 'b' 50 etc } int main() { int i, j, c, n; char s[BUFFER]; for (i=0; i<BUFFER && (c=getchar()) != '\n' && c != EOF; ++i) { if (c == 'x' && s[i-1] == '0') { --i; --i; } else s[i] = c; } for (n=0, j=0; j != i; ++j) n = n + ctoi(s[j])*power(16, (i-1)-j); printf("%d\n", n); return 0; }
Solution by i9383
If have suggests welcome tell me
#include <stdio.h> short isdigit0(char); /*if is or not digit number '0' '9'*/ short islower0(char); /*if is or not lower letter 'a' 'f'*/ short isupper0(char); /*if is or not upper letter 'A' 'F'*/ short hexsymbol0(char s[]); /*if has or not 0x or 0X symbol*/ int htoi0(char s[]); /*hexadecimal to integer*/ main() { char s[] = "0Xa1A"; printf("%d\n", htoi0(s)); return 0; } short isdigit0(char c) { if (c >= '0' && c <= '9') return 1; else return 0; } short islower0(char c) { if (c >= 'a' && c <= 'f') return 1; else return 0; } short isupper0(char c) { if (c >= 'A' && c <= 'F') return 1; else return 0; } short hexsymbol0(char s[]) { if (s[0] == '0') { if (s[1] == 'x' || s[1] == 'X') return 1; } else return 0; } int htoi0(char s[]) { int i, d = 0; if (hexsymbol0(s)) i = 2; else i = 0; while (s[i] != '\0') { if (isdigit0(s[i])) d = d * 16 + s[i] - '0'; /*example 123 when i == 0 s[i] == '1' 0 * 16 + '1' - '0' result is 1 when i == 1 s[i] == '2' 1 * 16 + '2' - '0' result is 18 when i == 2 s[i] == '3' 18 * 16 + '3' - '0' result is 291*/ else if (islower0(s[i])) d = d * 16 + 9 + s[i] - 'a' + 1; /*example 2af when i == 1 s[i] == 'a' 2 * 16 + 9 + 'a' - 'a' + 1 result is 42 when i == 2 s[i] == 'f' 42 * 16 + 9 + 'f' - 'a' + 1 result is 687 +9 cause before a has 9 numbers +1 cause 'a' - 'a' is 0 need +1 to equal 10 cause 'a' is 10*/ else if (isupper0(s[i])) d = d * 16 + 9 + s[i] - 'A' + 1; ++i; } return d; }
Solution by akiracadet
#include <stdio.h> #include <string.h> #include <math.h> int htoi(char s[]); int main(void) { char s[1000] = "FFF\0"; printf("%d\n", htoi(s)); } int htoi(char s[]) { int total; int power; int base; int i; power = 0; base = 16; total = 0; i = strlen(s); printf("%d\n", i); while (i >= 0) { --i; if (s[i] >= '0' && s[i] <= '9') { total = (s[i] - '0') * pow(base, power) + total; } else if (s[i] >= 'A' && s[i] <= 'F') { total = (s[i] - 'A' + 10) * pow(base, power) + total; } else if (s[i] >= 'a' && s[i] <= 'f') { total = (s[i] - 'a' + 10) * pow(base, power) + total; } ++power; } return total; }
Solution by Miguel Degrossoli
/* Exercise 2-3. Write a function "htoi(s)", which converts a string of * hexadecimal digits (including an optional 0x or 0X) into its equivalent * integer value. The allawable digits are 0 through 9, a through f, and A * through F. * * I'm using only what's been presented in the book so far. * * Here the user enters the hex number. * * I make sure it is valid before calling htoi(). * * It uses some experiences of previous lessons, so the size of the string is * twice the number of bytes an integer can hold, because a byte can be * represented by two hex digits. * * I add 1 to the limit, so it can take the trailing '\0'. * * I may add 2 to the limit, in case the user starts with 0x. * * I use tolower() from ctype.h, because the book already spoke about it at this * point. */ #include <stdlib.h> #include <stdio.h> #include <math.h> #include <limits.h> #include <ctype.h> unsigned char getwidth(unsigned long long int max); unsigned int htoi(char s[]); int main() { int i, c; unsigned char lim = getwidth(UINT_MAX) * 2; char s[lim + 3]; for (i = 0; i < lim && (c = getchar()) != '\n' && c != EOF; ++i) { /* first, lets convert it to lowercase. */ c = tolower(c); /* then, lets check if there's the leading 0x, so we can * increase the limit. */ if (i == 1 && s[0] == '0' && c == 'x') lim += 2; /* htoi should convert a good hexadecimal number, so we'll check * before calling it. */ if (isdigit(c) || (c >= 'a' && c <= 'f') || (i == 1 && s[0] == '0' && c == 'x')) s[i] = c; else { printf("Bad hexadecimal digit: %c.\n", c); exit(1); } } s[i] = '\0'; printf("Hexadecimal %s converts to integer %u.\n", s, htoi(s)); exit(0); } /* Retrieves the number of bytes used by a variable type */ unsigned char getwidth(unsigned long long int max) { int i; for (i = 0; pow(2, i) < max; ++i) ; return i; } /* Converts a good hexadecimal number to an unsigned integer */ unsigned int htoi(char s[]) { int i; unsigned int n; for (i = 0; s[i] != '\0'; ++i) if (i == 1 && s[0] == '0' && s[1] == 'x') n = 0; else if (isdigit(s[i])) n = 16 * n + (s[i] - '0'); else n = 16 * n + (s[i] - 'a' + 10); return n; }
Solution by Marvelcoder
* HexToInt.c * * Created on: 22-Aug-2020 * Author: Marvelcoder *
#include<stdio.h> int hexToInt(char []); int main(){ char hex[]="0x6BF0"; printf("Hexadecimal number %s after conversion is %d",hex,hexToInt(hex)); return 0; } int hexToInt(char arr[]){ int decimal,length,pow,temppow,base,tempbase,num; decimal=length=pow=temppow=num=0; for(int i=0;arr[i]!='\0';++i){ length++; } pow=length-1; for(int i=0;i<length;i++){ temppow=pow; tempbase=16; base=1; while(temppow!=0){ base=base*tempbase; temppow--; } if(pow==0)base=1; if(arr[i]>='0' && arr[i]<='9'){ num=arr[i]-'0'; }else if(arr[i]>='A' && arr[i]<='F'){ num=arr[i]-55; } decimal+=num*base; pow--; } return decimal; }
Solution by KlodElm
#include <ctype.h> #include <stdio.h> unsigned int htoi(char s[]); int main(void) { printf("\n%d\n", htoi("0XFa01B")); return 1; } unsigned int htoi(char s[]) { unsigned int i, n = 0; if (tolower(s[1]) == 'x') i = 2; else i = 0; for(; isdigit(s[i]) || (tolower(s[i]) >= 'a' && tolower(s[i]) <= 'f'); ++i) if (isdigit(s[i])) n = n*16 + s[i] - '0'; else n = n*16 + tolower(s[i]) + 10 - 'a'; return n; }
Solution by Nurmareko
#include <stdio.h> #include <math.h> #include <string.h> int htoi(char str[]); void check_expect(const int a, const int b); int decimal_value(char symbol, int place_power); int have_prefix(char str[]); int valid_hex(char symbol); int numeric(char c); int alphabetic_uppercase(char c); int alphabetic_lowercase(char c); main() { check_expect(htoi(""), -1); check_expect(htoi("xyz"), -1); check_expect(htoi("@12"), -1); check_expect(htoi(""), 0); check_expect(htoi("9"), 9); check_expect(htoi("a"), 10); check_expect(htoi("f"), 15); check_expect(htoi("A"), 10); check_expect(htoi("F"), 15); check_expect(htoi("2f"), 47); check_expect(htoi("F00"), 3840); check_expect(htoi("123456"), 1193046); check_expect(htoi("0x0"), 0); check_expect(htoi("0x9"), 9); check_expect(htoi("0xa"), 10); check_expect(htoi("0xf"), 15); check_expect(htoi("0xA"), 10); check_expect(htoi("0xF"), 15); check_expect(htoi("0x2f"), 47); check_expect(htoi("0xF00"), 3840); check_expect(htoi("0x123456"), 1193046); check_expect(htoi("0X0"), 0); check_expect(htoi("0X9"), 9); check_expect(htoi("0Xa"), 10); check_expect(htoi("0Xf"), 15); check_expect(htoi("0XA"), 10); check_expect(htoi("0XF"), 15); check_expect(htoi("0X2f"), 47); check_expect(htoi("0XF00"), 3840); check_expect(htoi("0X123456"), 1193046); return 0; } /* compute the value of string representation of hexadecimal, EXPECT positive value. */ int htoi(char str[]) { int exponent, i, power, sum; sum = 0; if (have_prefix(str)) { i = 2; exponent = strlen(str) - 3; } else { i = 0; exponent = strlen(str) - 1; } while (str[i] != '\0') { if (valid_hex(str[i])) { sum += decimal_value(str[i], exponent); ++i; --exponent; } else return -1; } return sum; } /* check for equality between a and b */ void check_expect(const int a, const int b) { if (a == b) printf("The test passed!\n"); else printf("Actual value %d differs from %d, the expected value.\n", a, b); } /* compute (n * 16^e) where n is the decimal value of hexadecimal symbol */ int decimal_value(char symbol, int e) { if (numeric(symbol)) return (symbol - '0') * pow(16, e); else if (alphabetic_uppercase(symbol)) return (symbol - '7') * pow(16, e); else if (alphabetic_lowercase(symbol)) return (symbol - 'W') * pow(16, e); else return 0; } /* is the given string representation of hexadecimal have prefix? */ int have_prefix(char str[]) { return (str[0] == '0' && str[1] == 'x' || str[1] == 'X'); } /* is the given symbol a valid hexadecimal symbol? */ int valid_hex(char symbol) { return (numeric(symbol) || alphabetic_uppercase(symbol) || alphabetic_lowercase(symbol)); } /* is c numeric? */ int numeric(char c) { return (c >= '0' && c <= '9'); } /* is c uppercased alphabetic? */ int alphabetic_uppercase(char c) { return (c >= 'A' && c <= 'F'); } /* is c lowecased alphabetic? */ int alphabetic_lowercase(char c) { return (c >= 'a' && c <= 'f'); }
Solution by Foowar
/* * exercise 2-3: * * 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. */ #include <stdio.h> #include <ctype.h> int htoi(const char *s) { int i; int ret; int sign; sign = 1; i = 0; if (s[i] == '-') { sign = -1; ++i; } else if (s[i] == '+') { ++i; } if (s[i] == '0') { ++i; if (s[i] != 'x' && s[i] != 'X') return 0; ++i; } for (ret = 0; s[i] != '\0'; ++i) { if (s[i] >= '0' && s[i] <= '9') { ret = 16 * ret + (s[i] - '0'); } else if (tolower(s[i]) >= 'a' && tolower(s[i]) <= 'f') { ret = 16 * ret + (10 + tolower(s[i]) - 'a'); } else { return 0; } } return ret * sign; }