我正在尝试解决 C编程语言一书中的练习2-3,但是我的解决方案无法正常工作,而且我找不到我做错了什么。练习表明编写一个函数,该函数接受包含十六进制数字的字符串,并将该数字作为int
返回。
这是我的代码:
#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;
}
为什么不起作用?
答案 0 :(得分:0)
您需要将pow(16, length - i)
更改为pow(16, length - i - 2)
。
“为什么2?”你可能会问。
那么,您需要学习如何调试程序。首先,您的length
似乎计算不正确。打印该值,您会发现它实际上比预期的多一。通常,C程序员在谈论字符串的长度时不计算'\0'
终止符,而标准函数strlen
也不这样。
因此,应在计算长度后从长度中删除1。然后这将是有意义的。例如,4 = 4×10 1和40 = 4×10 1。位置n上的数字应提高到幂n-1。之后,您使用pow(16, length - i - 1)
。注意,当我们有正确的长度时,它是1而不是2。
您对代码的其他评论
除非有特殊原因,否则我不会编写自定义函数来计算长度。而是使用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;
}
我也对其进行了重构。
答案 1 :(得分:0)
您的代码中存在多个问题:
scanf()
。如果用户在换行符之前键入四个以上的字符,则您将具有未定义的行为。使用fgets()
或至少指定要存储的最大字符数scanf("%4s", s)
更为安全。scanf()
的返回值,以防止无效输入(例如,从空文件重定向)时出现不确定的行为。htoi
中的第一个循环试图计算介于A
和F
之间的数字或字母的字符数,但是它不正确,因为它在计算的结果中包括第一个不匹配的字符length
。此外,如果用户键入char
之类的外来字符,则在默认情况下对é
进行签名的平台上,它具有未定义的行为。num
的当前值乘以16
并加上当前十六进制数字的值。在您的方法中,因子应为pow(16, length - i -
); if
length`已经正确计算。这是更正的版本:
#include <ctype.h>
#include <stdio.h>
int htoi(const char *s);
int main() {
char s[100];
if (fgets(s, sizeof s, stdin))
printf("%d\n", 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;
}