OberonCore
https://forum.oberoncore.ru/

Динамический массив. Алгоритм ввода числ.последовательности
https://forum.oberoncore.ru/viewtopic.php?f=35&t=513
Страница 1 из 3

Автор:  Никита [ Вторник, 12 Июнь, 2007 13:15 ]
Заголовок сообщения:  Динамический массив. Алгоритм ввода числ.последовательности

Добрый день... У меня возникла проблема с массивом, нужна программа на BB, которая создаёт динамический массив, даёт возможность пользователю заполнить значения (буквы, цифры - что угодно), а после подсчитывает колличество одинаковых элементов в массиве и выводит пользователю. Если вас не затруднит помогите кто чем сможет. Заранее спасибо!

Автор:  Илья Ермаков [ Вторник, 12 Июнь, 2007 13:54 ]
Заголовок сообщения: 

1) Динамический массив.
Объявляется так:
VAR a: POINTER TO ARRAY OF INTEGER;
Создается на заданное количество элементов так:
NEW(a, 150).
LEN(a) возвращает длину массива, а LEN(a)-1 соответственно номер его последнего элемента. Циклы надо писать с использованием "до LEN-1", это грамотно.
Удалять массив не надо, в ББ сборщик мусора, который сам его уничтожит потом.
2) Ввод данных.
А как Вы хотите получать данные от пользователя? Для учебных и "числомолотильных" задачек обычно используется модуль In (посмотрите его документацию). Он считывает данные из выделенного в момент запуска вашей программы куска текста.
Пример ввода:
Код:
VAR a: POINTER TO ARRAY OF INTEGER;
      i, n: INTEGER;
BEGIN
  n := 0;
  In.Open;
  (* Считаем количество элементов в выделенном фрагменте *)
  In.Int(i);
  WHILE In.Done DO (* Пока считывается успешно *)
    INC(n);   
    In.Int(x)
  END;
  (* создаем массив на посчитанное количество элементов *)
  NEW(a, n);
  (* Повторно считываем фрагмент - теперь уже запоминая в массиве *)
  In.Open;
  FOR i := 0 TO LEN(a)-1 DO
    In.Int(a[i])
  END

Автор:  Pavel [ Среда, 13 Июнь, 2007 08:15 ]
Заголовок сообщения: 

Возможно, допущена опечатка:
In.Int(x);

Необходимо
In.Int(i);

Автор:  Илья Ермаков [ Среда, 13 Июнь, 2007 09:34 ]
Заголовок сообщения: 

Да, конечно же.

Автор:  Никита [ Среда, 13 Июнь, 2007 09:44 ]
Заголовок сообщения: 

Данные от пользователя я хочу просто ввести в текстовом окне... по типу 2 ok.. 56 ok.. 34 ok и т.д.

Автор:  Никита [ Среда, 13 Июнь, 2007 09:47 ]
Заголовок сообщения: 

Огромное Вам спасибо, вы мне очень сильно помогли.

Автор:  Илья Ермаков [ Среда, 13 Июнь, 2007 10:19 ]
Заголовок сообщения: 

Никита писал(а):
Данные от пользователя я хочу просто ввести в текстовом окне... по типу 2 ok.. 56 ok.. 34 ok и т.д.

Тогда читайте хелп ББ (надеюсь, Вы русскую версию скачали?) - учебник "Компоненты ББ шаг за шагом" (средняя часть в окне хелпа), главу 4 "Формы".

Автор:  Евгений Темиргалеев [ Среда, 13 Июнь, 2007 18:25 ]
Заголовок сообщения: 

Желательно добавить проверку на то, что поток открылся. Для большей ясности.
Код:
...
BEGIN
   n := 0;
   In.Open;
   IF In.Done THEN
   (* Считаем количество элементов в выделенном фрагменте *)
   ...
   END

Автор:  Илья Ермаков [ Среда, 13 Июнь, 2007 22:59 ]
Заголовок сообщения: 

Поток может и открыться, но в нем не быть чисел...

Лучше уж после
Код:
  In.Int(i);
  WHILE In.Done DO (* Пока считывается успешно *)
    INC(n);   
    In.Int(x)
  END;

добавить:
ASSERT(n > 0, 20) - предусловие на то, что вводится хотя бы одно число.

Автор:  Pavel [ Четверг, 14 Июнь, 2007 08:27 ]
Заголовок сообщения: 

А вот так:
Код:
In.Open;
  (* Считаем количество элементов в выделенном фрагменте *)
   n := -1;
   REPEAT
      In.Int(i);  INC(n);
   UNTIL ~In.Done  ;
  (* создаем массив на посчитанное количество элементов *)
  IF  n>0  THEN NEW(a, n);
  (* Повторно считываем фрагмент - теперь уже запоминая в массиве *)
  In.Open;
  FOR i := 0 TO LEN(a)-1 DO In.Int(a[i]); END;
      ELSE   StdLog.String("Данные где?")
END;

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 10:27 ]
Заголовок сообщения: 

Pavel писал(а):
А вот так:
Код:
REPEAT
   In.Int(i);  INC(n);
UNTIL ~In.Done  ;

Цикл построен неверно. n будет на единицу больше, чем чисел.
Между выполнением In.Int(i) и INC(n) должна быть проверка условия In.Done, что и обеспечивал WHILE с вынесенным действием.
Схема чтения из потока:
Код:
Берем_след_элемент;
WHILE Взят_успешно() DO
   Используем элемент - например, считаем
   Берем_след_элемент
END;

Это цикл с вынесенным действием, т.к. чтений выполняется на одно больше, чем выполнений тела цикла с полезным действием - чтобы понять, что поток закончился, нужно попробовать прочитать.

WHILE с вынесенным действием можно реализовать и через UNTIL, но не так, как Вы написали, а вот так:
Код:
REPEAT
  Берем_след_элемент;
  IF Взят_успешно() THEN
      Используем_элемент
  END
UNTIL ~ Взят_успешно();

Здесь тело цикла выполняется на один раз больше, чем у предыдущего WHILE. Но чтобы полезное действие не выполнялось лишний раз на последнем "холостом" витке, нужно поставить IF.
В данном случае WHILE короче и удобнее. Однако бывают ситуации, код код взятия следующего элемента весьма громоздок, и удобнее поставить лишний IF, чем дублировать код перед циклом.

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 10:30 ]
Заголовок сообщения: 

А, пардон, Вы перед циклом сделали n := -1. Можно, но не красиво - шаманство. n - количество элементов, и инвариант на него - n >= 0 по определению. К тому же, если бы мы выполняли не подсчет, а какое-то другое более сложное действие с данными из потока, то такой номер бы не прошел.

Автор:  PGR [ Четверг, 14 Июнь, 2007 11:11 ]
Заголовок сообщения: 

Без повторения кода и без лишних вызовов функции. Да и понять проще...
Код:
LOOP
  Берем_след_элемент;
  IF ~Взят_успешно() THEN EXIT END;
  Используем элемент;
END;

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 11:18 ]
Заголовок сообщения: 

Ни в коем случае! Вот, елки-палки, даже в КП люди GOTO себе найдут... :-)
Без лишних вызовов функций и легко понимабельный - первый вариант с WHILE. Это типовая схема, которая используется всегда. Практически. Иногда - альтернативный вариант REPEAT.

LOOP-END - это не цикл для повседневного использования. Его ввели в КП как в промышленном языке для некоторых навороченных кусков вроде циклов обработки сообщений и т.п. Не более.

Почему "нельзя"? Потому что вариант с WHILE - это частный случай универсальной базовой схемы "полный проход по последовательности" которая просто формально приспосабливается к текущей ситуации Ее надо знать - и наоборот, уметь узнавать в чужом коде как единое целое. Тогда не будет казаться, что "склепанное на коленках" частное решение с GOTO "понять проще".

Автор:  PGR [ Четверг, 14 Июнь, 2007 11:43 ]
Заголовок сообщения: 

Почему GOTO? У этого цикла LOOP одна точка входа и одна точка выхода.

Автор:  Pavel [ Четверг, 14 Июнь, 2007 11:47 ]
Заголовок сообщения: 

Илья Ермаков писал(а):
Вы перед циклом сделали n := -1. Можно, но не красиво - шаманство.

Все программирование ШАМАНСТВО. :wink:
n- в данном варианте это количество элементов, если оно получилось равно нулю, то элементов нет.

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 11:52 ]
Заголовок сообщения: 

PGR писал(а):
Почему GOTO? У цикла LOOP одна точка входа и одна точка выхода.

Ну, в данном случае да. Но вообще цикл LOOP позволяет делать сколько угодно точек выхода. Не стоит его использовать. Если конструкция позволяет делать много выходов, то тут же начнут делать - просто в силу правила "насыщения степеней свободы инструмента".

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 11:56 ]
Заголовок сообщения: 

Цитата:
Все программирование ШАМАНСТВО. :wink:
n- в данном варианте это количество элементов, если оно получилось равно нулю, то элементов нет.

См. выше - ну зачем строить неверные циклы, затем изобретать велосипеды для их объезда, а потом еще искать теоретическое обоснование? :-)
Есть понятие инварианта - условия, которое должно соблюдаться на протяжении выполнения некоторого блока - в его начале, в середине и в конце. Если n - число элементов, то при грамотном построении алгоритма на всем его протяжении должен выполняться инвариант n >= 0. Если же инвариант приходится нарушать (n := -1), то это признак неграмотно построенного алгоритма...

Автор:  Vlad [ Четверг, 14 Июнь, 2007 12:00 ]
Заголовок сообщения: 

PGR писал(а):
Почему GOTO? У этого цикла LOOP одна точка входа и одна точка выхода.


Сейчас тебя пошлют читать Дейкстру :) Забей. Типичный случай, когда break (в твоем случае EXIT) удобнее/нагляденее/эффективнее.

Автор:  Илья Ермаков [ Четверг, 14 Июнь, 2007 12:01 ]
Заголовок сообщения: 

Вообще, полезно почитать книжку Бейбера "Программное обеспечение без ошибок".
viewtopic.php?t=411

Страница 1 из 3 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/