【问题标题】:How to print values in reverse without the use of arrays nor pointers in C如何在不使用 C 中的数组或指针的情况下反向打印值
【发布时间】:2021-12-09 04:33:31
【问题描述】:

我一直在研究将给定数字(十进制基数)转换为从 2 到 16 的任何其他基数的代码。

显然,我遇到了函数base_conversion_it(它代表迭代)反向打印值的问题。

我不能使用数组或指针,互联网上的每个人似乎都这样解决这个问题。我的任务需要创建一个迭代函数和一个递归函数(我做过并且工作过)。

void base_conversion_it(unsigned int n, unsigned int b) {

    if (n > 0) {

        //bases between 2 and 16
        if (b >= 2 && b <= 16) {

            int r;          //r = remainder
            int q = 1;      //quotient
            int num;        //saves the remainder

            while (q != 0) {

                r = n % b;
                printf("%X", r);

                q = n / b;
                n = q;
            }
        }
    }
}

【问题讨论】:

  • 您可能会或可能不会注意到参数n 是二进制的,而不是十进制的。它实际上并没有太大区别,但整数不会在计算机内部存储为十进制数。
  • “迭代、无指针、无数组”的约束使得很难产生有效的解决方案。您可能需要确定将打印多少位,然后安排打印重新计算的每个数字 - 这涉及多个循环。
  • @JonathanLeffler 我已经通过k = (log10(n) / log10(b) + 1) 设法确定了该号码的位数,但我如何相应地打印它们?
  • 查看来自 0______ 的更新答案——迭代解决方案相当简洁。它确实有两个循环——但我不经意间想到了三个循环,后两个是嵌套的。当然,避免嵌套要好得多。此外,请注意浮点运算中可能存在的不准确性。

标签: c printing reverse base ansi-c


【解决方案1】:

您从 units 数字开始转换。
也许从最重要的数字开始?

// It's Undefined Behaviour if `b` is outside the range [2...16]
void base_conversion_it(unsigned int n, unsigned int b) {
    unsigned highestbase = 1;
    while (highestbase * b <= n) highestbase *= b; //possible wrap around and infinite loop

    while (highestbase) {
        printf("%X", n / highestbase);
        n %= highestbase;
        highestbase /= b;
    }
    printf("\n");
}

【讨论】:

  • 唯一的问题是 base > 16
  • 是的...我删除了支票 (if (b &gt;= 2 &amp;&amp; b &lt;= 16)) 并决定将其命名为 UB :)
  • @pmg 你能否进一步解释为什么你删除了if 检查?
  • 如果函数被正确记录并且用户遵循规则,if 是多余的......就像sqrt(-42)
【解决方案2】:

抱歉错过了迭代。

char digits[] = "0123456789ABCDEFGHIJKLMNOP";

void print(unsigned long long val, unsigned base)
{
    unsigned long long mask = base;
    while(val / mask >= base) mask *= base;
    do
    {
        printf("%c", digits[val / mask]);
        val %= mask;
        mask /= base;
    }while(val);
}

int main(void)
{
    print(45654756453, 10); printf("\n");
    print(45654756453, 16); printf("\n");
    print(45654756453, 24); printf("\n");
    print(45654756453, 2); printf("\n");
}

https://godbolt.org/z/W3fGnnhYs

递归:

char digits[] = "0123456789ABCDEF";

void print(unsigned long long val, unsigned base)
{
    if(base <= 16 && base > 1)
    {
        if(val >= base) print(val / base, base);
        printf("%c", digits[val % base]);
    }
}

https://godbolt.org/z/84hYocnjv

【讨论】:

  • OP 有一个递归解决方案,需要不使用数组或指针的迭代解决方案的帮助。这在所有这些方面都失败了。
  • @JonathanLeffler 错过了这一点,已修改
  • 好多了。残差数组可以通过 OP 使用的相同技术来修复:printf("%llX", val / mask); — 并且不清楚数字的(常量)数组,而不是用于存储被发现的数字的数组,严重违反规则。
  • @JonathanLeffler 您可以将其扩展为基数 > 16,只需在数组中添加字母(或者更确切地说是数字 :))。 "%x" 不起作用godbolt.org/z/84hYocnjv
  • 由于问题规范说“从 2 到 16 的任何其他基数”,这不是一个主要问题。对于学校作业,可能需要遵循“无阵列”法的规定。对于一般工作,使用数字数组是完全合理的。我可能会优先使用putchar(digits[val / mask]); 而不是printf(),但这是琐事——在多线程世界(强制流锁定)中使用putchar() 的好处比以往的情况要小得多。
【解决方案3】:

如果您不能使用数组(包括字符串)或递归,那么我认为您需要以最高有效优先顺序计算输出数字。这比以相反的顺序计算它们并反转结果有点不自然,但它可以做到:

  • 使用循环查找n 的最重要的非零基数-b 的位值。例如,检查n除以b的连续幂的结果,直到结果为0,然后退一步。

  • 在一个单独的循环中,从发现的最重要位置的那个开始,一个接一个地读取n 的基数-b。对于每个数字,

    1. n的当前值除以当前数字的位值pv得到一个数字值。
    2. n 替换为n % pv

    小心一直向下直到位置值 1,而不是在 n 变为 0 时停止。

【讨论】:

    猜你喜欢
    • 2013-07-08
    • 2023-03-03
    • 2016-10-14
    • 1970-01-01
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-08
    相关资源
    最近更新 更多