# Thread: Converting hexidecimal digits to integer value

1. ## Converting hexidecimal digits to integer value

I am working on K&R's Exercise 2-3. The problem is as followed:

Write a function htoi(s), which converts a string of hexidecimal 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 have written the code (skipping the optional 0x or 0X) for this function and I'm pretty sure I'm correct, but I want someone to double check my work and let me know if there is anything I can improve or work on. Thank you in advance!

Here is my code:

Code:
```int htoi(char s[]){

int i, n;
i = 0;

n = 0; // integer value to be returned
for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i){

n = 16 * n + (s[i] - '0');

if(s[i] >= 'a' && s[i] <= 'f')
n = 16 * n + (s[i] - 'a');
else if(s[i] >= 'A' && s[i] <= 'F')
n = 16 * n + (s[i] - 'A');
else
return 0; // not a valid hex digit
}
return n;
}``` 2. Have you tested it with the input string "a"? Does it return an integer value of 10? 3. Originally Posted by laserlight Have you tested it with the input string "a"? Does it return an integer value of 10?
It returned an integer value of 0 when I tested it. 4. That's good, so now you know that you are mistaken when you wrote "I'm pretty sure I'm correct". Take a second look at the loop condition and go through the process of looping with the input of "a". 5. I see where I went wrong...

I forgot to add 10 in
Code:
`n = 16 * n + (s[i] - 'a');`
Same mistake on line 17. I have rewritten my code.
Here's what it looks like now:

Code:
```#include <stdio.h>
#include <stdlib.h>

int htoi(char s[]){

int i, n;
i = 0;

n = 0; // integer value to be returned

if(s[i] >= '0' && s[i] <= '9')
return n = 16 * n + (s[i] - '0');
else if(s[i] >= 'a' && s[i] <= 'f')
return n = 16 * n + (s[i] - 'a') + 10;
else if(s[i] >= 'A' && s[i] <= 'F')
return n = 16 * n + (s[i] - 'A') + 10;
}

int main(int argc, char *argv[]) {

char test;
int a;

printf("Enter a hexidecimal string to be converted:  ");
scanf("%s", test);

a = htoi(test);
printf("\nThe integer value is: %d\n ", a);
return 0;
}``` 6. What happened to your loop? 7. If I were you, I would write a main function like this:
Code:
```int main(void) {
printf("%s\n", (htoi("0") == 0) ? "pass" : "fail");
printf("%s\n", (htoi("1") == 1) ? "pass" : "fail");
printf("%s\n", (htoi("9") == 9) ? "pass" : "fail");
printf("%s\n", (htoi("a") == 10) ? "pass" : "fail");
printf("%s\n", (htoi("f") == 15) ? "pass" : "fail");
printf("%s\n", (htoi("A") == 10) ? "pass" : "fail");
printf("%s\n", (htoi("F") == 15) ? "pass" : "fail");
printf("%s\n", (htoi("10") == 16) ? "pass" : "fail");
printf("%s\n", (htoi("1d") == 29) ? "pass" : "fail");
printf("%s\n", (htoi("e1") == 225) ? "pass" : "fail");
printf("%s\n", (htoi("abc") == 2748) ? "pass" : "fail");
printf("%s\n", (htoi("a2b") == 2603) ? "pass" : "fail");
printf("%s\n", (htoi("5C7") == 1479) ? "pass" : "fail");
printf("%s\n", (htoi("a1b2") == 41394) ? "pass" : "fail");
return 0;
}```
Every time I make a change to my implementation of htoi and feel that I've got it right, I would compile and run the program. If all of the lines of output read "pass", then I know that chances are, I have implemented it correctly, and so I can modify the tests and move on to implement for the optional "0x" and "0X" prefixes. If any of the lines read "fail", or the program crashes, then I know I have a bug to fix. 8. Originally Posted by laserlight When I ran the original program with the for loop I kept getting 0 as the return value. I went back an looked at the book and reread the example of char to int conversions using the function lower.

Code:
```int lower(int c){
if (c >= 'A' && c<= 'Z')
return c + 'a' - 'A';
else
return c;```
I rewrote the function to reflect this example and was able to achieve the return value of 10 for 'a'. Was that incorrect? 9. It passes every test up to "F" and fails for the rest. Why is that? 10. Well, let's take your code from post #1, combine it with my main function from post #7, compile and run:
Code:
```pass
fail
fail
fail
fail
fail
fail
fail
fail
fail
fail
fail
fail
fail```
So we see that only the very first test passed. This initially surprised me because I thought it should pass for a few more, but on closer investigation I can see why: in the body of the loop, you always check to see if the digit is a valid alphabetic hex digit, and if it isn't you return 0. Since '1' is not a valid alphabetic hex digit, you return 0 for "1" despite correctly computing n == 1. Note that this is in addition to what I pointed out in post #4.

Now, let's take your code from post #5, combine it with my main function from post #7, compile and run:
Code:
```pass
pass
pass
pass
pass
pass
pass
fail
fail
fail
fail
fail
fail
fail```
Notice that all the tests with more than one hex digit fail. This is a direct result of your removal of the loop: since you are no longer looping, you only process one hex digit. 11. My main function in post #7 is a very simple example of how you might write unit tests to test your function. You don't get much information out of running the tests other than whether they passed or failed. Here's a slightly more sophisticated version:
Code:
```void test_htoi(char input[], int expected_output) {
int actual_output = htoi(input);
if (actual_output == expected_output) {
printf("htoi(\"%s\") passed\n", input);
} else {
printf("htoi(\"%s\") failed: expected=%d; actual=%d \n",
input, expected_output,
actual_output);
}
}

int main(void) {
test_htoi("0", 0);
test_htoi("1", 1);
test_htoi("9", 9);
test_htoi("a", 10);
test_htoi("f", 15);
test_htoi("A", 10);
test_htoi("F", 15);
test_htoi("10", 16);
test_htoi("1d", 29);
test_htoi("e1", 225);
test_htoi("abc", 2748);
test_htoi("a2b", 2603);
test_htoi("5C7", 1479);
test_htoi("a1b2", 41394);
return 0;
}```
If we run this with your code from post #1, we get:
Code:
```htoi("0") passed
htoi("1") failed: expected=1; actual=0
htoi("9") failed: expected=9; actual=0
htoi("a") failed: expected=10; actual=0
htoi("f") failed: expected=15; actual=0
htoi("A") failed: expected=10; actual=0
htoi("F") failed: expected=15; actual=0
htoi("10") failed: expected=16; actual=0
htoi("1d") failed: expected=29; actual=0
htoi("e1") failed: expected=225; actual=0
htoi("abc") failed: expected=2748; actual=0
htoi("a2b") failed: expected=2603; actual=0
htoi("5C7") failed: expected=1479; actual=0
htoi("a1b2") failed: expected=41394; actual=0```
and now you can see clearly that the failures are due to the actual value always being 0, which gives you a hint that you are always returning 0.

With your code from post #5:
Code:
```htoi("0") passed
htoi("1") passed
htoi("9") passed
htoi("a") passed
htoi("f") passed
htoi("A") passed
htoi("F") passed
htoi("10") failed: expected=16; actual=1
htoi("1d") failed: expected=29; actual=1
htoi("e1") failed: expected=225; actual=14
htoi("abc") failed: expected=2748; actual=10
htoi("a2b") failed: expected=2603; actual=10
htoi("5C7") failed: expected=1479; actual=5
htoi("a1b2") failed: expected=41394; actual=10```
You can see that the actual values are fairly low compared to the expected values, so it is a hint that you are not handling enough of the input string. This is confirmed when you look a bit more closely and see that the actual values correspond to the first hex digit of each of the input strings. 12. I didn't forget about your last response! I'm a bit busy today but I think I know how to solve my problem. I will be working on it later today and I'll get back to you. Thanks again! 13. Sorry for the really late reply... I have been pretty busy with some Calc 2 homework. I had a quiz and upcoming exam I have been studying for

So, I was able to solve the problem. What I did in the for loop was check to see if s[i] is not a null terminator. Then within if-else block I checked to see if the values were digits 0-9, a-f, A-F and stored the value to the corresponding hex digit to a variable called hexDigit. Finally, I converted the hex value to an integer.

For some reason, if I tried to use my original for loop my program would not pass for the first couple inputs (0, 1, 9, a, f, A, F). I'm not sure why that is though?

My code is as follows:
Code:
```int htoi(char s[]){

int hexDigit, i = 0, n;

n = 0;// integer to be returned
for(; s[i] != '\0'; ++i){

if(s[i] >= '0' && s[i] <= '9')
hexDigit = s[i] - '0';
else if(s[i] >= 'a' && s[i] <= 'f')
hexDigit = s[i] - 'a' + 10;
else if(s[i] >= 'A' && s[i] <= 'F')
hexDigit = s[i] - 'A' + 10;
else
s[i] = 0;

n = 16 * n + hexDigit;
}
return n;
}

int main(void) {
printf("%s\n", (htoi("0") == 0) ? "pass" : "fail");
printf("%s\n", (htoi("1") == 1) ? "pass" : "fail");
printf("%s\n", (htoi("9") == 9) ? "pass" : "fail");
printf("%s\n", (htoi("a") == 10) ? "pass" : "fail");
printf("%s\n", (htoi("f") == 15) ? "pass" : "fail");
printf("%s\n", (htoi("A") == 10) ? "pass" : "fail");
printf("%s\n", (htoi("F") == 15) ? "pass" : "fail");
printf("%s\n", (htoi("10") == 16) ? "pass" : "fail");
printf("%s\n", (htoi("1d") == 29) ? "pass" : "fail");
printf("%s\n", (htoi("e1") == 225) ? "pass" : "fail");
printf("%s\n", (htoi("abc") == 2748) ? "pass" : "fail");
printf("%s\n", (htoi("a2b") == 2603) ? "pass" : "fail");
printf("%s\n", (htoi("5C7") == 1479) ? "pass" : "fail");
printf("%s\n", (htoi("a1b2") == 41394) ? "pass" : "fail");
return 0;
}``` 14. Originally Posted by KingFlippyNips
So, I was able to solve the problem. What I did in the for loop was check to see if s[i] is not a null terminator. Then within if-else block I checked to see if the values were digits 0-9, a-f, A-F and stored the value to the corresponding hex digit to a variable called hexDigit. Finally, I converted the hex value to an integer.
Yes, that is the approach that I would have taken  Originally Posted by KingFlippyNips
For some reason, if I tried to use my original for loop my program would not pass for the first couple inputs (0, 1, 9, a, f, A, F). I'm not sure why that is though?
Let's take another look at the condition of your original for loop:
Code:
`for(i = 0; s[i] >= '0' && s[i] <= '9'; ++i){`
What it says is this: loop from the first character until a character that is not in the range '0' to '9' is found. This works great if your input consists entirely of digits from '0' to '9', e.g., "123" as you would loop over the entire input string. But suppose your input consists of the non-decimal range of hexadecimal digits, e.g., "ABC". Your loop will stop immediately because 'A' is a character that is not in the range '0' to '9'. Therefore the result is 0, which is obviously wrong.

Compounding this problem, within the loop body, you check to see if the character is a valid hex digit in the sense of whether it is a digit that is among the alphabetic hexadecimal digits 'A' to 'F'. Of course, knowing that within the loop body the character is surely in the range '0' to '9', it follows that it is surely "not a valid hex digit", therefore 0 is returned. Consequently, your function always returns 0, because either the character is not in the range of '0' to 9' hence 0 is returned, or it is in the range of '0' to '9' but not in the range of 'A' to 'F' (which is always true), hence 0 is returned. 15. There is also an implementation with a big string - "0123456789ABCDEF" - where a subscript matches the given place value; it's portable across character sets at least. Popular pages Recent additions code, digits, hexidecimal, integer, s[i] 