我有以下功能:第一个打印给定基数(基数)中的无符号整数 第二个函数完全相同但带有有符号整数。 如您所见,这些功能的主体完全相同。我一直在努力工作几个小时,以防止相同的代码加倍,我找不到解决这个问题的方法。
无符号功能
const char *digit = "0123456789abcdef";
int print_int_helper_unsigned(unsigned int n, int radix, const char *digit) {
int result;
if (n < radix) {
putchar(digit[n]);
return 1;
}
else {
result = print_int_helper_unsigned(n / radix, radix, digit);
putchar(digit[n % radix]);
return 1 + result;
}
}
签名功能:
int print_int_helper( int n, int radix, const char *digit) {
int result;
if (n < radix) {
putchar(digit[n]);
return 1;
}
else {
result = print_int_helper(n / radix, radix, digit);
putchar(digit[n % radix]);
return 1 + result;
}
}
答案 0 :(得分:4)
也许你想要这个:
#include <math.h>
...
int print_int_helper(int n, int radix, const char *digit) {
if (n < 0)
{
putchar('-');
}
return print_int_helper_unsigned(abs(n), radix, digit);
}
答案 1 :(得分:0)
将递归部分重构为辅助函数:
static void fprintf_digits_recursive(FILE *out,
const unsigned long radix,
const char *digits,
unsigned long value)
{
if (value >= radix)
fprintf_digits_recursive(out, radix, digits, value / radix);
fputc(digits[value % radix], out);
}
我将其标记为static
,因为它只能在此编译单元(文件)中可见,而不能在外部直接调用。
辅助功能的目的是打印出一个数字。如果value
有多个数字,则首先打印较高的数字。 (这就是递归调用之后fputc()
的原因。)
有符号和无符号整数打印机使用助手:
void print_int(const int value, const char *digits, const int radix)
{
if (radix < 1 || !digits) {
fprintf(stderr, "print_int(): Invalid radix and/or digits!\n");
exit(EXIT_FAILURE);
}
if (value < 0) {
fputc('-', stdout);
fprintf_digits_recursive(stdout, radix, digits, (unsigned long)(-value));
} else
fprintf_digits_recursive(stdout, radix, digits, (unsigned long)(value));
}
void print_uint(const unsigned int value, const char *digits, const int radix)
{
if (radix < 1 || !digits) {
fprintf(stderr, "print_int(): Invalid radix and/or digits!\n");
exit(EXIT_FAILURE);
}
fprintf_digits_recursive(stdout, radix, digits, (unsigned long)value);
}
我故意添加了输出流标识符并更改了参数顺序,以便更容易理解可见函数(有时也称为包装函数,如果它们非常简单)可以与实际工作的实际内部帮助函数不同。
我将基数和数字检查添加到包装函数中,因为这是推荐的做法。 (也就是说,不要将参数检查留给辅助函数,而是在包装函数中执行。如果需要,也可以提供&#34;快速&#34; /未检查的包装函数版本。)< / p>
这种方法用于将重复的代码重构为帮助程序和实际的公共函数。你找到重复的代码,将它移动到一个单独的内部帮助函数,注意参数可能与公共函数使用的非常不同 - 通常,你可能有例如一个动态分配的缓冲区,用于放入数据。
没有真正困难的部分,你只需要练习一下,并在选择将哪些参数传递给辅助函数时学会考虑多个用户 - 最初重复的函数。
在非常复杂的情况下,您可能需要将辅助函数拆分为多个帮助程序;进入某种帮助工具箱。这通常是例如动态内存管理辅助函数。
例如,如果要将其转换为生成动态分配字符串的接口,则可以使用字符串缓冲区接口,例如
struct strbuffer {
char *data;
size_t size; /* Number of chars allocated for */
size_t used; /* Number of chars used in data */
};
#define STRBUFFER_INIT { NULL, 0, 0 }
static void strbuffer_addchar(struct strbuffer *ref, const char c);
static char *strbuffer_finalize(struct strbuffer *ref);
static char *strbuffer_finalize_reverse(struct strbuffer *ref);
这样有符号的整数到字符串函数可能看起来像
char *new_int_to_string(const int value, const size_t radix, const char *digits)
{
struct strbuffer buf = STRBUFFER_INIT;
if (value < 0) {
reverse_radix(&buf, radix, digits, -value);
strbuffer_addchar(&buf, '-');
} else
reverse_radix(&buf, radix, digits, value);
return strbuffer_finalize_reverse(&buf);
}
和reverse_radix()
以相反的顺序构建数值
void reverse_radix(struct strbuffer *ref,
const unsigned long radix,
const char *digits,
unsigned long value)
{
do {
strbuffer_addchar(ref, digits[value % radix]);
value /= radix;
} while (value > 0);
}
辅助函数strbuffer_finalize()
会将data
字段重新分配到所需的确切长度,包括字符串终止\0
,清除结构,然后返回data
; strbuffer_finalize_reverse()
执行相同操作,但首先撤消内容。这样我们也可以将递归调用转换为一个简单的循环。
您甚至可以使用strbuffer助手实现浮点版本;你只是将小数部分与小数部分分开转换(所以还有两个辅助函数)。