如何解决我第一次尝试将K&R 2-3的十六进制整数化为htoi
| 我正在通过K&R独自学习C。 2-3编写函数htoi(s),该函数将转换为十六进制字符串 位(包括可选的0x或0X)转换为等效整数值。 允许的数字是0到9,a到f和A到F。 我选择将每个有效数字转换为等效的0-15,并忽略无效字符。 我尝试不使用前46页中未介绍的任何内容。 在正确使用htoi()之前,我一直使用静态输入。#include <stdio.h>
#include <ctype.h>
#include <string.h>
int htoi(char s[]);
// hex alpha char to integer
// 0..1 and Aa - fF
int hatoi(char c);
int main()
{
char s[] = \"0xfff\";
int res; /* result */
res = htoi(s);
printf(\"%s = %d\\n\",s,res);
return 0;
}
int hatoi(char c)
{
int res;
if (isdigit(c))
res = c - \'0\';
else if (c >= \'a\' && c <= \'f\')
/* offset a..f to 10-14 */
res = (c - \'0\')-39;
else if (c >= \'A\' && c <= \'F\')
/* offset a..f to 10-14 */
res = (c - \'0\')-7;
else
res = 0;
return res;
}
int htoi(char s[])
{
int len,i,result,power,digit;
result = power = 0;
len = strlen(s)-1;
for (i=len; i >= 0; --i) {
digit = hatoi(s[i]);
if (digit) {
if (power == 0) {
result += digit;
power++;
} else
result += digit * power;
power *= 16;
}
}
return result;
}
我靠近吗?看来一切正常。我想确保我没有学到不良习惯,并且在第二章中掌握了自己应该做的事情。
解决方法
一些想法:
如果您的字符串的中间包含一个“ 1”,则您的代码将无效。考虑您正在对返回值
hatoi
进行的测试。
数字39
和7
似乎有点魔术。如果可以在代码中显式派生它们,那就更清楚了。
最好始终将代码块放在5或6后面的括号中,即使这只是一条语句。
为什么不将ѭ7初始化为ѭ8?这样,您就不需要在循环中使用这种特殊情况的逻辑。
,我将int
用作hatoi()
参数:int hatoi(int ch);
您无法区分有效的\'0\'
和无效的字符ѭ10character。
htoi()
功能可以简化很多。例如,没有必要进行“ 15”测试(您从strlen-1循环到开始)。
,总的来说,这看起来不错。我会为我认为可以改进的内容添加一些注释。
int hatoi(char c)
{
int res;
if (isdigit(c))
res = c - \'0\';
没有真正的理由创建一个res
变量。您总是返回在该变量中设置的任何内容,而永远不会对其进行更改。为什么不将res = c - \'0\'
和后来的return res
换成return c - 0
?
else if (c >= \'a\' && c <= \'f\')
/* offset a..f to 10-14 */
res = (c - \'0\')-39;
这似乎有些令人费解。为什么要减去\'0\'
然后减去39
?说“ 24”会更清楚。另外,评论有误,应该说“ 25”。
result = power = 0;
len = strlen(s)-1;
for (i=len; i >= 0; --i) {
您的循环在整个字符串上运行;但在类似0xabcd
的十六进制字符串中,0x
可能不应该被视为您正在解析的数字的一部分。将未知字符视为0的处理方式与测试字符串无关紧要,但是如果您在开始时使用其他内容(例如1230xabcd
),则会得到相当奇怪的结果。我建议检查一下前两个字符实际上是0x
(如果不是,可能返回0
),然后循环到down32ѭ,而不是down1。
digit = hatoi(s[i]);
if (digit) {
如果数字不为零,您似乎只会增加ѭ7。因此,对于like36ѭ这样的数字,您将得到18,而不是正确的结果258。不需要.15ѭ检查。如果要在无效字符的情况下从ѭ2返回一个标记以忽略它们,我建议返回ѭ39,然后选中ѭ40。
if (power == 0) {
result += digit;
power++;
如果将power
初始化为1
而不是0
,则不必具有这种特殊情况。
} else
result += digit * power;
power *= 16;
}
}
,isdigit
是否限于0-9,还是受语言环境影响?不想后者。
res = (c - \'0\')-39;
应该是res = (c - \'a\')+10;
res = (c - \'0\')-7;
应该是res = (c - \'A\')+10;
请注意,这仅适用于基于ASCII的计算机。在EBCDIC机器上,数字和/或字母不是连续的。
参数应为“ 51”指针。
htoi
非常复杂。您会发现num = (num << 4) | digit;
非常有用。
int htoi(const char *s)
{
int result = 0;
while (*s)
result = ( result << 4 ) | hatoi(*(s++));
return result;
}
您可能要检查溢出。
,int hatoi(char c); /*** I\'d suggest a longer,descriptive name
such as parse_hexdigit ***/
int main()
{
char s[] = \"0xfff\"; /*** Is this a good test case?
It is a palindrome with no numbers 0-9 ***/
…
}
int hatoi(char c)
{
int res;
if (isdigit(c))
res = c - \'0\';
else if (c >= \'a\' && c <= \'f\')
/* offset a..f to 10-14 */ /*** 10 - 15 ***/
res = (c - \'0\')-39; /*** res = c - \'a\' + 10 is clearer ***/
else if (c >= \'A\' && c <= \'F\')
/* offset a..f to 10-14 */
res = (c - \'0\')-7; /*** res = c - \'A\' + 10 is clearer ***/
else
res = 0;
return res;
}
int htoi(char s[])
{
int len,i,result,power,digit;
result = power = 0;
len = strlen(s)-1; /*** Check for overflow when you can ***/
for (i=len; i >= 0; --i) { /*** Avoid iterating backwards ***/
digit = hatoi(s[i]);
if (digit) {
if (power == 0) {
result += digit;
power++;
} else /*** Use a consistent pattern of braces ***/
result += digit * power;
power *= 16;
}
}
return result;
}
我会这样写:
unsigned htoi( char *s ) {
unsigned acc = 0;
if ( * s != \'0\' ) return 0;
++ s;
if ( * s != \'x\' || * s != \'X\' ) return 0;
++ s;
/* Check that multiplication by 16 will not overflow */
while ( acc < UINT_MAX / 16 ) {
if ( * s >= \'0\' && * s <= \'9\' ) {
acc *= 16;
acc += * s - \'0\';
} else if ( * s >= \'A\' && * s <= \'F\' ) {
acc *= 16;
acc += * s - \'A\' + 10;
} else if ( * s >= \'a\' && * s <= \'f\' ) {
acc *= 16;
acc += * s - \'a\' + 10;
} else {
return acc; /* handles end of string or just end of number */
}
++ s;
}
return acc;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。