2.1. Высокоуровневые языки программированияЛюбой алгоритм рассчитан на конкретного исполнителя, имеющего свою систему команд. Алгоритм для компьютера должен быть записан с помощью команд, которые компьютер может выполнять. Устройством, выполняющим команды в компьютере, является процессор. Систему команд процессора называют машинным языком или машинным кодом. Каждая команда процессора записывается в двоичном коде. Для записи этих команд в символьной форме используют язык Ассемблер. Ассемблер является языком низкого уровня, поскольку содержит команды, отражающие машинный код. В языках программирования высокого уровня используются команды, которые объединяют последовательности машинных команд. Программы, написанные на таких языках, проще для понимания человеком, поскольку для обозначения команд используют слова естественного языка (чаще всего английского). Языки программирования высокого уровня, или высокоуровневые языки программирования (пример 2.1), были разработаны для того, чтобы суть алгоритма могла не зависеть от аппаратной реализации компьютера. Для преобразования текста программы, написанной на языке высокого уровня, в элементарные машинные команды используются специальные программы — трансляторы (пример 2.2). Например, в тексте программы достаточно написать «while», а уже транслятор языка переведет эту команду в последовательность машинных кодов. Принципы работы трансляторов зависят от аппаратного и программного обеспечения компьютера. Языки программирования высокого уровня являются формальными искусственными языками. У каждого языка программирования можно выделить две составляющие: синтаксис и семантику. Синтаксис (грамматика языка) — совокупность правил для написания программы. Семантика — смысловая сторона языка (определяет смысловое содержание языковой конструкции). Текст программы на языке высокого уровня представляет собой обычный текстовый файл. Для его «чтения» и превращения в последовательность машинных команд выполняется анализ текста программы — проверка на соответствие синтаксическим правилам и семантике данного языка программирования. В случае обнаружения несоответствия компилятор может выдавать сообщения об ошибках (пример 2.3). За время существования вычислительных машин было создано более 8 тыс. языков программирования, и ежегодно появляются новые. Некоторые из них являются узкоспециальными, другие используются миллионами программистов по всему миру. Существуют различные подходы к классификации языков программирования. По степени отличия семантики языка от машинного кода языки делят на низкоуровневые и высокоуровневые. Часто языки программирования делят на компилируемые и интерпретируемые, однако такое деление условно, поскольку для любого традиционно компилируемого языка (такого, как Паскаль) можно написать интерпретатор. 2.2. Парадигмы программированияВ истории развития языков программирования можно выделить различные парадигмы программирования — совокупность идей и понятий, определяющих стиль программирования. Между парадигмами и языками программирования нет жесткой связи. Парадигма показывает один из возможных способов использования средств языка программирования для написания кода программы. Часто язык программирования, созданный в рамках одной парадигмы, через некоторое время модернизируется, расширяется и начинает использоваться в рамках другой парадигмы. Рассмотрим некоторые парадигмы программирования. Структурное программирование — парадигма программирования, в основе которой лежит представление программы в виде блоков иерархической структуры. Разработана в конце 1960-х — начале 1970-х гг. В соответствии с данной парадигмой любая программа состоит из трех базовых управляющих структур: ветвление, цикл и последовательность; кроме того, используются подпрограммы (пример 2.4). Разработка программы ведется пошагово, методом «сверху вниз» (нисходящее программирование): сначала определяются цели решения задачи, а затем идет детализация каждого шага, который, став отдельной задачей, также может детализироваться. Процедурное программирование — парадигма программирования, при которой последовательно выполняе мые команды можно собрать в подпрограммы с помощью механизмов самого языка (пример 2.5). Это концепция программирования «снизу вверх», или концепция восходящего программирования — разработка программ начинается с разработки подпрограмм (процедур, функций), в то время как проработка общей схемы не закончилась. Парадигмы структурного и процедурного программирования основаны на подпрограммах. Разница заключается в порядке их разработки: «сверху вниз» или «снизу вверх». Функциональное программирование — парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании. Основывается функциональное программирование на вычислении результатов функций от исходных данных и результатов других функций и не предполагает явного хранения состояния программы (пример 2.6). Объектно-ориентированное программирование (ООП) — парадигма программирования, основанная на представлении программы в виде совокупности объектов и отражении их взаимодействия. Концепция ООП позволяет объединить данные и алгоритмы их обработки в единую структуру, называемую классом. Каждый объект является экземпляром какого-либо класса (пример 2.7). В ООП программа представляет собой набор объектов, имеющих состояние и поведение. Состояние и поведение объекта может измениться в результате события. Программа в целом — это объект. Для выполнения своих функций она обращается к входящим в нее объектам, которые, в свою очередь, могут обращаться к другим объектам, реализовывать свои методы или реагировать на события. Объектно-ориентированное программирование особенно важно при реализации крупных проектов. Большинство современных языков программирования являются мультипарадигменными — поддерживают сразу несколько парадигм программирования (пример 2.8). Отдельно рассматривают такие классы языков программирования, как учебные (пример 2.9) и эзотерические языки программирования (пример 2.10). Часто для записи алгоритмов применяют псевдокод — язык описания алгоритмов, использующий ключевые слова языков программирования, но опускающий детали, несущественные для понимания алгоритма (например, описания переменных). Главная цель использования псевдокода — обеспечить понимание алгоритма человеком, сделать описание более воспринимаемым, чем исходный код на языке программирования. При написании псевдокода может использоваться лексика русского языка (пример 2.11). 2.3. Основные структурные элементы языка программированияДля записи элементов языка программирования используется алфавит. Алфавиты большинства языков программирования близки друг другу по синтаксису и, как правило, используют буквы латинского алфавита, арабские цифры и общепринятые спецсимволы (знаки препинания, знаки математических операций и сравнений, разделители, служебные слова). Большинство распространенных языков программирования содержат в своем алфавите следующие элементы:
Несмотря на значительные различия между языками, многие фундаментальные понятия в большинстве языков программирования схожи между собой (пример 2.12). Согласно известной формуле Н. Вирта «Алгоритмы + структуры данных = программы», рассматривая язык программирования, нужно говорить о способах записи команд алгоритма с помощью операторов и организации работы с данными (пример 2.13). Операторы Одним из основных понятий всех языков программирования является оператор, который представляет собой законченную фразу языка и является предписанием на выполнение конкретных действий по обработке данных. Программа строится из операторов так же, как текст произведения формируется из предложений. Выделяют следующие операторы: оператор присваивания, оператор условного перехода (ветвления), оператор цикла (пример 2.14), оператор выбора, составной оператор, иногда используют пустой оператор, оператор безусловного перехода и др. Все операторы языка в тексте программы отделяются друг от друга с помощью явных или неявных разделителей (в Pascal таким разделителем является «;»). Операторы выполняются в том порядке, в котором они записаны в тексте программы. Порядок выполнения операторов может быть изменен только посредством управляющих операторов: ветвления, цикла и др. Данные Большая часть операторов предназначена для обработки величин. Величина характеризуется типом, именем и значением. Типы данных могут быть простыми и структурированными (пример 2.15). Величина простого типа в каждый момент имеет одно значение. Величина структурированного типа состоит из величин других типов. Например, строка состоит из символов, каждый отдельный символ строки имеет свое значение (код). Самым распространенным структурированным типом данных является массив, с которым вы познакомитесь в этом учебном году. Всем объектам в языках программирования (переменным, функциям, процедурам и др.) даются имена. Имя объекта в программе называют идентификатором (от слова «идентифицировать»). Идентификатором является любая конечная последовательность букв и цифр, начинающаяся с буквы (пример 2.16). Имя может содержать знак подчеркивания «_». Использовать служебные слова языка в качестве идентификатора запрещается в большинстве языков программирования. Величины могут быть постоянными (константы) и переменными. Переменная может принимать некоторое значение в результате выполнения команды ввода или с помощью оператора присваивания. В ходе выполнения программы значения переменной могут неоднократно меняться. После описания переменная отождествляется с некоторым блоком памяти, содержимое которого является ее значением. Переменная хранит значение, соответствующее ее типу (например, переменная целого типа не может принимать значение вещественного числа). Это значение может извлекаться из памяти для выполнения с ним операций, соответствующих типу переменной. Подпрограммы Алгоритм, реализующий решение отдельной части основной задачи, называют вспомогательным, а его запись на языке программирования — подпрограммой. Подпрограммы могут быть реализованы в виде функций или процедур. Функция описывает процесс вычисления определенного значения, зависимого от некоторых аргументов, поэтому для функции всегда указывается тип возвращаемого значения. Для каждого языка высокого уровня разработана библиотека стандартных функций: арифметических, логических, символьных и т. д. (пример 2.17). Функции (как стандартные, так и задаваемые программистом) используются в программе в выражениях. Часто используют подпрограммы, которые не возвращают конкретное значение, а представляют собой самостоятельный этап обработки данных. В языке Pascal их называют процедурами, в других языках они могут называться по-другому или не иметь собственного названия и описываться так же, как функции (пример 2.18). Язык программирования — инструмент для решения конкретной задачи. Не существует единственного самого лучшего языка программирования. Для решения задач разного рода и уровня сложности требуется применять разные языки и технологии программирования. В простейших случаях достаточно освоить основы структурного написания программ, например на языке PascalABC. Для создания же сложных проектов требуется не только свободно владеть каким-то языком в полном объеме, но и иметь представление о других языках и их возможностях. Как правило, чем сложнее задача, тем больше времени требуется на освоение инструментов, необходимых для ее решения. |
Первым высокоуровневым языком программирования, который был реализован практически, стал в 1949 г.
Краткий код (Short Code). Операции и переменные в этом языке программирования кодировались двухсимвольными сочетаниями.Пример 2.1. Некоторые языки программирования высокого уровня:
Пример 2.2. При трансляции программы происходит преобразование текста с одного языка на другой. Различают следующие виды трансляции: компиляция и интерпретация. Компилятор — транслятор, преобразующий исходный код с какого-либо языка программирования на машинный. В результате создается исполняемый файл, который может быть выполнен непосредственно в операционной системе. Среда программирования PascalABC имеет встроенный компилятор, опции которого можно настроить, выполнив команду Сервис Настройки: Интерпретатор — транслятор, который может работать двумя способами:
Чистая интерпретация применяется для языков JavaScript, VBA, Lisp и др. Примеры интерпретаторов, создающих байт-код: Perl, PHP, Python и др. В 1951 г. американский ученый Грейс Мюррей Хоппер (1906— 1992) создала первый в мире компилятор и ввела сам этот термин. Компилятор осуществлял функцию объединения команд, производил выделение памяти компьютера и преобразование команд высокого уровня (в то время псевдокодов) в машинные команды. Пример 2.3. Семантическая (строка 4) и синтаксическая (строка 6) ошибки в среде PascalABC.
Пример 2.4. Основная идея структурного программирования заключается в том, что программа должна иметь простую структуру, быть хорошо читаемой и легко модифицируемой. Структурированность кода поддерживается посредством подпрограмм, которые вызываются из других подпрограмм. Структурное программирование поддерживают такие языки, как Pascal, Go, С и многие другие языки программирования. Пример 2.5. Особенность языков процедурного программирования заключается в том, что задачи разбиваются на шаги и решаются шаг за шагом. Решение для каждого отдельного шага оформляется в виде отдельной процедуры. К процедурным языкам относят: C, Pascal, Lua и др. Пример 2.6. В основе функциональных языков лежит лямбда-исчисление (Х-исчисление) — математическая теория для формализации понятия вычислимости. К ним относят: Haskell, Lisp, F# и др. Пример 2.7. В программе текстовый редактор объектами могут быть абзац текста, меню, кнопки и т. д. В классе, который описывает кнопку, содержатся данные о размере кнопки, ее внешнем виде, алгоритмы, позволяющие «нажать» кнопку или «навести на нее мышь» и др. Конкретная кнопка, например Ч , является объектом. Такое событие, как «клик мышью по такой кнопке», изменит начертание текста. Событие «двойной клик мышью по абзацу текста» выделит его и т. д. К объектно-ориентированным языкам относят:
Пример 2.8. Мультипарадигменные языки программирования чаще всего поддерживают процедурную (структурную), объектно-ориентированную и функциональную парадигмы: C++, Python, JavaScript, Ruby, C#.
Пример 2.9. Учебный язык обеспечивает простоту, ясность и удобочитаемость конструкций языка. Как учебные языки программирования разрабатывались: Basic, Pascal, Logo, Scratch. Пример 2.10. Некоторые эзотерические языки служат для проверки математических концепций (Thue, Unlambda), другие создаются для развлечения. Часто они пародируют «настоящие» языки программирования или являются абсурдным воплощением концепций программирования (Smetana, Var’aq, FiM++ и др.). Пример 2.11. Псевдокод алгоритма нахождения суммы квадратов первых n натуральных чисел.
Пример 2.12. Некоторые служебные слова (в алфавитном порядке) в разных языках программирования. Пример 2.13. Структурная схема процедурного языка программирования. Выражения строятся из величин (констант и переменных), функций, скобок, знаков операций и т. д. Тип выражения определяется результатом вычислений. Выражения могут принимать числовые, логические, символьные, строковые и другие значения. Пример 2.14. Запись оператора цикла (поиск суммы квадратов первых n натуральных чисел).
Некоторым идентификаторам заранее предписан определенный смысл, например sin, cos, sqrt, abs — имена математических функций.
Пример 2.17. Список стандартных функций языка программирования PascalABC можно посмотреть в справочной системе:
|
1. Для чего предназначен транслятор?
2. Какие функции выполняет компилятор? Интерпретатор?
3. Что определяется парадигмой программирования?
4. Из каких элементов может состоять алфавит языка программирования?
5. Что представляет собой оператор языка программирования?
6. Какие типы данных вам известны?
7. Для чего используются функции и процедуры?
Упражнения
1. Напишите программы для решения следующих задач.
- Определите последнюю цифру натурального числа N.
- Два отрезка на плоскости задаются координатами своих концов. Определите, какой из них короче.
- Найдите сумму 1 +\(\frac{1}{2^2}+\frac{1}{3^2}+…+\frac{1}{N^2}\) для заданного N.
- Вводится строка текста. Определите, является ли она палиндромом.
- Вводятся два целых числа, являющихся числителем и знаменателем дроби. Сократите дробь, выведите полученные числитель и знаменатель. Подсказка: можно воспользоваться алгоритмом Евклида.
- *.Дед Мазай и заяц играют в очень простую игру. Перед ними — гора из N одинаковых морковок. Каждый из игроков во время своего хода может взять из нее любое количество морковок, равное неотрицательной степени числа 2 (1, 2, 4, 8, …). Игроки ходят по очереди. Кто возьмет последнюю морковку, тот и выигрывает. Составьте алгоритм, который при заданном значении N определяет победителя в этой игре. Учтите, что каждый из игроков хочет выиграть и не делает лишних ходов, т. е. играет оптимально.
2.* Предложенные ниже алгоритмы записаны разными способами. Определите, что делает каждый из предложенных алгоритмов, и реализуйте их на языке Pascal.
3.* Изобразите любой алгоритм из упражнения 2 в виде блок-схемы.