在Ada语言中从函数返回可变大小的矩阵

4
我正在为大学课程学习Ada语言,但我对其中一些概念感到困惑。
我目前遇到的问题是:假设我有一个函数,它接受一个矩阵(只是一个整数二维数组),并返回一个新的、更小的矩阵(去掉第一行和第一列)。
我这样声明矩阵和函数:
type MATRIX is array(INTEGER range <>, INTEGER range <>) of INTEGER;
function RemoveFirstRowCol (InMatrix: in MATRIX) return MATRIX is

然后我决定返回矩阵的大小:

     Result_matrix: MATRIX (InMatrix'First(1) .. InMatrix'Length(1) - 1, InMatrix'First(2) .. InMatrix'Length(2) - 1);

然后我进行计算并返回Result_matrix。我的问题是:当我尝试将此函数的结果返回到任何不是具有完全正确大小的已声明矩阵中时,我会在运行时得到异常。我的问题是,我这样做对吗?我觉得我不应该提前知道函数返回的大小。即使使用比我得到的矩阵更大的已声明矩阵,我仍然会出现错误。不过,整个Ada的思想是强类型,所以也许这是有意义的(我应该确切地知道返回类型)。总之,我是否正确地执行了此操作,是否真的没有办法在预先不知道返回矩阵大小的情况下使用此函数?谢谢,Edan。
4个回答

4

您不需要提前知道返回矩阵的大小,也不需要使用访问(指针)类型。只需在单元或块的声明部分调用函数即可,边界将自动设置:

procedure Call_The_Matrix_Reduction_Function (Rows, Cols : Integer) is

   Source_Matrix : Matrix(1 .. Rows, 1 .. Cols);

begin
   -- Populate the source matrix

   -- ...

   declare
      Result : Matrix := RemoveFirstRowCol (Source_Matrix)
      -- Result matrix is automatically sized, can also be declared constant
      -- if appropriate.
   begin
      -- Process the result matrix

      -- ...

   end;
end Call_The_Matrix_Reduction_Function;

注意:由于结果矩阵是在堆栈上分配的,如果行数和列数很大,可能会出现问题。


1

因为您的MATRIX类型是使用未绑定索引声明的,所以该类型是不完整的。这意味着它可以被函数返回。在这种情况下,它就像指针一样。当然,编译器在编译时不知道确切的索引,结果矩阵将始终分配在堆中。

您的解决方案应该是有效的。唯一的问题是当您创建结果矩阵时,它只能在原始矩阵索引从0开始的情况下工作。

m:MATRIX(11..15,11..20);

在这种情况下,m'first(1) 是11,m'length(1) 是5!因此你得到:
Result_matrix:MATRIX(11..4,11..9);

出现了约束错误(CONSTRAINT_ERROR)...

请使用最后一个属性。即使您通常使用0索引。

但请记住,您不需要使用指向矩阵的指针,因为该矩阵也是不完整的,这就是为什么它可以被用作函数返回值。


1
严格来说,GNAT(不知道其他编译器)不会在堆上分配结果;它将在“次级堆栈”上分配,并在离开作用域时自动释放。 - Simon Wright

0

你的函数在编译时无法确定结果矩阵的大小,需要返回指向新矩阵的指针:

type Matrix is array (Positive range <>, Positive range <>) of Integer; 
type Matrix_Ptr is access Matrix; 

       -- chop the 1'th row and column
       function Chopmatrix (
             Inputmatrix : in     Matrix ) 
         return Matrix_Ptr is 
          Returnmatrixptr : Matrix_Ptr;  

       begin

          -- create a new matrix with is one row and column smaller
          Returnmatrixptr  := new Matrix(2 .. Inputmatrix'Last, 2..  Inputmatrix'Last(2) );
          for Row in Inputmatrix'First+1 .. Inputmatrix'Last loop
             for Col in Inputmatrix'First+1 .. Inputmatrix'Last(2) loop
                Returnmatrixptr.All(Row,Col) :=   Inputmatrix(Row,Col);
             end loop;

          end loop;
          return Returnmatrixptr;
       end Chopmatrix ;

1
您几乎肯定不需要在堆上分配新矩阵。如果目标变量由调用(M: Matrix := RemoveFirstRowCol (Input_Matrix);)初始化,它将在(次要)堆栈上分配。 - Simon Wright

0

调用者知道它传递给函数的矩阵的维度,因此调用者可以根据这些维度定义存储函数返回值的变量的类型。这真的不起作用吗?


它确实能工作,只是我认为有点笨拙(因为我不希望调用我的函数的人需要进行这些计算)。 - Edan Maor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接