这段代码有问题:
while(c = getchar() != '\n' && c != EOF)
没有足够的括号——赋值是一个低优先级的运算符。应该是:
while ((c = getchar()) != '\n' && c != EOF)
另一组问题是循环体中的转换代码:
if (c >= 97)
c = c - 'a' - 1;
else
c = c;
numdec += numdec * base + c;
97 的选择大概是a 的 ASCII 或 ISO 8859-n 或 Unicode 代码点。这将忽略大写字母、标点符号,并将数字 0 到 9 视为 48..57。您可能需要使用#include <ctype.h>。它也不验证“数字”是否对基数有效。
但是,在第一次调用 intToDec() 时,读取的第一个字符是一个换行符,由 scanf() 留下,所以第一个数字始终为零,如果您按照提示每行输入一个数字到。
当您最终到达outToDec() 时,您会发现一些有趣的命理。我添加了printf() 语句来跟踪函数的进入和退出,以及循环中的关键点:
void outFromDec(int num, int base)
{
printf("-->> %s: %d %d\n", __func__, num, base);
int count = 0, temp = num, i;
char c;
while (temp != 0)
{
temp /= base;
count++;
}
printf("Count: %d\n", count);
temp = num;
do
{
printf("count: %d; temp = %d\n", count, temp);
for (i = 1; i < count; i++)
temp /= base;
if (temp <= 9)
c = '0' + temp;
else
c = 'a' + temp - 1;
putchar(c);
count--;
temp = num / temp;
} while (temp != 0);
printf("<<-- %s\n", __func__);
}
__func__ 是 C99 中包含函数名称的预定义标识符。您可能无法在 MSVC 中使用它;如果不是,请用函数名替换它。
对于输入1、9、9,程序的输出为:
-->> inToDec: 9
<<-- inToDec: 0
-->> inToDec: 9
<<-- inToDec: 57
-->> outFromDec: 57 9
Count: 2
count: 2; temp = 57
6count: 1; temp = 9
9count: 0; temp = 6
6count: -1; temp = 9
9count: -2; temp = 6
计数继续减少,6 和 9 继续交替。您似乎正在尝试使用首先发现的最高有效数字 (MSD) 来隔离数字。判断count的循环是正确的;循环打印数字显然不是。你应该可以从那里拿走它;是例行调试。请注意我如何使用打印语句来查看发生了什么。如果只看代码无法解决,如有必要,打印出每个表达式的结果。
我观察到以 10 为基数打印 57,您会发现要打印 2 个数字 (count == 2)。第一个数字将通过除以基数 (10) count-1 次得到;这会给你 5 打印。您可能需要从数字中减去 5 * 10,以便下一次(在本例中为最后一次)循环时,您只需从 7 开始,然后打印。循环将停止。如果count 变为负数,您应该确保循环中断。
这是一种格式化 10 位 32 位数字(甚至更适合 19 位 64 位数字)的昂贵方式。不过,它可以工作。标准程序以相反的顺序收集数字并安排以相反的顺序将它们打印出来。 (number % base 为您提供要打印的数字;number /= base 减少了要处理的位数。)
正如经常发生的那样,OP 受到人为约束,可能不使用字符串。呸!
这是一个看似稳健的“读取整数”函数。它确实假设了 2 的补码算法;它包含一个断言,如果它曾经在符号幅度或 1 的补码的机器上运行时应该触发(但我没有测试它;我没有任何此类机器可用于测试)。
请注意,代码将数字累加为负数,如果应该是正数,则在最后将其设为正数。这使得处理 INT_MIN 比尝试将其累积为正值int 更容易。
出于练习的目的,我将系统视为sizeof(intmax_t) == sizeof(int)(因此也是sizeof(int) == sizeof(long) 和sizeof(int) == sizeof(long long));如果整数类型是intmax_t 而不是int,则此技术将起作用。请注意,C 标准不排除这种假定的配置(但标准要求 CHAR_BIT * sizeof(int) >= 64 是符合要求的实现)。
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
/* Read an integer from stdin without prompt: code is not allowed to use strings! */
enum { E_OK = 0, E_EOF = -1, E_INVCHAR = -2, E_OVERFLOW = -3 };
extern int read_an_int(int *value);
int read_an_int(int *value)
{
int number = 0;
int c;
int pos_neg = +1;
assert(-INT_MAX != INT_MIN); // Probably 2's complement
while ((c = getchar()) != EOF && isspace(c))
;
if (c == '-')
{
pos_neg = -1;
c = getchar();
}
else if (c == '+')
{
pos_neg = +1;
c = getchar();
}
if (c == EOF)
return E_EOF;
if (!isdigit(c))
return E_INVCHAR;
number = '0' - c; /* Negated digit */
while ((c = getchar()) != EOF && isdigit(c))
{
int d = '0' - c; /* Negated digit */
if (number < INT_MIN / 10 || (number == INT_MIN/10 && d < INT_MIN % 10))
return E_OVERFLOW;
//printf("N1 %d; d %d; ", number, d);
number = number * 10 + d;
//printf("N2 %d\n", number);
}
if (c != EOF)
ungetc(c, stdin);
if (pos_neg != -1)
{
//printf("Should be switched (%d)(%d)\n", pos_neg, number);
if (number == INT_MIN)
return E_OVERFLOW;
number = -number;
//printf("Should be positive (%d)(%d)\n", pos_neg, number);
}
*value = number;
return E_OK;
}
static void gobble_input(void)
{
int c;
while ((c = getchar()) != EOF)
{
if (isdigit(c) || c == '+' || c == '-')
{
ungetc(c, stdin);
break;
}
printf("Skip %c\n", c);
}
}
int main(void)
{
int rc;
int number;
while ((rc = read_an_int(&number)) != E_EOF)
{
switch (rc)
{
case E_INVCHAR:
printf("Invalid character spotted\n");
gobble_input();
break;
case E_OVERFLOW:
printf("Input would have overflowed integer range %d..%d\n", INT_MIN, INT_MAX);
break;
case E_OK:
printf("Input number: %d\n", number);
break;
default:
assert(0);
break;
}
}
return 0;
}
我使用的测试数据文件是:
0
1
2
3
4
5
6
7
8
9
11
+123
1234
56789
+123456789
2147483647
2147483648
+000000123456789
000000123456789
-0000
+0000
-1
-2
-9
-21
-321
-4321
-2147483647
-2147483648
-2147483649
# Bogus data or partially bogus data
-
+
-213a
+213a
+.213
3.14159E+23
输出结果是:
Input number: 0
Input number: 1
Input number: 2
Input number: 3
Input number: 4
Input number: 5
Input number: 6
Input number: 7
Input number: 8
Input number: 9
Input number: 11
Input number: 123
Input number: 1234
Input number: 56789
Input number: 123456789
Input number: 2147483647
Input would have overflowed integer range -2147483648..2147483647
Input number: 123456789
Input number: 123456789
Input number: 0
Input number: 0
Input number: -1
Input number: -2
Input number: -9
Input number: -21
Input number: -321
Input number: -4321
Input number: -2147483647
Input number: -2147483648
Input would have overflowed integer range -2147483648..2147483647
Invalid character spotted
Skip
Skip B
Skip o
Skip g
Skip u
Skip s
Skip
Skip d
Skip a
Skip t
Skip a
Skip
Skip o
Skip r
Skip
Skip p
Skip a
Skip r
Skip t
Skip i
Skip a
Skip l
Skip l
Skip y
Skip
Skip b
Skip o
Skip g
Skip u
Skip s
Skip
Skip d
Skip a
Skip t
Skip a
Skip
Invalid character spotted
Invalid character spotted
Input number: -213
Invalid character spotted
Skip
Input number: 213
Invalid character spotted
Skip
Invalid character spotted
Input number: 213
Input number: 3
Invalid character spotted
Input number: 14159
Invalid character spotted
Input number: 23
请注意,最后一行提供了 3 个有效数字(以及两个无效字符,. 和 E)。
这不是特别容易;这就是为什么这些东西被编码在库函数中的原因。此外,“无字符串”要求意味着当存在无效字符或溢出时,我无法进行体面的错误报告。