На мой взгляд, динамические массивы многократно проще статических, незачем вообще про них упоминать. Впрочем, их удаление из языка я, разумеется, не поддерживаю.
Жаль, что Вы не раскрыли это Ваше “многократно проще” - почему-то у меня есть стойкое ощущение того, что далеко не многократно и не особо проще. В чем-то да, проще, но в чем-то и сложнее. Прежде всего, напомню, что речь шла об аудитории, которой адресован 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, как сейчас нужно работать с двоичными файлами: что там с сериализацией динамических массивов? Как сохранить в файл запись со строками произвольной длины и динамическими массивами внутри?
Вот Вам “кажется…”, а я ежедневно в качестве модератора информатики на сервисе “Школьные знания” общаюсь не с одним десятком школьников различных возрастов и вживую вижу те проблемы, о которых пишу.
Вот когда Вы издадите свои учебники по информатике, где все будет базироваться на динамических массивах, и когда их повсеместно признают, тогда можно будет говорить об отказе от “анахронизма”. А сейчас для обучения гораздо востребованее не “динамические массивы” с какой-то особой структурой, а массивы с динамически изменяемой верхней границей. Как в Бейсике. Там не делят массивы на статические, динамические… Если надо границы поменять, выдал в нужном месте 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.
Мы будем использовать в срезах синтаксис 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”. Вообще, весь мир - динамический. И - открою страшную тайну - у нас и статические массивы на самом деле динамические, просто они косят под статические
Именно так. Их же не раздражает, что в ячейках компьютера хранятся нолики и единички.
Как Вы молодого человека убедите - так он и будет сразу считать правильным.
Вспомните - в Путешествии Гулливера были остроконечники и тупоконечники.
Мы поступаем по-другому как видите. Везде на сайте PascalABC.NET будут культивироваться только динамические массивы как правильный код.
В частности, скоро конструкция
for i:=1 to n do
будет вызывать навязчивое предупреждение с просьбой описать переменную в заголовке цикла, а еще через годик - ошибку компиляции. Флаг программирования в старом стиле, конечно, оставим.
Всё зависит от примеров. Недавно в сбербанке я был первым в очереди с номером номерка 973.
Правильные примеры, сказанные уверенно и без издёвки, позволят школьнику легко запомнить индексацию с нуля. Вопрос - в целях.
Нет, нет - тут Вы не правы. C++ нельзя. И - это обычные дети. Ничего необычного в них нет. Просто они хотят знакомиться с современными компьютерными технологиями. C++ нельзя - еще раз. Совсем маленьким можно Scratch - в курсе пользователя.
Ну - как хотите - это ваша привычка - не более. Если бы Вы сразу написали на динамических массивах - то при переходе на статические Вы бы ругались.
Должен заметить, что при обращении матрицы методом гаусса-Жордана Вы задаёте предельный размер матрицы - скажем, 100 на 100 - и постоянно думаете о двух проблемах: память расходуется неэффективно и не понадобится ли мне в будущем матрица размера 101.
Тогда уж так:
const n=15;
type Arr=array[1..n] of integer;
procedure Print(a:Arr);
А никакого “огромного количества” нет. Все это количество - заслуга LINQ, который немедленно массив превращает в последовательность и снова сделать её массивом помогает волшебное слово ToArray. Но если у нас есть возможность преобразования статического массива в динамический посредством этого же волшебного слова, разница нивелируется.
Еще раз - я “всеми лапками” за динамические массивы. Однозначно, будущее программирования за ними. Поэтому на том ресурсе, о котором я упомянул (не хочу повторяться, чтобы не выглядело рекламой), если я выкладываю решение, я пишу его на последней версии PascalABC.NET и практически всегда на динамических массивах+LINQ. Пусть привыкают и видят, как это коротко и красиво. Но пока наши учебные программы для начинающих к этому не готовы, нам нужны и статические массивы. И не на правах бедных родственников. Жаль, что они не аналоги математических векторов, матриц и т.д. но раз так - значит так. Хотя, конечно, MatrixRandom(), который создает отнюдь не матрицу в обычном её понимании - семантически не самое удачное имя.
А я заметил. Программа со статическими массивами работает дольше. Но это уже особенность реализации.
Возможно, Вы не обратили внимания, что было написано: алгоритм ПЕРЕВОДИЛСЯ с Алгол-60. В те времена еще не было массовых привычек индексировать от нуля. Поэтому небольшие проблемы были именно с переходом на такую индексацию. Что до размера - для этого в Паскале давно уже научились объявлять его в const и там менять, если надо.
Кстати, заодно. Может, это я такой невезучий, но на двухмерных массивах Swap(a[i,j],a[j,i]) существенно проигрывает прямому обмену через промежуточную переменную. Проверьте, если время будет.
Да-да, конечно строка динамическая. И как “дань предкам”, обращение s[0] ведет к ошибке, потому что в динамической строке элементы нумеруются … от единицы. Подгадили предки, которые раньше в s[0] длину строки хранили…
Проверил на таком алгоритме.
procedure Transpose(a: array [,] of real);
begin
var m := a.GetLength(0);
for var i:=0 to m-1 do
for var j:=0 to i-1 do
begin
var t := a[i,j];
a[i,j] := a[j,i];
a[j,i] := t;
end;
//Swap(a[i,j],a[j,i]);
end;
begin
var a := MatrixRandomReal(10000,10000);
Transpose(a);
Print(Milliseconds);
end.
Не проигрывает. Приведите свой.