Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ОПРОГ-А

.pdf
Скачиваний:
37
Добавлен:
10.02.2015
Размер:
1.48 Mб
Скачать

Оперативная память – это основной вид ОЗУ в компьютере. В ней временно хранятся данные и команды, необходимые программам, запущенным на компьютере, а также процессору, для выполнения предписанных операций. Основное требование к оперативной памяти – достаточно высокое быстродействие и большой объем хранимой информации. Содержащиеся в оперативной памяти данные доступны только тогда, когда на модули памяти подаётся напряжение. Прекращение подачи питания на модули памяти, даже кратковременное, приводит к искажению либо полной потере содержимого памяти.

Основным видом ПЗУ является, конечно же, магнитный диск. На основе этой технологии долгое время строились такие носители информации как дискеты, жесткие диски и т.д. Более современными носителями информации являются оптические диски, а также флэш-память. Все эти виды носителей информации позволяют хранить данные, даже когда питание от них отключено.

6. Разработка программного обеспечения

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

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

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

Вне зависимости от целей и назначения программирования, разработка программного обеспечения, по большому счету, идет всегда в соответствии с некими общими правилами и этапами создания программ. Формально об этом нам могут рассказать этапы разработки и версии ПО. Начнем с описания числового формата версии программы. На самом деле для отслеживания изменений в программах и сообщении пользователям о том, с какой программой они сейчас работают (более новой, или уже устаревшей, например) было создано большое количество схем присвоения номеров версиям программного обеспечения. Версии пробовали нумеровать целыми числами, что оказалось неудобно из-за невозможности разделить важные и не очень важные изменения. Иногда используют буквенные обозначения, текущие даты, Дональд Кнут нумерует версии системы компьютерной вёрстки ΤΕΧ последовательными приближениями числа , но это уже, конечно, экзотика. Наиболее распространенный и современный способ нумерации – это использова-

21

ние специального формата, в котором легко отражаются все изменения в программе, как важные и заметные пользователю, так и «внутренние» – интересные больше программистам:

1.2.3.4

В этом обозначении у каждого из четырех чисел есть свой смысл, определяющий значимость перемен между стадиями разработки ПО. В данном случае приняты такие правила: первое число (обозначенное цифрой 1) может быть изменено только тогда, когда код программы практически полностью изменен, когда программа претерпела существенные изменения, заметные пользователю. Мы можем назвать это число основной официальной версией продукта. Второе число (обозначенное цифрой 2) обычно используется для указания на текущие обновления программы, заметные и важные, но не приводящие к кардинальному изменению программной оболочки. Мы можем назвать это число промежуточной официальной версией продукта. Третье число (обозначенное цифрой 3) изменяется обычно незаметно для пользователя и связано с внутренними изменениями в программе. Иногда такие изменения довольно важны для программистов, но могут не иметь никакого значения с точки зрения пользователей. Мы можем назвать это число внутренней версией продукта. Наименее значимым для пользователя является четвертое число (обозначенное цифрой 4), оно изменяется при незначительных переменах в интерфейсе программы, внешних ресурсах, документации. Очень часто четвертое число отражает дату последнего обновления программы или изменения дополнительных модулей (как, например, обновление антивирусных баз). Как правило, его называют номером сборки или билдом (от английского обозначения build). Такой подход позволяет пользователям (и даже потенциальным последователям создателей программы), оценить, насколько было протестировано в реальных условиях данное программное обеспечение, насколько современной является используемая версия. Зачастую при изменении версий ПО возникают конфликты, связанные с тем, что существенные изменения программ разработчики уже могут снова продавать, а менее важные – должны предоставлять бесплатно. Иногда желание заработать денег перевешивает ответственность перед пользователями и в создании номеров версий приводит к намеренным ошибкам в изменении версий. Например, разработчики могут изменить номер версии, даже если ни одна строчка кода не была переписана, лишь для того чтобы создать ложное впечатление, что были внесены значительные изменения в код программы. Или просто перерисовать иконки в интерфейсе ПО и сказать, что это отражает существенное изменение функционала программы. Доказать их неправоты в этих случаях очень сложно.

Типичная нумерация в данной схеме может выглядеть так (опуская непринципиальное четвертое число): 0.9, 0.9.1, 0.9.2, 0.9.3 – для начала работы над программой; 1.0, 1.0.1, 1.0.2, 1.1, 1.1.1 – для эволюций первой версии; 2.0, 2.0.1, 2.0.2, 2.1, 2.1.1, 2.1.2, 2.2 – для второй и т. д. Разработчики порой перескакивают от версии 5.0 сразу к 5.5, для того чтобы обозначить добавление нескольких значимых функций в программе, однако их недостаточно, чтобы изменить главный номер версии. Не все согласны с такой практикой и подобные скачки используются редко.

22

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

Другой подход использования главных и второстепенных номеров версий заключается в добавлении буквенно-цифровой последовательности, определяя тем самым стадию разработки релиза: «альфа», «бета», «релиз-кандидат». На самом деле эти обозначения позволяют не только увидеть, с какой версией идет работа, но и понять, на какой стадии находится разработка программы. В разработке программного обеспечения стадии разработки программного обеспечения используются для описания степени готовности программного продукта и могут применяться для любых версий создаваемого ПО, но наиболее важны в момент, когда выпускается первая версия программы. Стадия разработки может отражать количество реализованных функций, запланированных для определённой версии программы, степень их готовности, уровень доступности программы пользователю (бесплатная пробная версия или готовое платное ПО). Стадии либо могут быть официально объявлены и регламентируются разработчиками, либо иногда этот термин используется неофициально для описания состояния продукта. В любом случае, использование специальных обозначений в номере версии, как правило, требует написания соответствующего лицензионного соглашения. Этапы разработки присваиваются любому создаваемому программному обеспечению, как правило, в виде следующих названий:

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

2.Альфа версия. Внутреннее тестирование – стадия начала тестирования программы в целом специалистами-тестерами, обычно не разработчиками программного продукта, но, как правило, внутри организации, разрабатывающей продукт. На этой стадии могут добавляться новые функциональные возможности. Программы, находящиеся на первых двух стадиях разработки, могут применяться только для ознакомления с будущими возможностями и не становятся доступны пользователям.

3.Бета версия. Публичное тестирование – стадия активного тестирования и отладки программы, прошедшей первые этапы, если они были. Программы этого уровня могут быть использованы другими разработчиками программного обеспечения для испытания совместимости. Их

23

могут начинать демонстрировать пользователям, зачастую набирая добровольных тестировщиков среди них (как часто бывает с компьютерными играми). Программы на этом этапе разработки по-прежнему могут содержать достаточно большое количество ошибок. Бета-версия ПО не является финальной версией, и публичное тестирование производится на страх и риск пользователя, разработчик не несёт никакой ответственности за ущерб, причинённый в результате использования бета-версии. Этим часто пользуются создатели программ, предоставляя пользователям только бета-версии продукта. Например, разработчики ICQ в 2003-м году использовали это, выпустив бета-версию программы. Финальной версии ICQ 2003 так и не появилось, вместо этого два года спустя вышли версии ICQ 4 и ICQ 5. Многими сообществами признано, что 2003 версия продукта была самой «глючной» и с самым большим содержанием рекламы за всю историю этого мессенджера.

4.Релиз-кандидат или rc (от англ. release candidate) – стадия-кандидат на то, чтобы стать итоговой. Программы этой стадии прошли комплексное тестирование, благодаря чему были исправлены все найденные критические ошибки, тем не менее, некоторые ошибки могут быть выявлены на этом этапе. Как правило, релиз-кандидаты используются для презентации новых продуктов и часто создаются исключительно для маркетинговых целей.

5.Релиз или RTM (от англ. release to manufacturing промышленное издание) – издание продукта, готового к тиражированию и продаже. Это стабильная версия программы, как правило, не содержащая ошибок, прошедшая все предыдущие стадии.

Следует отметить, что стадии Бета и Альфа, выносимые иногда «на суд общественности», не являются показателями нестабильности данной версии программы, т.к. присваиваются программе один раз или один раз за серию (изменения в первом числе в номере версии), они могут присваиваться нескольким релизам подряд. Важной характеристикой использования таких схем обозначения версий и этапов является соблюдение идентичности стадий разработки версий. Например, нельзя вносить никаких изменений между последней бета-версией и первым релизкандидатом или последним релиз-кандидатом и готовым продуктом. Если это сделано, необходимо выпустить другую версию на более низкой стадии разработки, чтобы не прерывать нумерацию вносимых изменений в программу. В случае если в процессе использования программы пользователями в ней обнаруживаются новые ошибки, то их также устраняют, выпуская заплатки или патчи. Наряду с обновлениями программы они тоже вносят изменения в версию продукта.

Теперь можно сформулировать некоторые правила и законы проектирования программного обеспечения. Проектирование ПО – это целая наука и, конечно, все рассказать в рамках короткого курса невозможно, но некоторые интересные факты мы обсудим. Проектированию подлежат все три составных части программы – интерфейс, функциональная часть и архитектура. Причем в каждой области, проекти-

24

рование – серьезная и сложная задача, требующая разработки специалистами в данной области, также проектирование – неотъемлемая часть программирования. Существуют разные подходы к проектированию ПО, как «ручные» так и автоматизированные. Если проект несложный, то его можно спроектировать просто «на бумаге», набросав план дальнейших действий и разрабатывая программу в соответствии с ним. Но если создаваемая программа сложна и состоит из большого числа компонентов, то в этом случае часто прибегают к помощи вспомогательных программ. Одним из наиболее известных производителей такого специализированного ПО является компания IBM Rational Software. Этой компанией были разработаны различные средства автоматизации проектирования программных продуктов и баз данных, в том числе RUP (Rational Unified Process). В основе Rational Unified Process лежат следующие принципы:

раннее обнаружение и непрерывное (до окончания проекта) устранение основных рисков, связанных с разработкой ПО;

концентрация на выполнении требований технического задания;

ожидание изменений в требованиях, проектных решениях и реализации в процессе разработки;

компонентная архитектура ПО, реализуемая и тестируемая на ранних стадиях проекта;

постоянное обеспечение качества на всех этапах разработки проекта;

работа над проектом в команде, в которой ключевая роль принадлежит проектировщикам.

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

7. Языки программирования

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

Одно из таких разделений – на низкоуровневые и высокоуровневые языки программирования. Низкоуровневый язык программирования – это такой язык про-

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

25

в последнее время макросами), а также возможность использования специальных команд или инструкций. При помощи инструкций в таких языках появляется возможность управлять процессом трансляции машинных кодов, создавая более осмысленные тексты программ, понятные не только знакомым с процессорными командами специалистам, но и программистам более широкого круга. Часто эти языки позволяют работать вместо конкретных ячеек памяти с переменными, но при этом язык может зависеть от особенностей конкретного семейства процессоров. Классический пример одного из самых низкоуровневых языков – язык ассемблера, (группа языков ассемблера – что более корректно). Если говорить о более «продвинутых» языках, то к низкоуровневым языкам можно отнести и некоторые классические языки программирования, например, Си (хоть это и не совсем аккуратно). К плюсам таких языков можно отнести чрезвычайно высокую скорость работы получающегося кода, оптимальное использование и оптимальная работа с машинными ресурсами. Минусы низкоуровневых языков – довольно высокая сложность исходного кода и наличие жестких ограничений на создаваемый код.

Высокоуровневый язык программирования – язык программирования, разра-

ботанный для быстроты и удобства использования программистом. Их главное отличие и преимущество перед низкоуровневыми языками – это абстракция, то есть введение особых конструкций языка, кратко описывающих такие структуры данных и операции над ними, описания которых на машинном коде (или другом низкоуровневом языке программирования) могут быть очень громоздкими и сложными для понимания даже опытными программистами. Высокоуровневые языки позволяют не только облегчить решение сложных задач, но и существенно упростить процесс написания программного обеспечения, благодаря использованию, возможно, менее универсальных, зато более понятных и простых программных решений. К сожалению, тот факт, что высокоуровневые языки программы довольно далеки от аппаратной реализации компьютера, имеет свои минусы. Например, код, формируемый такими языками, работает гораздо медленнее низкоуровневых аналогов, программы получаются менее эффективными, на таких языках нельзя писать программные инструкции к используемому оборудованию (драйверы) и т.д. Почти все современные языки программирования могут быть отнесены в категорию высокоуровневых. Причем многие из них, например, скрипты, еще и зависят от установленного на компьютере программного обеспечения (Java, PHP, ). История высокоуровневых языков программирования, как считается, началась в 40-х годах прошлого века, но наиболее широкое распространение эти языки получили с созданием Фортрана в 1957 году.

Еще одно деление языков программирования в современности может уже считаться устаревшим, но оно позволяет лучше понять разницу между еще двумя специальных терминами – блоками и модулями. Блочный язык программирования – язык, в котором вся программа делится на части (подпрограммы), находящиеся в определенной иерархической связи друг с другом. Эти участки кода называются блоками и должны содержаться в одном файле. Блочная структура программы позволяет при распределении памяти отводить одни и те же поля памяти машины для хранения величин, описанных в блоках, которые не пересекаются, что приводит к

26

существенной экономии памяти во время работы программы. Модульные языки программирования разделяют программу на модули – отдельные файлы, в которых хранятся законченные фрагменты кода. Это деление было популярно в 60-70-х годах прошлого века, когда формировались такие языки программирования как Си, Фортран, Паскаль, Кобол, Ада и другие. Однако оно очень быстро исчерпало себя, и современные языки программирования являются блочно-модульными. То есть, позволят хранить подпрограммы как в блоках, так и в отдельных модулях.

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

Методология структурного программирования в самой краткой формулировке есть проектирование методом «сверху вниз» (или методом нисходящего проектирования), т.е. написание текста программы от общего к частному, от наиболее общих шагов алгоритма к максимально подробной детализации каждого шага. Программирование для универсальных компьютеров начиналось с программирования в машинных кодах, затем появились и начали своё развитие языки высокого уровня. Еще не так давно использование языков высокого уровня было невозможно из-за малого объема внутренней памяти программ. Однако с развитием компьютерных технологий появилась потребность унифицировать процесс разработки программного обеспечения и ускорить его. Применение структурного программирования позволяет существенно увеличить скорость написания программ, уменьшить сложность кода, сократить число ошибок и облегчить отладку написанной программы. Данная методология программирования была предложена в 70-х годах XX века Э. Дейкстрой, и, впоследствии, разработана и дополнена Николаусом Виртом – автором известной книги «Алгоритмы и структуры данных», описывающей основные идеи разработки алгоритмов в программировании, построения эффективных и надежных программ. В соответствии с данной методологией любая программа представляет собой набор блоков или модулей, подчиненных общей иерархической схеме. Виртом были предложены следующие законы, которые легли в основу структурного программирования:

1.Любая программа представляет собой структуру, построенную из трёх типов базовых конструкций, повторяющих свои аналоги из классических алгоритмов:

a.последовательное исполнение – однократное выполнение операций в том порядке, в котором они записаны в тексте программы;

b.ветвление – однократное выполнение одной из двух или более операций, в зависимости от выполнения некоторого заданного условия;

27

c.цикл – многократное исполнение одной и той же операции до тех пор, пока выполняется некоторое заданное условие (условие продолжения цикла).

2.В программе базовые конструкции могут быть вложены друг в друга произвольным образом, но никаких других средств управления последовательностью выполнения операций не предусматривается. Таким образом, некоторые специальные команды языков программирования – например, оператор безусловного перехода (goto) формально не являются разрешенными.

3.Повторяющиеся фрагменты программы (или же логически завершенные участки кода) могут оформляться в виде подпрограмм (процедур

или функций).

4.Разработка программы ведётся пошагово, методом нисходящего проектирования.

Опишем основные преимущества такого подхода. Прежде всего, в случае применения структурного программирования сначала пишется текст основной программы, в котором вместо каждого связного логического фрагмента текста вставляется вызов подпрограммы, которая будет выполнять этот фрагмент. В результате основной исходный код становится более компактным, более понятным. Вместо помещённого в подпрограмму фрагмента в код просто вставляется инструкция вызова подпрограммы. Зачастую для ускорения разработки кода и упрощения отладки вместо настоящих, работающих, подпрограмм в программу вставляются пустые подпрограммы, не выполняющие никаких действий, не нагружающие результирующий машинный код. Если полученная программа работает правильно и без сбоев, программист продолжает написание кода, постепенно заменяя все подпрограммызаглушки на реально работающие. В этом случае гарантируется работоспособность программы на каждом из этапов разработки. Программисту не приходится работать со всем текстом программы сразу – только с отдельными небольшими фрагментами. В случае возникновения необходимости внесения изменений такие изменения вносятся, не затрагивая части программы, непосредственно не связанные с ними. Это еще больше повышает надежность разработки кода. К сожалению, несмотря на все плюсы, структурное программирование имеет и свои минусы. Программы, которые пишутся таким методом, всегда конкретные. Они нацелены на решение определенных задач, что не очень удобно при разработке программного обеспечения для современных графических операционных систем. В этих задачах чаще требуется универсальность подхода, сборка программ из уже готовых «кирпичиков» – абстрактных участков кода, ускоряющих разработку ПО.

Такие возможности предоставляет более современная методология програм-

мирования. Объектно-ориентированное программирование (часто сокращаемое до

ООП) – методология программирования, в основу которой положены понятия объектов и классов. Появление и развитие ООП начинается с 60-х годов прошлого века (язык Simula 67, появившийся в 1967 году). Тем не менее, наиболее широко и полно идеи этой методологии развились позже – к 80-м годам XX века, т.к. изначально

28

идеи ООП не были восприняты как нечто очень важное и принципиальное для развития программирования. Здесь огромную роль сыграли Алан Кэй и Дэн Ингаллс, создав язык Smalltalk. Именно он стал первым широко распространённым объект- но-ориентированным языком программирования, на основе идей этого языка Бьерн Страуструп разрабатывал наиболее популярный в современном программировании язык Си++. В настоящее время большинство программных проектов реализуются в стиле ООП, благодаря возможности с большой скоростью разрабатывать новые проекты из фактически уже готовых элементов – классов. Принципы, положенные в основу ООП, очень просты – мы живем в мире объектов. Есть автомобили, дома, компьютеры, и многое другое, что обладает не только своими уникальными особенностями, но и общими чертами. Существуют абстрактные объекты – числа, символы, кнопки на поверхности современного графического приложения. Все они могут быть описаны абстрактно, а затем каждый конкретный объект появляется из такого абстрактного описания. Каждый объект характеризуется своими атрибутами и выполняемыми действиями, все их можно универсальным образом описать в виде класса – абстрактной конструкции, выражающей общие черты каждого уникального объекта. Понятно, что написание программ, использующих уже готовые классы, идет в несколько раз быстрее, чем если бы каждый объект пришлось описывать уникальным способом. Основными понятиями ООП становятся несколько принципов, описывающих уникальную организацию таких языков программирования:

1.Абстракция данных. Все программы строятся на основе классов – абстрактных конструкций, отображающих общие свойства конкретных объектов. Объекты представляют собой упрощенное, идеализированное описание реальных сущностей предметной области.

2.Инкапсуляция. Согласно этому принципу, любой класс должен рассматриваться как чёрный ящик – пользователь класса должен видеть и использовать только интерфейсную часть класса (т. е. список «внешних» декларируемых свойств и методов класса) и не вникать в его внутреннюю реализацию. Тем самым повышается простота использования классов и надежность их использования, без опасений сломать что-то «внутри» класса.

3.Сокрытие данных. Неотделимая часть ООП, логичное следствие инкапсуляции, управляющая областями видимости. Ограничивает доступ к данным внутри класса.

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

5.Полиморфизм. Полиморфизмом называют явление, при котором функции (методу) с одним и тем же именем соответствует разный программный код (полиморфный код) в зависимости от того, объект какого класса используется при вызове данного метода.

29

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

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

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

Важные задачи решают и высокоуровневые, как правило, объектноориентированные языки. Они облегчают задачу написания интерфейсов программ, в том числе графических. На них создаются многие современные прикладные программы и программное обеспечение для мобильных устройств. Эти языки привлекают к себе простой организацией процесса создания новых приложений и достаточно легким в изучении синтаксисом. Но внутреннее устройство таких языков может быть достаточно сложным и их изучение – интересный и не всегда простой процесс. К сожалению, совсем простых языков не бывает – программирование сложная, но интересная область работы.

8. Структуры данных

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

30