О статических и динамических массивах

А для чего нужны эти статические массивы? Они все равно на стеке не размещаются. Статические массивы - это лишние накладные расходы и ненужное выделение памяти при каждом объявлении.

Да действительно, давайте их уничтожим, как класс? Зачем новорожденных выкармливать грудным молоком, пусть едят прожаренную свиную вырезку! А ничего, что в начале обучения дается понятие статического массива, а потом уже происходит разговор о динамических структурах?

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

Жаль, что Вы не раскрыли это Ваше “многократно проще” - почему-то у меня есть стойкое ощущение того, что далеко не многократно и не особо проще. В чем-то да, проще, но в чем-то и сложнее. Прежде всего, напомню, что речь шла об аудитории, которой адресован PascalABC.Net. Основная направленность, насколько я понял - все же сфера образования. Включающая, конечно же, общеобразовательные школы. Так уж сложилось, что чаще всего у школьника первым алгоритмическим языком оказывается именно Паскаль. И изучают его не справочной системе системы программирования, а по учебнику. А там первая информационная структура, с которой школьник сталкивается - массив. В его простейшем, статическом понимании. “Заведем десять ячеек. Первое число мы поместим в первую ячейку, второе - во вторую, … и так поступи со всеми десятью числами”. В первое время, пусть с трудом, но доходит. А теперь представьте себе, что речь о динамическом массиве. “Заведем десять ячеек. В НУЛЕВУЮ (?) поместим первое число, в ПЕРВУЮ - второе,… а последнее, десятое число поместим в ДЕВЯТУЮ ячейку”. Мало того, что ввели новое понятие, так еще и нумерацию сдвинули. “- Мариванна, у меня на руке пять пальцев, мне что, надо на уроке информатики теперь мизинец четвертым называть?”.

Задача. В массиве удвоить значение элемента, если его порядковый номер четный и утроить в противном случае. Как понятнее школьнику, если по оператору попытаться восстановить исходное задание?

if Odd(i) then a[i]*=3 else a[i]*=2; // статический [1..n]
или
if Odd(i) then a[i]*=2 else a[i]*=3; // динамический [n]

Хочу быть правильно понятым: динамические массивы - прекрасная вещь! Но во всех языках они несут на себе отпечаток адресации областей памяти и поэтому индексируются от нуля. Статический массив имеет граничные пары, что в необходимых случаях дает возможность добиться от алгоритма большей прозрачности. Простая задача: по заданному номеру месяца вывести его название. В статический массив заносим 12 наименований и a[n] дает искомое. В динамическом - либо результат достигается через a[n-1], вызывая определенное недоумение у начинающего, либо надо определять 13 элементов и “самый первый” - тот, что перед первым (!) стоит, не учитывать. Прошу не считать это сообщение прологом к холивару про индексацию от 0 и от 1.

Ну, вы пишете именно про индексацию. Ясно, что если для введения динамических массивов пользоваться старыми учебниками, формулировки задач в которых ориентированы на статические массивы и индексацию с единицы, то ничего хорошего не выйдет. Мне кажется, что принцип считающего с нуля компьютера воспринимается школьниками достаточно быстро, особенно их не путать «особыми» массивами, индексируемыми с единицы.

У статических массивов есть одно полезное применение — численные расчёты с векторами и матрицами, размеры которых фиксированы, а как структуры данных они очень плохи. Мы фактически сразу вынуждены задавать максимально возможный размер и вводить фактическую заполненность, иначе остаётся решать задачи как в ваших примерах про 10 ячеек или 12 месяцев, плодя по всему коду «магические» константы.

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

При вводе динамических массивов нужно отказываться от понятия порядкового номера, достаточно ограничиться термином «индекс», объяснив при желании, что это на самом деле смещение от начала.

Кстати, я не слышал от @Admin, как сейчас нужно работать с двоичными файлами: что там с сериализацией динамических массивов? Как сохранить в файл запись со строками произвольной длины и динамическими массивами внутри?

1 лайк

Вот Вам “кажется…”, а я ежедневно в качестве модератора информатики на сервисе “Школьные знания” общаюсь не с одним десятком школьников различных возрастов и вживую вижу те проблемы, о которых пишу.

Вот когда Вы издадите свои учебники по информатике, где все будет базироваться на динамических массивах, и когда их повсеместно признают, тогда можно будет говорить об отказе от “анахронизма”. А сейчас для обучения гораздо востребованее не “динамические массивы” с какой-то особой структурой, а массивы с динамически изменяемой верхней границей. Как в Бейсике. Там не делят массивы на статические, динамические… Если надо границы поменять, выдал в нужном месте ReDim [Preserve] и живешь спокойно дальше. Похожее есть и Pascal: SetLength(), только без опции, позволяющей определить, зачищать ли содержимое массива с изменившимися границами.

Не согласен. Вы сами писали о векторах, матрицах - целом разделе математики. И что, говоря о трехмерном пространстве, мы должны считать что координата Х отображается в нулевом индексе? Есть индекс и есть порядковый номер. “- Алло, девушка, почему мне до сих пор не предоставили справку, Вы же сказали. что я первый на очереди? - Да, но Вы забыли, что перед Вами еще нулевой?” И не надо пытаться заставить человечество считать все от нуля лишь потому, что так было удобно когда-то индексировать области памяти в ассемблере.

@RAlex вы зря тут меряетесь количеством школьников: у @bravit достаточно школьников, чтобы судить (да и у меня тоже). Если вы видите проблемы, то это, как справедливо сказал @bravit, проблемы подходов в обучении, методического обеспечения и так далее, но не проблемы динамических массивов. При должном подходе всё получается вполне доступно и даже лучше, чем с громоздким синтаксисом статических. Таков наш опыт в Воскресной компьютерной школе.

По поводу нужности. Не знаю, как в ПаскалеАБЦ, а в жизни статические массивы нужны. Традиционно у них есть свои экологические ниши: численные рассчёты, а также низкоуровневое программирование аля C (буфера). Разницу нужно понимать, но — не школьнику, а хотя бы студенту (или 11-класснику). А школьнику 7-8 классов (когда мы вводим массивы) нужно предоставить простейший из возможных синтаксисов и всё. Без философии, без низкоуровневой организации и т. п.

Сложно запомнить об индексации с 0? Смешно об этом говорить, они столько нового на занятиях узнают, это всего лишь одна мало значащая деталь.

PS Тему надо отделять, на мой взгляд.

Только Вы забываете о разнице в контингенте. Те, кто в идут в воскресную компьютерную школу - люди, которые планируют свою жизнь так или иначе связать с компьютерной техникой. Им можно и С++ без проблем преподавать. Но большая часть детей вовсе не видит себя в будущем программистами и им эти компьютерные абстракции нужны в крайне ограниченных и понятных каждому конструкциях. Так сказать, на макроуровне.

А приведите пример, пожалуйста, этого нехорошего “громоздкого синтаксиса статических массивов”. Вот я вчера попробовал переработать с Алгол-60 некогда известный алгоритм 120б “Обращение матрицы методом Гаусса-Жордана”. На статических массивах сразу написал и заработало. А для перехода к динамическим массивам пришлось немного потрудиться, потому что надо было переводить все на индексирование с нуля. Программа, естественно, не стала ни короче (в байтах исходник даже длиннее из-за постоянных n-1), ни понятнее.

P.S. И не надо этого цехового “меряетесь количеством школьников…”. Я не о количестве говорю, а скорее, о качественной разнице.

И - да, тему надо отделять. Или просто почистить)))

Тогда уж так

var b := a.ToArray;

Intellisense надо поправить

В двоичных файлах типа file или file of что-то сохранить объекты со ссылочной семантикой не получится.

Для этого надо использовать более мощную .NET-сериализацию:

uses System;
uses System.IO;
uses System.Runtime.Serialization.Formatters.Binary;

type 
  [Serializable]
  RC = record
    s: string := 'ABC';
    a := Arr(1,2,3);
  end;

begin
  var formatter := new BinaryFormatter();
  var fs := new FileStream('d:\aa.dat', FileMode.OpenOrCreate);
  var r: RC; 
  formatter.Serialize(fs, r);
  fs.Close;
  r.s := 'XYZ';
  r.a := Arr(666,666,666);
  fs := new FileStream('d:\aa.dat', FileMode.OpenOrCreate);
  r := RC(formatter.DeSerialize(fs));
  fs.Close;
  Println(r);
end.
2 лайка

Мы будем использовать в срезах синтаксис a[2:10:2]. Не советуйте нам пожалуйста синтаксические конструкции, которыми вряд ли кто-то будет пользоваться

А вот это отличные новости! Чувствуется, что система программирования, как раньше говорили, идет “верной дорогой” )))

Да я только “за”! Если победите Write(a[3:12:4][2:10:2]:6:3), будет замечательно.

Проще. Это Вы привыкли просто. Ребенку, которому рассказывают это впервые, особой разницы нет.

Но - Вы правы - старых учебников много, и там везде с единицы. Мы и не запрещаем старые массивы. Но Вы получаете вместе с ними тяжелое наследство: память выделяется жестко в процессе компиляции и чтобы их передавать - нужна именная эквивалентность:

type Arr = array [1..10000] of integer; // на всякий случай 10000
procedure Print(const a: Arr; n,m: integer)

и

procedure Print(a: array of integer)

Я уж не говорю, что мы лишаемся огромного количества стандартных методов работы с массивами.

Поэтому проще в дальнейшем - для решения более высокоуровневых задач. А так - побаловаться с индексами в короткой программе на 5-10 строк - да, не проще.

Это вопрос, в начале чьего обучения.

Динамические структуры - давайте не смешивать с динамическими массивами. Динамические структуры - это структуры, меняющие свою структуру (связи между элементами) во время выполнения программыю

Не забывайте также, что у нас и строка string - динамическая. Собственно, она и во Free Pascal динамическая если Вы специально не ставите опцию “программировать в стиле устаревшего Turbo Pascal”. Вообще, весь мир - динамический. И - открою страшную тайну - у нас и статические массивы на самом деле динамические, просто они косят под статические :slight_smile:

Именно так. Их же не раздражает, что в ячейках компьютера хранятся нолики и единички.

Как Вы молодого человека убедите - так он и будет сразу считать правильным.

Вспомните - в Путешествии Гулливера были остроконечники и тупоконечники.

Мы поступаем по-другому как видите. Везде на сайте PascalABC.NET будут культивироваться только динамические массивы как правильный код.

В частности, скоро конструкция

for i:=1 to n do

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

1 лайк

Всё зависит от примеров. Недавно в сбербанке я был первым в очереди с номером номерка 973.

Правильные примеры, сказанные уверенно и без издёвки, позволят школьнику легко запомнить индексацию с нуля. Вопрос - в целях.

Нет, нет - тут Вы не правы. C++ нельзя. И - это обычные дети. Ничего необычного в них нет. Просто они хотят знакомиться с современными компьютерными технологиями. C++ нельзя - еще раз. Совсем маленьким можно Scratch - в курсе пользователя.

1 лайк

Ну - как хотите - это ваша привычка - не более. Если бы Вы сразу написали на динамических массивах - то при переходе на статические Вы бы ругались.

Должен заметить, что при обращении матрицы методом гаусса-Жордана Вы задаёте предельный размер матрицы - скажем, 100 на 100 - и постоянно думаете о двух проблемах: память расходуется неэффективно и не понадобится ли мне в будущем матрица размера 101.

1 лайк

Тогда уж так:

const n=15;
type Arr=array[1..n] of integer;
procedure Print(a:Arr);

А никакого “огромного количества” нет. Все это количество - заслуга LINQ, который немедленно массив превращает в последовательность и снова сделать её массивом помогает волшебное слово ToArray. Но если у нас есть возможность преобразования статического массива в динамический посредством этого же волшебного слова, разница нивелируется.

Еще раз - я “всеми лапками” за динамические массивы. Однозначно, будущее программирования за ними. Поэтому на том ресурсе, о котором я упомянул (не хочу повторяться, чтобы не выглядело рекламой), если я выкладываю решение, я пишу его на последней версии PascalABC.NET и практически всегда на динамических массивах+LINQ. Пусть привыкают и видят, как это коротко и красиво. Но пока наши учебные программы для начинающих к этому не готовы, нам нужны и статические массивы. И не на правах бедных родственников. Жаль, что они не аналоги математических векторов, матриц и т.д. но раз так - значит так. Хотя, конечно, MatrixRandom(), который создает отнюдь не матрицу в обычном её понимании - семантически не самое удачное имя.