Основы Pascal. Типы данных. Структура программы на языке Pascal

Вид материалаДокументы
Языки низкого уровня
Языки высокого уровня
Языки сверхвысокого уровня
Базовые понятия, концепции и особенности реализации языков программирования.
Явное объявление
Связывание переменных с ячейками памяти и время их жизни. Классификация переменных по времени жизни.
Статические переменные
Автоматические переменные
Явные динамические переменные
Неявные динамические переменные
Именованной константой
Понятия проверки и совместимости типов. Строгая типизация.
Совместимость имен типов
Область видимости переменной и варианты обзора данных
Динамический обзор данных
Методы передачи параметров в подпрограммы.
Перегрузка операторов и подпрограмм. Настраиваемые подпрограммы.
Перегруженная подпрограмма
Типы данных в языках программирования: массивы, множества, записи и объединения, указатели и ссылки. Абстрактные типы данных.
Ограниченным типом
...
Полное содержание
Подобный материал:
1   ...   5   6   7   8   9   10   11   12   ...   17
Классификация языков программирования по степени абстракции от аппаратного обеспечения.

По степени абстракции от аппаратного обеспечения языки программирования можно разделить на три класса.
  • Языки низкого уровня. Обычно это машинно-ориентированные языки, позволяющие писать программы, непосредственно работающие с памятью и другими аппаратными ресурсами. Одним из представителей этого класса языков является Ассемблер.
  • Языки высокого уровня. Позволяют в значительной мере абстрагироваться от особенностей аппаратного обеспечения и предоставляют средства манипулирования сложными структурами данных, скрывая детали их реализации. Вместе с тем, во многих случаях есть возможность работы непосредственно с аппаратными ресурсами. К таким языкам относятся, в частности, языки Ada, C/C++, Java, Pascal.
  • Языки сверхвысокого уровня. В языках данного класса полностью скрывается прямой доступ к аппаратным ресурсам и работа с ними осуществляется «прозрачно» для пользователя, без необходимости учитывать специфику реализации тех или иных операций обработки данных. Примером подобных языков служат Haskell, Prolog, Python, Ruby.



  1. Базовые понятия, концепции и особенности реализации языков программирования.

Концепция связывания в языках программирования. Связывание типов.

Связывание — процесс установления некоторой связи, например между атрибутом и объектом или между операцией и символом. Момент установления связи называется временем связывания (binding time). Связывание может происходить во время разработки или реализации языка, а также в ходе компиляции, загрузки или выполнения программы. Например, символ звездочки (*) обычно связывается с операцией умножения в процессе создания языка, а тип данных INT/INTEGER с некоторым диапазоном возможных значений целых чисел во время реализации языка. В языках C и Pascal переменная связывается с конкретным типом данных, а вызов библиотечной функции с её командами при компиляции программы. Переменная может связываться с ячейкой памяти при загрузке программы в память или перед началом выполнения фрагмента, в котором к ней обращаются, например, в случае переменных, объявленных в подпрограммах на языке Pascal.

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

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

Связывание переменных с ячейками памяти и время их жизни. Классификация переменных по времени жизни.

Связывание переменной с ячейкой памяти происходит посредством выделения свободной ячейки из пула доступной памяти. Этот процесс называется размещением в памяти. Обратный процесс называется удалением из памяти и связан с перемещением открепленной от переменной ячейки памяти обратно в пул доступной памяти. Время жизни переменной начинается в момент её связывания с некоторой ячейкой памяти и заканчивается в момент её открепления от этой ячейки. В соответствии с вариантами времени жизни можно выделить следующие категории скалярных (неструктурированных) переменных.

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

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

Явные динамические переменные — это безымянные (абстрактные) ячейки памяти, размещаемые и удаляемые с помощью явных команд периода выполнения, определяемых программистом. Обращаться к этим переменным можно только с помощью указателей и ссылок. Память для таких переменных извлекается из так называемой кучи (heap), которая представляет собой неорганизованный набор ячеек. Явные динамические переменные создаются либо специальным оператором, как, например, в языках Ada и C++, либо вызовом предусмотренной для этого системной подпрограммы, как в языке C. Кроме того, в некоторых языках, в частности в C++, есть средства уничтожения таких переменных. Явные динамические переменные часто применяются для организации различных динамических структур, таких как связанные списки и деревья, которые могут «увеличиваться» и «уменьшаться» во время выполнения программы. Также такие переменные используются в объектно-ориентированном программировании для работы с объектами.

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

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

Понятия проверки и совместимости типов. Строгая типизация.

Проверка типов обеспечивает совместимость типов операндов оператора. К операторам в данном случае относятся также подпрограмма, операндами которой являются её параметры, и оператор присваивания, операндами которого являются его целевая переменная и вычисляемое выражение. Совместимым типом называется тип, который либо изначально допускается для данного оператора, либо правила языка позволяют системе реализации неявно преобразовать его в тип, допускаемый для данного оператора. Такое автоматическое преобразование называется приведением. Применение оператора к операнду неприемлемого типа называется ошибкой определения типа. Если в языке все связывания переменных с типами являются статическими, то проверка типов практически всегда может выполняться статически. Это позволяет обнаруживать ошибки определения типа до начала выполнения программы, но снижает гибкость программирования. Динамическое связывание типов требует динамической проверки типов во время выполнения программы. Проверка типов осложняется, если язык позволяет хранить в ячейке памяти в разное время выполнения программы величины разных типов.

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

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

Область видимости переменной и варианты обзора данных.

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

Статическое, т.е. до периода выполнения, определение область видимости любой переменной называется статическим обзором данных. Большинство отдельных статических областей видимости в императивных языках связаны с определениями программных единиц. Когда в языке, использующем статический обзор данных, компилятор обнаруживает переменную, её атрибуты определяются путем поиска объявившего её оператора. В языках со статическим обзором данных этот процесс выполняется примерно следующим образом. Предположим, что сделано обращение к переменной n подпрограммы sub1. Соответствующее объявление в начале разыскивается в подпрограмме sub1. Если для данной переменной оно не найдено, то поиск продолжается в объявлениях подпрограммы, включающей в себя sub1 и называемой её статическим родителем. Если объявление переменной n не найдено и в этой подпрограмме, то поиск продолжается в следующей внешней единице (в модуле, включающем родителя подпрограммы sub1) и так далее, пока не завершится успехом, или поиск в самом внешнем блоке не закончится неудачей. В последнем случае будет зафиксирована ошибка необъявленной переменной. Статический родитель подпрограммы sub1, его статический родитель и так далее вплоть до основной программы называются статическими предками подпрограммы sub1. В соответствии с рассмотренной схемой, объявления некоторых переменных могут быть скрыты от ряда подпрограмм.

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

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

  1. Методы передачи параметров в подпрограммы.

К основным методам передачи параметров в подпрограммы относятся следующие.
  • Передача по значению. При использовании данного метода значение фактического параметра используется для инициализации соответствующего формального параметра, который в дальнейшем функционирует в подпрограмме как локальная переменная. Передача по значению обычно осуществляется путем реальной передачи данных. Передача по значению реализована, в частности, в таких языках, как Ada, C, C++, FoxPro, Pascal.
  • Передача по результату. При передачи параметра по результату, никакое значение в подпрограмму не передается. Соответствующий формальный параметр действует как локальная переменная, но непосредственно перед возвращением управления обратно в вызывающий модуль его значение передается фактическому параметру, который должен представлять собой переменную. Как правило, возвращается непосредственное значение, а не путь доступа к нему. Поддержка данного метода реализована, например, в языке Ada.
  • Передача по значению и результату. В практическом плане этот способ является комбинацией передачи по значению и передачи по результату. Значение фактического параметра используется для инициализации соответствующего формального параметра, который затем действует как локальная переменная. При завершении выполнения подпрограммы значение формального параметра передается обратно фактическому параметру. Метод передачи по значению и результату поддерживается в некоторых реализациях языков ALGOL и FORTRAN.
  • Передача по ссылке. В данном методе в вызываемую подпрограмму передается путь доступа к данным, обычно представляющий собой просто адрес. В результате вызываемая подпрограмма может получить доступ к фактическому параметру в вызывающем программном модуле. Основное достоинство передачи по ссылке связано с тем, что процесс передачи эффективен, поскольку не требуется ни тиражировать память, ни копировать что-либо. Метод передачи по ссылке реализован во многих языках, в частности в Ada, C, C++, FoxPro, Pascal.

Перегрузка операторов и подпрограмм. Настраиваемые подпрограммы.

Во многих языках один и тот же оператор применяется для выполнения разных операций. Такое множественное использование операторов называется перегрузкой операторов. Перегрузка считается приемлемой, если она не вредит читабельности и/или надежности программы. Некоторые языки, поддерживающие абстрактные типы данных, в частности Ada, C++ и FORTRAN 90, допускают перегрузку операторных символов, определяемую программистом.

Перегруженная подпрограмма — это подпрограмма, имя которой совпадает с именем другой подпрограммы в той же среде ссылок, но которая отличается от других версий количеством, порядком, типами своих параметров или типом возвращаемого значения, если она является функцией. Конкретный вариант вызова перегруженной подпрограммы определяется списком фактических параметров и типом возвращаемого значения при использовании функции. Многие языки содержат встроенные перегруженные подпрограммы. В ряде языков, а именно в Ada, C++ и Java, пользователи сами могут создавать несколько версий подпрограмм с одним и тем же именем.

Настраиваемая или полиморфная подпрограмма — это подпрограмма, которая при разных вызовах получает параметры разных типов. Перегруженные подпрограммы представляют собой разновидность полиморфизма, называемую специальным полиморфизмом. Параметрический полиморфизм обеспечивается подпрограммами с настраиваемыми параметрами, которые используются для описания типов параметров подпрограммы. Разновидность данного вида полиморфизма поддерживается, в частности, в языках Ada и C++. В этих языках в процессе компиляции создаются копии кода для каждого отдельного типа, а связывание вызовов с подпрограммами осуществляется статически.

  1. Типы данных в языках программирования: массивы, множества, записи и объединения, указатели и ссылки. Абстрактные типы данных.

Порядковые типы данных.

Порядковым называется тип, для которого область возможных значений может быть связана с последовательностью натуральных чисел. Например, в языках Ada и Pascal к порядковым типам относятся целый, символьный и булевский типы. Многие языки допускают определение пользовательских порядковых типов двух разновидностей: перечислимых и ограниченных типов.

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

Ограниченным типом называется непрерывная подпоследовательность порядкового типа. Связь ограниченного типа с его родительским типом устанавливается путем сопоставления величин в определении ограниченного типа с соответствующими величинами в ранее объявленном или встроенном порядковом типе.

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

Массивы и их виды. Понятие сечения массива.

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

Связывание типа индекса массива с переменной массива обычно является статическим, но диапазон значений индексов иногда связывается динамически. По тип связывания с диапазонами значений индексов и с памятью массивы делятся на следующие категории:
  • Статическим массивом называется массив, в котором диапазоны значений индексов связываются статически и размещение в памяти также является статическим, т.е. происходит до выполнения программы.
  • Фиксированным автоматическим массивом является массив, в котором диапазоны значений индексов связываются статически, но размещение в памяти происходит во время обработки объявлений при выполнении программы.
  • Автоматическим массивом называется массив, в котором диапазоны значений индексов связываются статически, а размещение в памяти выполняется динамически, т.е. происходит во время выполнения программы. Однако после связывания диапазоны индексов и адрес массива в памяти не изменяются в течение всей жизни переменной. Преимуществом массивов этого типа по сравнению с двумя предыдущими является гибкость, т.к. не нужно заранее знать размер массива.
  • Динамическим массивом является массив, в котором связывание диапазонов значений индексов и размещение в памяти являются динамическими, причем ячейки памяти, содержащие массив, могут меняться как угодно в период жизни массива. Достоинство этого типа массивов по сравнению с вышеописанными состоит в максимальной гибкости, поскольку размеры массива по мере необходимости могут увеличиваться и уменьшаться во время выполнения программы.

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

Типы данных: ассоциативные массивы, множества, записи и объединения.

Ассоциативным массивом называется неупорядоченное множество элементов данных, индексированных таким же количеством величин, называемых ключами. Ключи задаются пользователем и содержатся в самой структуре массива. Таким образом, каждый элемент ассоциативного массива фактически представляет собой пару элементов: непосредственно элемент данных и ключ, используемый для обращения к нему. В качестве встроенной структуры данных ассоциативные массивы присутствуют, в частности, в таких языках, как Perl и PHP, где они называются хэшами или хэш-таблицами, а также Python, где они известны под именем словарей. В некоторых языках, например в Java и Ruby, работа с ассоциативными массивами поддерживается стандартными библиотеками.

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

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

Объединением называется переменная, которая может содержать в различные периоды выполнения программы значения различных типов. В некоторых языках, например в Ada и Pascal, объединения представляют собой лишь часть структур записей, в других, в частности в C, C++ и FORTRAN, являются обособленным типом данных.