【问题标题】:How does this Decimal to Binary conversion program work?这个十进制到二进制转换程序是如何工作的?
【发布时间】:2017-06-26 01:15:24
【问题描述】:

我一直在寻找一个简单的十进制到二进制转换程序,然后,我遇到了以下使用递归的程序。

void bin(unsigned n)
{
/* step 1 */
if (n > 1)
    bin(n/2);

/* step 2 */
printf("%d", n % 2);
}

int main(void)
{
bin(4);
return 0;    
}

正如预期的那样,这个程序的输出是100。但是,我无法理解它如何显示输出100,因为根据我的说法,输出应该是1(不正确)而不是100

这是我对bin函数步骤的解释。

  1. 我们会将4 作为bin 的参数放在首位。
  2. 4 > 1,因此,它将再次使用参数 2 调用 bin 函数。
  3. 现在,2 > 1,因此,它将再次使用参数 1 调用 bin 函数。
  4. 由于1不大于1,我们将转到步骤2,编译器将打印1(因为1%2=1),因此,这个程序应该只打印1而不是100

谁能解释并指导我哪里错了?

【问题讨论】:

  • 使用您的 调试器 并单步执行程序。您将很快了解为什么以及何时打印零。
  • 程序使用递归逻辑。请通过递归了解更多详细信息。
  • 这个sn-p中唯一的十进制printf("%d", n % 2);(应该是printf("%u", n % 2);,顺便说一句)
  • @wildplasser, n%2 是二进制的 0000...010000..00 所以%u 是不必要的。
  • 该用户明确表明他试图这样做,为什么要投反对票,他正在努力学习和尝试。

标签: c recursion binary


【解决方案1】:

将整数除以 2 与将其右移一位相同。所以使用递归,它将位向右移动,直到只剩下 1 位(最左边的位)

然后它打印最左边的位并返回。返回时,仍然有两个位,最左边和最左前一个。使用% 2,它会丢弃所有最左边的位并在最左边打印这个。现在它返回并且......等等。

这有效地从左到右打印位。

【讨论】:

  • Ogilivie 在将位向右移动的同时,我们应该将最右边的位旋转到最左边还是完全消除它?
  • 不要旋转它。你的递归永远不会结束。
  • 如果我们不旋转它,那么它将如何找到其他两位。例如。如果我取 7 而不是 4,那么它的二进制表示是 111。首先除以 2 后,它将变为 011;秒后,它将变为 001。然后在打印 1 后,仅剩下两个 0。从哪里可以找到另外两个 1?
  • 它在递归返回时找到它们。 我强烈建议您通过调试器逐步执行此操作,以便查看发生了什么!
【解决方案2】:

按照你的逻辑:

somefunc();
someotherfunc();

somefunc() 完成它的事情时,someotherfunc() 将不会被执行,因为somefunc() 已经完成。

当对bin 的调用完成或根本不运行时,步骤 2 完成,然后步骤 2 始终完成。因此,bin 的每次迭代都会打印一些内容,并且由于它是递归之后,它会从最深处开始执行,并以与实际递归路径相反的顺序进行打印。

bin的每次调用都有自己的局部变量,因此它们不会相互干扰。因此,当从bin 调用bin 时,n 与以前相同,但返回的bin 有一个n,它是调用者n 的一半。

【讨论】:

  • 您能否解释一下为什么它会从最深处递归它或以相反的顺序打印,而不是您所说的实际递归路径。我不明白它背后的逻辑。
  • @DG4 这是因为它会按照您编写它的顺序来声明它。如果在条件递归之前移动 print 语句,它将以相反的顺序打印它,因为它首先打印最低位,然后递归。由于您的版本首先递归并等待 every depth 在此迭代之前打印,并且您始终打印最低位,因此它将最高位打印到最低位,因此与第一次迭代的递归路径的顺序相反是最低位,下一个是下一个最低位......最高位。
【解决方案3】:

也许图示的顺序会让你更容易理解:

  • bin(4)
    • bin(2)
      • bin(1)
        • printf("%d",1%2); // 1
      • printf("%d",2%2); // 0
    • printf("%d",4%2); // 0

【讨论】:

  • 我理解你显示的这个序列,但我无法理解的是第二个和第三个 printf 语句,其输出为 0 在打印 1 之后出现。是因为我们看到这里的堆栈实现如 push 和 pop 还是有其他原因?
  • @DG4: bin(2) 执行它下面的两个项目符号。 bin(4) 执行它下面的两个项目符号。你现在明白了吗?
  • 不,我问的是包含 2%2 和 4%2 的 printf 语句。
  • @DG4: bin(2) 调用bin(2/2) 然后printf("%d",2%2)。同样,bin(4) 调用bin(4/2),然后调用printf("%d",4%2)。你现在明白了吗?
  • @DG4:bin(1) 完成,然后bin(2) 继续。然后bin(2) 完成,然后bin(4) 继续。
【解决方案4】:

你在正确的轨道上,

  1. 我们先把4作为bin的参数。

  2. bin(4): 4 > 1,因此,它将再次调用带有参数2的bin函数。函数执行尚未完成。被调用函数执行后程序会返回这里

  3. bin(2):现在,2 > 1,因此,它将再次调用带有参数 1 的 bin 函数。函数执行尚未完成。被调用函数执行后程序会返回这里

  4. bin(1):由于 1 不大于 1,我们将转到步骤 2,编译器将打印 1(因为 1%2=1),因此该程序应打印“1”。函数执行完成

  5. bin(2):程序现在返回调用函数并打印 0(因为 2%2=0)。函数执行完成
  6. bin(4):程序现在返回调用函数并打印 0(因为 2%2=0)。函数执行完成

因此输出为“100”

【讨论】:

  • 在第四步之后的回答中,程序如何在打印出值'1'后返回调用函数并带有新值?我的第二个问题是你是否将它视为一个堆栈,我们在其中看到推送和弹出之类的东西来打印函数的值?
  • 当你从你的主函数中调用任何函数(比如说fun())时,程序控制在执行fun()之后不会返回到主函数吗?同样的事情也发生在这里。
猜你喜欢
  • 1970-01-01
  • 2014-07-31
  • 2017-11-08
  • 2017-07-10
  • 2023-04-11
  • 2018-04-03
  • 2016-02-09
  • 2016-08-26
相关资源
最近更新 更多