"Herrcho" <> wrote in message
news: m...
> Hi~ i've studied C for a few months myself,
Good for you.
> and i'd appreciate it if anyone could improve my coding or correct it.
>
> the following is my solution to the K&R exercise 2-3
Excellent, finally someone who has actually shown some code!

Beware, many of my comments below are nits, but it is nice to learn the
good habits now before you'd need to unlearn the wrong ones, like myself.
> "Write the function htoi(s), which converts a string of hexademical digits
> (including an optional 0x or 0X) into its equivalent integer value.
> The allowable digits are 0 through 9, a through f, and A throught F."
>
>
//************************************************** ************************
>
> #include <stdio.h>
>
> int isxdigit2(int c)
Identifiers starting with 'is' followed by a lowercase letter are reserved
by the C standard. Use something like is_xdigit2 instead.
By the way, there already is a macro isxdigit, you need to #include
<ctype.h>
> {
> if ( (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <=
'9') )
This is not guaranteed to work on non-ASCII systems. The ranges 'a'..'f' and
'A'..'F' do not need to be consecutive. It is guaranteed about '0'..'9',
though.
> return 1;
> else
> return 0;
> }
Proper indentation would make your code easier to read.
> int tolower2(int c)
> {
> if (c >= 'A' && c <= 'Z')
> return c+32;
> else
> return c;
> }
Same comments as above. BTW, identifiers starting with 'to' are reserved
too.
> int power2(int base, int num)
> {
> int sum;
> for (sum = 1; num >0 ; num --)
> sum *= base;
> return sum;
> }
>
> int char_to_num(int c)
> {
> if (c >= '0' && c <= '9')
> {
> return c - 48;
Where does the magic number 48 come from? ITYM return c - '0';
> }
> else
> {
> return 10 + (tolower2(c) - 'a');
Again, this only works if you are sure that 'a'..'f' is a consecutive set.
> }
> }
>
> int htoi(char *c)
> {
> int i, k, prefix = 0;
> size_t sum = 0;
>
> if (c[0] == '0' && tolower2(c[1]) == 'x')
> prefix = 1;
Are you sure that you have 2 valid characters in c? What happens when you
call htoi("7"), for example?
Try:
if (c[0] && c[0] == '0' && c[1] && (c[1] == 'x' || c[1] == 'X'))
prefix = 1;
It's admittably a bit less elegant but safer. By the way, you could work on
an algorithm without the variable prefix. It's really simple, think about it
a little. All you need is to skip the first 2 characters of c...
> for (i = (prefix == 1)? 2:0 ; c[i] ;i++ )
> {
> if (!isxdigit2(c[i]) )
> {
> printf("Wrong hexa number\n");
"Hexa" as in "jinxed"?
> return 0;
> }
> c[i] = char_to_num(c[i]);
> }
>
> for (k = (prefix == 1)? 2 : 0 ; k <= i-1 ; ++k )
> {
> sum += c[k] * power2(16, i-1-k);
> }
>
> return sum;
> }
>
> int main()
> {
> char c[] = "0xAB";
> printf("%u", htoi(c));
Err, no sir. %u in printf() expects unsigned int, but you provide it with
the result of htoi(), which returns int. This is strictly speaking an
undefined behaviour, although admittably I have yet to see a platform where
it does not work. In any case, use %d instead or change your htoi() to
return unsigned int.
> return 0;
> }
It looks OK, though overly complicated. You could use already available
macros isxdigit and tolower (both defined in ctype.h), but frankly you
should not even need them. And you certainly should not need your power2().
Think about it. What's 1986 in decimal?
In your algorithm, it's 1*10^3 + 9*10^2 + 8*10^1 + 1*10^0.
How about (((1)*10 + 9)*10 +

*10 + 6?
Now try converting it to a C program, for any (hexa)decimal number with any
number of digits.
> //************************************************** ****************
>
> when i change char c[] to char *c in main(),
> it shows error, why ??
Undefined behaviour. Your htoi() tries to alter the string it is given in
situ. With char c[] in main, the string literal "0xAB" get copied to a local
array c, which is OK. But when you declare c as char *, you pass a pointer
to the string literal to htoi()... oops!
> Thanks..
HTH,
Peter