Why isn't my solution to K&R exercise 2-3 working?
Why isn't my solution to K&R exercise 2-3 working?
I'm trying to solve exercise 2-3 in the book The C Programming Language, but my solution isn't working and I can't find out what I did wrong. The exercise says to write a function that takes a string containing a hexadecimal number and returns that number as an int.
int
Here is my code:
#include <stdio.h>
#include <ctype.h>
#include <math.h>
int htoi(char *s);
int main() {
char s[5];
scanf("%s", s);
printf("%d", htoi(s));
}
int htoi(char *s) {
int length, num = 0, i;
char c = 'A';
for (length = 0; c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; length++)
c = toupper(s[length]);
for (i = 0; i <= length; i++) {
c = toupper(s[i]);
if (c >= '0' && c <= '9')
num += (c - '0') * pow(16, length - i);
else if (c >= 'A' && c <= 'F')
num += (c - 'A' + 10) * pow(16, length - i);
}
return num;
}
Why isn't it working?
Using a debugger can help finding where the program behaves undesired so that you can check the logic is correct.
– Tony Tannous
Jun 30 at 21:04
There's a function called
isxdigit() you may use.. then instead of using pow(), you may multiply. Hint: 123 = (1*10 + 2)*10 + 3.– Mance Rayder
Jun 30 at 21:24
isxdigit()
pow()
Note that code such as
c >= 'A' && c <= 'F' implicitly relies on the ASCII character set. Only the digit characters '0' through '9' are guaranteed by the C standard to be represented consecutively.– Andrew Henle
Jul 1 at 1:38
c >= 'A' && c <= 'F'
'0'
'9'
I'd start over.
pow is a bad choice for this purpose. A far better algorithm is to process characters in a loop with val = (val << 4) + hexVal(ch), where int val is initially 0. Find the hexVal of a character with ch - '0' for characters between 0 and 9. For 'a' through 'f' use a switch statement with e.g. case 'a': case 'A': return 10;– Gene
Jul 1 at 2:05
pow
val = (val << 4) + hexVal(ch)
int val
hexVal
ch - '0'
'a'
'f'
switch
case 'a': case 'A': return 10;
2 Answers
2
You need to change pow(16, length - i) to pow(16, length - i - 2).
pow(16, length - i)
pow(16, length - i - 2)
"Why 2?" you may ask.
Well, you need to learn how to debug programs. First of, your length does not seem to be properly calculated. Print that value and you'll see that it is actually one more than expected. Usually, C-programmers do not count the '' terminator when talking about the length of a string, and the standard function strlen does not either.
length
''
strlen
So you should remove 1 from length after it is calculated. And then it will make sense. For instance, 4=4*10⁰ and 40=4*10¹. The digit on position n should be raised to the power n-1. After that you use pow(16, length - i - 1). Notice it's 1 instead of 2 when we have correct length.
pow(16, length - i - 1)
Other comments on your code
Unless you have a specific reason to do so, I would not write a custom function to calculate the length. Instead, use strlen and check for correctness later. In this program it seems that you can assume that the string always will be correct. So I would have written it like this:
strlen
int htoi(char * s) {
int length = strlen(s), num = 0, i;
for (i = 0; i < length; i++) {
int factor = pow(16, length - i - 1), digit;
int c = toupper(s[i]);
if (c >= '0' && c <= '9')
digit = c - '0';
else if (c >= 'A' && c <= 'F')
digit = c - 'A' + 10;
num += digit * factor;
}
return num;
}
I also refactored it a little bit.
NULL is a pointer. NUL is a character. A string length, in C, never counts the '' terminator.– Mance Rayder
Jun 30 at 21:29
NULL
NUL
''
@ManceRayder --
NUL exists in ASCII, EBCDIC, and some other character sets, but is never mentioned in the C Standard; there it is just called a null character, a null byte, or a null terminator.– David Bowling
Jul 1 at 0:26
NUL
@DavidBowling -- I'm not saying that C specifies or requires that. It's mentioned, at §7.4, as an example of what a control character refers to.
– Mance Rayder
Jul 1 at 3:20
There are multiple problems in your code:
scanf()
fgets()
scanf("%4s", s)
scanf()
htoi
A
F
length
char
é
num
16
pow(16, length - i -
if
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int htoi(const char *s);
int main() {
char s[100];
if (fgets(s, sizeof s, stdin))
printf("%dn", htoi(s));
return 0;
}
int htoi(const char *s) {
unsigned int num = 0;
int i;
for (i = 0; isxdigit((unsigned char)s[i]); i++) {
if (c >= '0' && c <= '9')
num = num * 16 + c - '0';
else
num = num * 16 + 10 + toupper(c) - 'A';
}
return num;
}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Please describe the problem. "It's not working" is not a problem description. What does your function do? (Not what it should do. What does it do?)
– klutt
Jun 30 at 20:57