Algorithm 我的排序算法运行时错误

Algorithm 我的排序算法运行时错误,algorithm,Algorithm,我开发了下面的排序算法,但是有一些运行时错误我无法找出。当涉及到填充数组的部分时,程序终止。我还是ada的初学者,所以我不知道问题出在哪里 With Ada.Text_IO; With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO; Use Ada.Text_IO; Procedure sort is n,i,x : Integer; -- Max_Heapify Function... Procedure Max_Heapif

我开发了下面的排序算法,但是有一些运行时错误我无法找出。当涉及到填充数组的部分时,程序终止。我还是ada的初学者,所以我不知道问题出在哪里

With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;

Procedure sort is
   n,i,x : Integer;


   -- Max_Heapify Function...
   Procedure Max_Heapify ( i, n : integer) is 
      j, Temp : Integer;
   begin
      Temp:=Int_Acc(i);
      j:=2*i;

         if Temp>Int_Acc(j) then


         elsif Temp<=Int_Acc(j) then
            Int_Acc(j/2):=Int_Acc(j);
            j:=2*j;
         end if;
      end loop;
      Int_Acc(j/2):=Temp;
   end Max_Heapify;


begin
   Get(n);
      for i in MyArr'range loop
         Put_Line("Enter Element " & Integer'Image(i));
         Get(MyArr(i));
      end loop;
   end;
end sort;
带有Ada.Text\u IO;
使用Ada.Integer\u Text\u IO;
使用Ada.Integer\u Text\u IO;
使用Ada.Text\u IO;
程序排序是
n、 i,x:整数;
--Max_Heapify函数。。。
过程Max_Heapify(i,n:整数)为
j、 温度:整数;
开始
温度:=Int_Acc(i);
j:=2*i;
如果温度>Int_Acc(j),则
elsif温度<代码>如果jInt_Acc(j)那么
j:=j+1;
我想你想要的只是“和”而不是“然后”,尽管我已经好几年没看过Ada代码了


编译了吗?

您的问题是坚持使用c风格的编程范例编写Ada代码

首先

声明:

   Type Arr is array(1..20) of Integer;
   Type int_access is access Arr;
   MyArr : int_access;
使用
Int\u Acc:in-out Int\u access
作为过程参数在Ada中是无用的。您正试图传递一个指向数组的指针(您正在这样做!),但您应该只传递
类型Arr
作为
输入输出
——Ada编译器知道这是作为指针来做的

其次

我看不出您实际上在哪里为
MyArr
分配内存。这可能是运行时错误的来源。(当您写入或索引一个不存在的数组时,我希望会出现问题!)

第三: 您似乎混合了固定长度数组和可变长度输入。如果N>20,您将遇到问题

第四
这种语言并不是从喜欢它的人那里得到帮助的最佳方式。

NWS已经解决了这个问题:有一个指针,但没有数组

但很明显,您已经学习了C语言,这就给您留下了很多学习其他语言的机会,包括Ada。确实有更好的方法来做很多事情,这些方法并没有教给C程序员,因为C不允许它们


分配不带指针的可变大小数组,例如malloc和free

Type Arr is array(positive range <>) of Integer;   -- of any size

begin
   Put_Line("Enter Number Of Elements Of Array");
   Get(n);
   declare    -- now we know the size
      My_Arr : Arr(1 .. n);
   begin      -- My_Arr is in scope until the end of this block
      ...
   end;
end sort;
这是不好的,因为它违反了DRY原则:循环边界重复,并且有希望表示作为单独参数传递的数组大小的东西。。。例如,如果您决定将
n
重命名为有意义的名称,这将是维护的噩梦

更好编程:使用类型系统。认识到仅仅声明一个数组就声明了一个新的整数子类型,表示数组的索引。您可以通过
My\u Arr'range
访问它,也可以通过
My\u Arr'last
访问上限

   for i in My_Arr'range loop
      Get(MyArr(i));
   end loop;
   HeapSort(MyArr);
   for i in My_Arr'range loop
      Put_Line(Integer'Image(MyArr(i)));
   end loop;
而诸如在数组声明后重新定义n之类的意外情况将不再产生缓冲区溢出。 注意:Heapsort现在从数组中获取其范围。(Max_Heapify可能仍然需要一个单独的参数来操作数组的子集)

可以说是最好的-如果它能让意图更清楚-明确地命名索引数据类型并使用它

   declare    -- now we know the size
      subtype My_Range is positive range 1 .. n;
      My_Arr : Arr(My_Range);
   begin      -- My_Arr is in scope until the end of this block
      for i in My_Range loop ...

最后,你更喜欢哪一个;错误发生后立即出现存储错误异常(写入忘记分配的内存),或者由于在另一个变量上乱涂乱画而导致很晚发生异常


编辑

在解决了主要问题之后,还有两个更微妙的问题

如果我编译修改后的程序(在Gnat 4.8中),我会收到几个警告:其中一个很重要,它会准确地告诉您问题所在

With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;

Procedure sort is
   n,i,x : Integer;


   -- Max_Heapify Function...
   Procedure Max_Heapify ( i, n : integer) is 
      j, Temp : Integer;
   begin
      Temp:=Int_Acc(i);
      j:=2*i;

         if Temp>Int_Acc(j) then


         elsif Temp<=Int_Acc(j) then
            Int_Acc(j/2):=Int_Acc(j);
            j:=2*j;
         end if;
      end loop;
      Int_Acc(j/2):=Temp;
   end Max_Heapify;


begin
   Get(n);
      for i in MyArr'range loop
         Put_Line("Enter Element " & Integer'Image(i));
         Get(MyArr(i));
      end loop;
   end;
end sort;
大多数警告源于以下事实:

for i in My_Arr'range loop
声明其自己的循环变量
i
,该变量隐藏任何现有的范围内声明。因此,您可以通过删除不必要的声明来整理代码

剩下的是:

sort.adb:51:28:警告:循环范围可能为空
排序。adb:51:28:警告:边界可能是错误的

for循环边界为空范围,反向

  • 1。。3
    声明具有3个值的子类型
  • 反向1。。3
    声明相同的子类型并在其上向后迭代
  • 但是
    3。。1
    声明一个空的子类型(不包含有效值),因此对它进行迭代(无论是哪种循环)都不会产生任何效果

希望这是拼图中缺失的部分。我不清楚为什么一个有故障的回路收到此警告,而另一个(在第38行)没有收到此警告。

这不是问题所在,但无论如何,谢谢。Ada是我见过的最迟钝的语言不,你真的希望
然后
指定操作顺序,并避免优化器在检查之前安排(可能超出范围)数组访问。可以说是语言允许这些策略中的一种或另一种,但不能同时允许这两种策略。您的编译器是否不输出实际的错误消息,可能带有堆栈跟踪或(至少)失败行的指示符?编译器显然不会为运行时错误输出任何内容:这很好,但它看不到未来!但是(假设Gnat)使用正确的标志编译,运行时异常将给出一个堆栈跟踪,addr2line可以将其转换为源位置。根据我的经验,非常接近出错的地方…@NMWS你提到的是完全正确的解决方案。但是关于N>20的点。。。我如何解决这个问题,有没有一种方法可以将大小添加到数组中?对于大小正确的N数组,请参阅我答案的第一部分。@BrianDrummond我解决了运行时错误的问题,但似乎还有另一个问题;子程序大多不被称为。。。上述代码已更新。提前感谢:)@BrianDrummond上面的代码是用一个可变大小的数组更新的。但是子程序大部分都没有被调用,这有一个很好但更微妙的原因:for循环的边界是空的,相反的。。。请参见编辑我的答案。完全信息@Brian。你能帮忙吗
for i in My_Arr'range loop