将别名记录数组传递给过程

Passing array of aliased records to a procedure

在 Ada 2012 中,我希望在声明的数组中有一个链表,而不是分配的。我想通过程序设置链接指针。

我已将我的程序简化为以下演示我想要使用的原理的程序,但我无法在 Raspi 上的 Gnat 4.9.2 (Debian Jessie) 运行 中编译它...

procedure Arr is
   type Cell;
   type Cell_Ptr is access all Cell;

   type Cell is
      record
         Number : Integer := 0;
         Next : Cell_Ptr := null;
      end record;

   type Chain is array (1 .. 100) of aliased Cell;

   procedure Make_Links (Ch : in out Chain);

   procedure Make_Links (Ch : in out Chain) is
   begin
      for I in Ch'First .. Ch'Last - 1 loop
         Ch (I).Next := Ch (I + 1)'Access;                 -- ERROR HERE
      end loop;
   end Make_Links;

   My_Chain : Chain;
begin
   Make_Links (My_Chain);
end Arr;

我收到此编译器错误: “非局部指针不能指向局部对象”在上面指示的行。

我知道我正在尝试做一些有点奇怪的事情,但我计划有一些其他函数,这些函数根据我传递这个单元格数组的过程以不同的方式(向后或随机等)执行链接到.

如何修复此代码以使其通过编译?不太了解这个(我还是个新手,但很享受学习的过程)。

由于您实际上并未分配和释放内存,因此看不到需要指针。我会通过做这样的事情来实现相同的功能:

procedure Arr is

   type Cell_Index is new Integer range 0 .. 100;
   subtype Valid_Cell_Index is Cell_Index range 1 .. Cell_Index'Last;

   type Cell is
      record
         Number : Integer := 0;
         Next   : Cell_Index := 0;
      end record;

   type Chain is array (Valid_Cell_Index) of Cell;

   procedure Make_Links (Ch : in out Chain);

   procedure Make_Links (Ch : in out Chain) is
   begin
      for I in Valid_Cell_Index'First .. Valid_Cell_Index'Last - 1 loop
         Ch (I).Next := I+1;
      end loop;
   end Make_Links;

   My_Chain : Chain;
begin
   Make_Links (My_Chain);

end Arr;

这样您仍然可以使用 Next 作为同一数组的索引,并且可以使用您想要的任何链接模式预加载您的数组。

不使用 ’Access,而是使用 ’Unrestricted_Access。这是 one of GNAT’s “implementation-defined” attributes:

The Unrestricted Access attribute is similar to Access except that all accessibility and aliased view checks are omitted. This is a user-beware attribute.

最后我想通了。以下代码是 OP 中代码的修改版本。它做了我最初想要的,没有做任何不愉快的事情......

with Ada.Integer_Text_IO, Ada.Text_IO;
use Ada.Integer_Text_IO, Ada.Text_IO;

procedure Arr is
   type Cell;
   type Cell_Ptr is access all Cell;

   type Cell is
      record
         Number : Integer := 0;
         Next : Cell_Ptr := null;
      end record;

   type Chain is array (1 .. 100) of aliased Cell;
   type Chain_Ptr is access all Chain;

   procedure Make_Links (CP : in out Chain_Ptr);

   procedure Make_Links (CP : in out Chain_Ptr) is
   begin
      for I in CP'First .. CP'Last - 1 loop
         CP.all (I).Next := CP.all (I + 1)'Access;
      end loop;
   end Make_Links;

   My_Chain : aliased Chain;
   My_CP : Chain_Ptr := null;
   My_C : Cell_Ptr := null;
begin
   My_CP := My_Chain'Access;
   Make_Links (My_CP);

   --  verify that the code works by writing values into the array
   for I in My_Chain'Range loop
      My_Chain (I).Number := 1000 * I;
   end loop;

   --  and read them back out using the pointer links
   My_C := My_Chain (My_Chain'First)'Access;
   while My_C /= null loop
      Put (My_C.Number);
      Put_Line ("");
      My_C := My_C.Next;
   end loop;

end Arr;

我没有直接传递数组,而是传递了一个指向数组的指针,Gnat 似乎对此很满意。我 认为 我之前尝试做的事情被过程参数的 "pass by copy" 规则破坏了。