Печать массива целых чисел генерирует странный вывод в Аде - PullRequest
1 голос
/ 03 мая 2020

Я создал простую программу Ada, которая позволяет пользователю заполнять массив максимум 100 неотрицательными и ненулевыми целыми числами, а затем распечатывает их. Когда я вызываю функцию для распечатки чисел, она печатает их, но в то же время она также печатает кучу странных и, казалось бы, случайных чисел. Какую ошибку я допустил в своем коде, который заставляет программу выводить такие странные результаты? Я впервые пишу на Аде. Например, когда я заполняю пустой массив числами [1,2,3,4,5], выводится следующее:

    1
          2
          3
          4
          5
      32624
  911328835
      32624
  911328836
      32624
   67043328
  134217726
  134217726
 2013265921
  134217726
  134217726
  134217726
   67043328
  909181968
      32624
 2114692683
      89452
  914381552
      32624
 1543503876
          2
         14
          2
         14

Я использую компилятор gnatmake в Ubuntu и при компиляции исходного кода это не дает мне никаких сообщений об ошибках / предупреждениях.

Вот мой исходный код, я знаю, что мне, вероятно, не нужно использовать отдельные функции, но я все равно реализовал их в учебных целях.

with Ada.Containers.Vectors;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
use Ada.Containers;


procedure thing is 
type Vector is array (1..100) of Integer;
A: Vector;--array doesn't need to be completely filled up

K: Integer;
--array filling function below
function mkarr return Vector is --asks user to fill empty array with positive and non zero integers

begin

Ada.Text_IO.Put ("enter numbers to fill array, negative or 0 will stop process: ");
for I in 1..100 loop
    Ada.Integer_Text_IO.Get(K);
    if K>0 then
        A(I) := K;
    end if;
    if K<=0 then
        return A;
    end if;

end loop;
return A;
end;




--array printing prodcedure below
procedure printarr(A: in out Vector) is
begin
    for I in A'Range loop
    if A(I)>0 then
        Ada.Integer_Text_IO.Put(A(I));
        New_Line(1);
    end if;
    end loop;
end printarr;



B: Vector := mkarr;


--main method below
begin



printarr(A);
end thing;

Ответы [ 3 ]

6 голосов
/ 03 мая 2020

В mkarr вы используете 0 или отрицательное значение, чтобы отметить конец ввода, но вы не сохраняете это значение в массиве. Если какой-либо мусор, сохраненный в массиве после окончания введенных вами значений, окажется положительным, то невозможно сказать, что это недопустимое значение.

В printarr, если вы встретите 0 или отрицательное значение вы его не печатаете, но продолжаете печатать оставшиеся положительные значения (которые являются мусором).

Если вы сохраняете значение часового в mkarr и выходите из печати в printarr, когда натолкнуться на стража, программа должна работать.

Некоторые другие заметки:

A и K используются только внутри mkarr. Они должны быть локальными для mkarr.

Вы никогда не используете Ada.Containers.Vectors. Вы можете удалить соответствующие директивы with и use.

Для более сложного использования вы можете mkarr вернуть массив, содержащий только введенные данные, сделав Vector необязательным типом массива и возвращая ломтик. Еще проще определить массив фиксированной длины внутри mkarr. Разрешить произвольное количество вводимых данных сложно, но, вероятно, Ada.Containers - хороший способ сделать это. (Отказ от ответственности: я не смотрел на Ada.Containers.)

3 голосов
/ 03 мая 2020

Расширение на Ответ Кита : Вы хотите получить результат переменной длины, поэтому более ада-подобный способ - использовать «неограниченный массив»:

type Vector is array (Positive range <>) of Integer;

Это означает, что Вы можете создавать экземпляры массива любого размера, который вам нравится, при условии, что границы положительные: 1 .. 100, 42 .. 43 и c. Вы даже можете создать массив нулевой длины, указав, что последняя граница (называемая ’Last) будет меньше первой (называемой ’First). В этом особом случае вам разрешается использовать ’Last вне диапазона типа индекса (в данном случае 0 или даже -42, если вы хотите запутать людей!).

function mkarr return Vector is

У нас должен быть фактический массив для накопления значений, поэтому установите верхний предел 100.

   Result : Vector (1 .. 100);

Нам нужно знать, сколько элементов существует.

   Last : Natural := Result'First - 1;

Подробнее или меньше, чем раньше,

   K : Integer;
begin
   Ada.Text_IO.Put
     ("enter numbers to fill array, negative or 0 will stop process: ");
   for I in Result'Range loop

Мы можем вернуть массив максимум с Result’Length элементами.

      Ada.Integer_Text_IO.Get (K);
      if K > 0 then

Мы можем добавить еще один элемент.

         Last := Last + 1;
         Result (Last) := K;
      else

Менее 100 элементов, поэтому верните только этот фрагмент.

         return Result (Result'First .. Last);
      end if;
   end loop;

Мы собрали 100 результатов, поэтому вернем все из них.

   return Result;
end mkarr;
0 голосов
/ 04 мая 2020

Как отмечено здесь , ваш пример упоминает Ada.Containers.Vectors без дальнейшей ссылки на пакет. Если вы стремитесь к такому решению, обсужденному здесь , вы можете сначала создать экземпляр универсального c пакета Vectors, чтобы получить контейнер целых чисел с изменяемым размером:

package Integer_Container is new Vectors (Natural, Integer);

Ваша функция для создания массив может затем объявить Vector с именем A и инициализировать его элементы и длину для указания c значений:

function Make_Array (Size : Count_Type) return Vector is
A : Vector := To_Vector (New_Item => -1, Length => Size);
…

Вы можете использовать Итерация в Ada 2012 для упрощения сбора данных в Make_Array:

for E of A loop
   Get (K);
   if K > 0 then
      E := K;
   else
      exit;
   end if;
end loop;

Аналогично, procedure Print_Array (A : in Vector) может l oop следующим образом:

for E of A loop
   Put (E, 4);
end loop;

Типичное использование может выглядит примерно так:

Print_Array (Make_Array (42));

Дополнительные сведения можно найти здесь и здесь .

...