dc unix:即使在同一数组索引处存储新值后仍保留初始值

roo*_*kea 5 calculator dc

我无法理解手册页中给出的这个例子dc

$ dc  
 1 0:a 0Sa 2 0:a La 0;ap  
 1  
Run Code Online (Sandbox Code Playgroud)

对我来说答案应该是 2 因为:

  1. 1 0:a
    这里我们将 1 存储在 array 的第 0 个位置a

  2. 0Sa
    现在我们将 0 压入 register 的堆栈a

  3. 2 0:a 现在我们再次将 2 存储在数组的第 0 个位置,a从而覆盖先前存储在该位置的 1。

  4. La
    现在我们弹出存储在寄存器堆栈中的 0a并将其推送到主堆栈。

  5. 0;a
    现在我们再次将 0 推送到主堆栈,然后将其弹出以用作数组索引,因此我们将存储在数组第 0 个位置的 2 推a送到主堆栈。

  6. p
    现在我们打印主堆栈的顶部,即 2。所以答案应该是 2。

我错过了什么?

PS- 我想dc用作标签,但看起来它不存在,因此必须至少使用一个标签debian(我的工作站操作系统)。

Run*_*ium 6

就像在混合数组和堆栈中一样。在示例中,寄存器a既用作数组又用作堆栈。

1 0:a 
0 Sa 
2 0:a 
La 
0;a p
Run Code Online (Sandbox Code Playgroud)
  1. First :a-register a被视为一个数组
  2. 然后Sa- 寄存器a被视为堆栈。实际上将数组从 pt 1. 向下推送并创建一个数组。As by man请注意,寄存器的每个堆叠实例都有自己的关联数组。
  3. 然后:a- 寄存器a被视为一个数组。将先前值和第一个数组值向下推。
  4. 然后La- 寄存器a被视为堆栈。要获得第一个堆叠数组,将丢弃a[0]=2它,因为它是一个数组。
  5. 然后;a- 寄存器a被视为一个数组。现在只剩下一个值了,添加到a的第一个数组值是1

有关更多示例,请参阅答案底部。


根据评论:

«每个寄存器有多少个数组和堆栈?我以为一个寄存器有一个堆栈和一个单独的数组。»

堆栈:

入栈dc是下推栈或 LIFO(后进先出)。和餐厅里的盘子一样。

      ,------ pop / push - take / leave 
    /
   |
   v
[-----] top
[-----]           ...                 ...                .
[-----]          [-----]             [-----]            ..
 (main)        (register-a)        (register-b)        ...
Run Code Online (Sandbox Code Playgroud)

我们有一个堆栈或工作堆栈,除非指定了需要寄存器的操作,否则将使用该堆栈。每个寄存器都有自己的堆栈。

基本寄存器操作:

  • Sr:从堆栈中弹出一个并将压入由 register 指定的堆栈。两个堆栈都修改了。r
  • Lr弹出一个由指定的寄存器堆栈的值r它到栈。两个堆栈都修改了。
  • sr:从堆栈中弹出一个值并将其写入寄存器。实际上更改 register 指定的堆栈中的最顶层值。如果该堆栈中没有值 – 添加它。堆栈已修改。寄存器堆栈保留在更改的值旁边。rr
  • lr:从寄存器读取r。如果有多个,则实际上是最高值。主要改变了。寄存器堆栈保留。
  • :r:从堆栈中弹出两个值,并使用第一个,最上面的,作为将第二个值存储在 register 数组中的位置的索引。主要改变了。寄存器堆栈保留。r
  • ;r:从堆栈中弹出一个值并将其用作索引,从哪里读取指定的寄存器中的当前数组。主要改变了。寄存器堆栈保留。r

堆栈和数组混合

一种查看方式是成对查看。当您开始时,所有寄存器都是空的。当您通过 将元素添加到堆栈时Sr,您隐藏了该堆栈中的所有底层元素。说你这样做:

1 Sx
2 Sx
4 Sx

x = (S)  4     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN
Run Code Online (Sandbox Code Playgroud)

现在您可以更改寄存器x 中的值,即;更改最顶部的元素 by sx,您可以读取 by lx– 无需更改堆栈中的元素数量:

lx p  # Read value in register x - in effect read topmost element from stack.
4     # Printed value by p.
3 sx  # Change value in register x - in effect change topmost element in stack.

x = (S)  3     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN
Run Code Online (Sandbox Code Playgroud)

如果您决定添加数组元素,事情就会朝着更复杂的方向发展。

4 1:x
5 2:x
    
x = [A] 
        [2]=5  VISIBLE
        [1]=4  VISIBLE
    (S)  3     VISIBLE
    (S)  2     HIDDEN
    (S)  1     HIDDEN
Run Code Online (Sandbox Code Playgroud)

现在我们已经向堆栈中的当前数组添加了值。我们可以读取和修改任何VISIBLE元素。

44 1:x
55 2:x
33 sx

1;x p # Read and print index 1
44

lx p  # Read and print stack top.
33

x = [A] 
        [2]=55  VISIBLE
        [1]=44  VISIBLE
    (S)  33     VISIBLE
    (S)  2      HIDDEN
    (S)  1      HIDDEN
Run Code Online (Sandbox Code Playgroud)

如果我们然后添加一个堆栈元素,一种方式可以说堆栈框架是不可扩展的,因为我们已经向其上方的数组添加了值。因此添加了一个新的堆栈帧

6 Sx
7 Sx

x = (S)  7      VISIBLE
    (S)  6      HIDDEN
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN
Run Code Online (Sandbox Code Playgroud)

如果我们现在尝试访问最后一个数组,它是隐藏的。实际上,我们从一个空数组中读取,结果是默认值0。我们可以修改寄存器的值7sr,但不能访问数组两级下来,除非我们摆脱上述两个堆元件。

如果我们现在决定添加一些数组元素,它们将被添加到一个新的数组中(作为一个配对数组),它位于栈顶元素。

8 1:x
9 2:x

x = [A]
        [2]=9   VISIBLE
        [1]=8   VISIBLE
    (S)  7      VISIBLE
    (S)  6      HIDDEN
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN
Run Code Online (Sandbox Code Playgroud)

现在,如果我们弹出堆栈,我们会弹出7,但由于中间有一个数组(可以这么说),它也被删除了。

Lx p  # Pop + print top stack element.
7     # Value printed.

x = (S)  6      VISIBLE
    [A] 
        [2]=55  HIDDEN
        [1]=44  HIDDEN
    (S)  33     HIDDEN
    (S)  2      HIDDEN
    (S)  1      HIDDEN
Run Code Online (Sandbox Code Playgroud)

89的数组消失了。值为6的堆栈元素可见。但是底层数组被阻塞了。通过1;x pyield 0读取。

在某种程度上,我们可以说堆栈元素是阻塞的,而数组是不透明的。数组有点挂在堆栈元素上。

我们需要从堆栈中再次弹出以显示底层堆栈元素 + 数组。

Lx p  # Pop + print top stack element.
6     # Value printed.

x = [A] 
        [2]=55  VISIBLE
        [1]=44  VISIBLE
    (S)  33     VISIBLE
    (S)  2      HIDDEN
    (S)  1      HIDDEN
Run Code Online (Sandbox Code Playgroud)

总之,可以说数组和堆栈的数量不限于每个寄存器一个。

每个寄存器有多少个数组和堆栈?
– 取决于您在该寄存器上执行的交替Sr:r操作次数。

另一种看待它的方式是只有一个堆栈但有多个数组,如果我们在添加数组元素之间添加堆栈元素......

另一种方式是说在任何给定时刻当前数组不是

[register][array]
Run Code Online (Sandbox Code Playgroud)

[register][stack-element][array]
Run Code Online (Sandbox Code Playgroud)

这使:

[register][stack-element][array][...]
[register][stack-element][array][1]
[register][stack-element][array][0]
Run Code Online (Sandbox Code Playgroud)

并且该stack-element部分是不透明的、只读的等等。尽管在这种情况下我们还必须记住,我们不需要堆栈元素的值。只将数组值添加到寄存器是可以的。

或者每个堆栈元素都与一个我们可以修改的零填充数组配对:

1 Sx
2 Sx
3 Sx
4 1:x
5 2:x
6 Sx
7 Sx
8 1:x
9 2:x

x = (S)  7   +   A[0]=0   A[1]=8   A[2]=9   A[3]=0  ...  A[2048]=0
    (S)  6   +   A[0]=0             ...                  A[2048]=0
    (S) 33   +   A[0]=0   A[1]=4   A[2]=5   A[3]=0  ...  A[2048]=0
    (S)  2   +   A[0]=0             ...                  A[2048]=0
    (S)  1   +   A[0]=0             ...                  A[2048]=0
Run Code Online (Sandbox Code Playgroud)

希望它使它更清楚一点。


一些例子


$ dc
[ein]  0:a
[zwei] Sa
[drei] 0:a

0;ap   # Copy + print index 0 of topmost array in register a
drei

Lap    # Throws away [drei] and pops+prints first element in stack*
zwei

0;ap   # Copy + print index 0 of first array 
ein
Run Code Online (Sandbox Code Playgroud)
$ dc
[uno]    0:a  # Array a(1)
[dos]    1:a  # Array a(1)
[tres]   2:a  # Array a(1)

[cuatro] Sa   # Array a(2)
[cinco]  Sa   # Array a(2)
[seis]   Sa   # Array a(2)

[siete]  0:a  # Array a(3)
[ocho]   1:a  # Array a(3)
[nueve]  2:a  # Array a(3)

Laf      # Throws away Array 3 to get to first stack array, Array 2.
seis

Laf
cinco
seis

Laf
cuatro
cinco
seis

2;af      # Now we're at the first array, Array 1.
tres
cuatro
cinco
seis

1;af
dos
tres
cuatro
cinco
seis

0;af
uno
dos
tres
cuatro
cinco
seis
Run Code Online (Sandbox Code Playgroud)


mik*_*erv 5

你必须记住,这dc是一个编译器——而且是一个疯狂的旧编译器。它是一种机器语言——面向堆栈的计算器。它非常强大,但它的界面并不是为您设计的 - 它的设计目的是在所有用户友好性都经过机器处理后,有效地处理您用其他语言编写的指令。

dc不以直观的方式存储数据。dc 东西东西。当它读取新输入时,如果不立即执行,则该值只会被扔到堆栈上。堆栈中的所有内容都已被向下推 - 最新的位于顶部,最旧的位于底部。您必须处理最新的堆栈成员才能检索最旧的堆栈成员。

很多人都能得到这么多。毕竟,堆栈并不那么奇怪——它有点像洗衣篮。但这也是相当一维的,而且dc比这更进一步。

所以就有了输入堆栈——主堆栈。默认情况下,这是所有dc指令输入和输出的所在。当你向它发出命令时,它就会工作。但还有所有其他寄存器 - 至少 256 个。其中每一个本身也是一个堆栈。

[Ss]您通常使用ave 和oad 命令来处理寄存器[Ll]。要将主堆栈上的顶部值作为标量值保存到寄存器中,a请执行以下操作sa。然后,您可以l随时使用 将此标量值加载回主堆栈的顶部la。好吧,只要寄存器的当前实例a保持当前状态,就可以。

要在旧的标量值保留的地方创建新的寄存器标量实例,您可以使用. 该命令弹出主堆栈并入栈寄存器堆栈。与 不同,该命令是寄存器的破坏性负载 - 当使用该命令将标量值弹出到主堆栈时,该寄存器实例中的任何内容都会被破坏,并且寄存器的任何先前实例都可以再次访问。aSaalaLaL

这也很容易通过一点练习就能掌握——它就像主堆栈一样,但每个寄存器都有一个。但每个寄存器还有一个更进一步的维度——它们的数组。

每个寄存器的每个实例都有一个数组。我认为默认大小是每个 2048 个索引 - 尽管我经常想知道堆栈有多深并且只能说它相当深。当您实例化寄存器的新标量值时,您不仅会下推其标量值,还会下推其数组。新实例有一个新数组,旧实例的数组保持不变,并且在弹出新实例后将像标量值一样可供您访问。

数组索引访问有点棘手。首先,几乎所有主堆栈操作都是破坏性的。访问数组索引的唯一方法是从主堆栈中提取其值,然后调用它。因为您的索引引用此时已被破坏,所以很难召回它。o并且O对于保留索引计数器很有用 - 但不要尝试使用索引 1 或 0。

不管怎样,寄存器的数组和它的堆栈不是独立的,而是相互依赖和多维的。通过练习、耐心和一点超人的决心,可以用它完成一些很酷的事情。祝你好运。

  • @rootkea - 不:“s”*不*执行新实例。它替换寄存器的标量值。`S` 获取一个*新*实例并将其堆叠在旧实例之上。‘L’ 销毁新的并将其弹出,将旧的再次带到堆栈的顶部。 (2认同)