Exercise 2-3. Write the function
htoi(s), which converts a string of hexadecimal digits (including an optional0xor0X) into its equivalent integer value. The allowable digits are0through9,athroughf, andAthroughF.
How htoi Works
Hexadecimal is simply base-16 positional notation. Converting from a hex string to an integer uses exactly the same accumulation pattern as atoi does for decimal: scan each digit left to right and maintain a running total with n = n * 16 + digit. The only new challenges are mapping three distinct character ranges (digits, lowercase letters, uppercase letters) to the values 0–15, and skipping an optional 0x/0X prefix before the main loop starts.
The character arithmetic is the elegant core of this solution. To convert a hex letter to a numeric value, subtract the base character and offset by the starting value of that range: 'a' - 'a' + 10 = 10, 'b' - 'a' + 10 = 11, …, 'f' - 'a' + 10 = 15. The same formula works for uppercase with 'A' as the base. Note that the function stops cleanly at the first invalid character — so htoi("0x1Z") correctly returns the value accumulated up to but not including 'Z'.
/* Compile: gcc -ansi -Wall ex2-3.c -o ex2-3 */
#include <stdio.h>
int htoi(const char s[]);
int main(void)
{
printf("htoi(\"0x1A\") = %d\n", htoi("0x1A"));
printf("htoi(\"0XFF\") = %d\n", htoi("0XFF"));
printf("htoi(\"ff\") = %d\n", htoi("ff"));
printf("htoi(\"10\") = %d\n", htoi("10"));
printf("htoi(\"0x10\") = %d\n", htoi("0x10"));
return 0;
}
int htoi(const char s[])
{
int n, i;
n = 0;
i = 0;
/* skip optional 0x or 0X prefix */
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
i = 2;
for (; s[i] != '\0'; ++i) {
int digit;
if (s[i] >= '0' && s[i] <= '9')
digit = s[i] - '0';
else if (s[i] >= 'a' && s[i] <= 'f')
digit = s[i] - 'a' + 10;
else if (s[i] >= 'A' && s[i] <= 'F')
digit = s[i] - 'A' + 10;
else
break; /* invalid character — stop */
n = n * 16 + digit;
}
return n;
}
Compile and Run
gcc -ansi -Wall ex2-3.c -o ex2-3
./ex2-3
Sample Output
htoi("0x1A") = 26
htoi("0XFF") = 255
htoi("ff") = 255
htoi("10") = 16
htoi("0x10") = 16
Quick sanity check: 0x1A = 1×16 + 10 = 26; 0xFF = 15×16 + 15 = 255; 0x10 = 1×16 + 0 = 16.
What This Exercise Teaches
- Horner’s method for base conversion:
n = n * 16 + digitaccumulates a multi-digit number in one left-to-right pass — the same pattern used inatoifor base 10. - Character arithmetic: subtracting the base character maps a character to its ordinal position within a range.
'f' - 'a' + 10gives 15 without any lookup table. - Multi-character prefix detection: you must check both
s[0]ands[1]before advancingiby 2 — checking only the first character would incorrectly skip the leading zero in"01". - Graceful handling of invalid input:
breaking on the first unrecognised character rather than returning an error code matches the behaviour of the standard library’sstrtol(s, NULL, 16).
Standard Library Equivalent
Once you understand how htoi works, it is worth knowing that the standard library provides strtol from <stdlib.h> for this job:
#include <stdlib.h>
long val = strtol("0xFF", NULL, 16); /* val == 255 */
The second argument, when non-NULL, receives a pointer to the first character that was not converted — a more informative version of the break in our loop. Writing htoi by hand first makes strtol‘s design immediately clear.
Set Up Your C Environment
To compile and run this solution, you need GCC installed. If you haven’t set up C on your machine yet:
- Install GCC on Windows 11
- Install GCC on macOS
- Install GCC on Ubuntu/Linux
- VS Code for C Programming — recommended editor
← Exercise 2-2 |
Chapter 2 Solutions |
Exercise 2-4 →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie