|
||||||||||||
|
||||||||||||
|
|||||||||
МЕНЮ
|
БОЛЬШАЯ ЛЕНИНГРАДСКАЯ БИБЛИОТЕКА - РЕФЕРАТЫ - Основы программирования на языке ПаскальОсновы программирования на языке Паскаль| | |Краткий курс лекций | |"Основы программирования на языке Паскаль" | | | | | |Введение. | | Прежде всего, следует напомнить, что изучение языка программирования | |представляет собой знакомство с формальными правилами записи алгоритмов для| |их последующего выполнения компьютером. Формальность сия проистекает из | |самих принципов, заложенных в архитектуру вычислительных устройств, и | |жесткости математической логики. Поэтому, постарайтесь воспринять все | |довольно строгие правила как неизбежность, настроить себя на серьезную, | |скрупулезную, порой сложную работу. Однако не стоит бояться, расстраиваться| |и сетовать на судьбу: немного аккуратности, внимания, знания предыдущего | |материала - и вы уже программист. | | | |Основные понятия. | | Как и любой алгоритм, являющийся, как вы помните, последовательностью | |инструкций, программа на языке Паскаль состоит из команд (операторов), | |записанных в определенном порядке и формате. | | Команды позволяют получать, сохранять и обрабатывать данные различных | |типов (например, целые числа, символы, строки символов, т.д.). Однако кроме| |команд в записи программы участвуют еще так называемые "служебные слова". | |Это и есть элементы формальности, организующие структуру программы. Их не | |так много, но их значение трудно переоценить. Служебные слова можно | |использовать только по своему прямому назначению. Переопределять их не | |разрешается. | | Вам уже известно, что основное назначение компьютера - облегчить | |человеку работу с большими объемами информации, поэтому подавляющее | |большинство программ построено по одному, довольно простому принципу: | |получение данных из внешнего мира (ввод), обработка их по соответствующему | |алгоритму, хранение необходимой информации и вывод во внешний (по отношению| |к компьютеру) мир полученных результатов. Все эти действия реализуются | |через имеющиеся в языках программирования команды, алгоритмические | |структуры и структуры данных. | | | |Основная структура программы. | | Правила языка Паскаль предусматривают единую для всех программ форму | |основной структуры: | |Program <Имя программы>; | |<Раздел описаний> | |Begin | |<Тело программы> | |End. | | Здесь слова Program, Begin и End являются служебными. Правильное и | |уместное употребление этих слов является обязательным. | | Угловые скобки в формате указывают на то, что вместо них при реальном | |программировании должно быть подставлено конкретное значение. Сама запись | |программы в принципе может производиться вообще в одну стоку. При этом ее | |части должны отделяться друг от друга хотя бы одним пробелом. Однако, такая| |запись неудобна для чтения, недостаточно наглядна, поэтому я рекомендую | |придерживаться приведенной структуры, а в теле программы по возможности | |записывать по одному оператору в строке. | | Имя программы выбирается программистом самостоятельно в соответствии с| |правилами построения идентификаторов. | | Все объекты, не являющиеся зарезервированными в Паскале, наличие | |которых обусловлено инициативой программиста, перед первым использованием в| |программе должны быть описаны. Это производится для того, чтобы компьютер | |перед выполнением программы зарезервировал память под соответствующие | |объекты и поставил в соответствие этим участкам памяти идентификаторы. | |Раздел описаний может состоять из пяти подразделов: | | 1. Описание меток (Label). | | 2. Описание типов (Type). | | 3. Описание констант (Const). | | 4. Описание переменных (Var). | | 5. Описание процедур и функций (Procedure, Function). | | При отсутствии необходимости в каком-либо виде объектов, | |соответствующий подраздел может быть опущен. | | | |Алфавит языка. | | Основу любого языка составляет алфавит, то есть конечный, | |фиксированный набор символов, используемых для составления текстов на | |данном языке (в нашем случае - программ). Конечно, стройность картины | |немного портит наличие диалектов, создающихся стихийно и очень часто | |включающих в себя апокрифические (неканонические) буквы и знаки. В | |программировании эта проблема решается введением понятия "стандарт языка". | |Оно практически неприменимо к языкам человеческим, вечно развивающимся и | |изменяющимся. Мы с вами в основном будем говорить о той самодостаточной | |части языка Паскаль, которая входит в различные его компьютерные реализации| |в неизменном виде. В плане изучения, я не вижу большого смысла излагать вам| |строгие правила стандарта, хотя такие существуют. Ограничимся некоторыми | |замечаниями, раскрывающими все же формальности употребления символов в | |языке Паскаль. | | Итак, алфавит языка Паскаль составляют: | | 1) буквы латинского алфавита; | | 2) арабские цифры; | | 3) специальные знаки. | | Использование символов первой группы чаще всего вопросов не вызывает, | |но свои тонкости здесь имеются. Во-первых, это употребление заглавных и | |строчных букв. Большинство существующих трансляторов не различают буквы | |разных регистров. Таким образом, записи "progRaM" и "PROGram" будем считать| |идентичными. Во-вторых, некоторые символы латиницы и кириллицы совпадают по| |начертанию. Нельзя ли вместо буквы "К" латинской написать "K" русскую? | |Ответ: в тетради (если вы их сможете различить) - пожалуйста, в программе | |на ЭВМ - ни в коем случае. На вид они может быть и похожи, но уж коды-то у | |них совершенно разные, а компьютер, как вам известно, оперирует внутри себя| |не буквами, а их числовыми кодами. | | По поводу привычных арабских цифр сказать можно только то, что с их | |помощью записываются не только числа. Цифры в качестве обыкновенных | |символов могут использоваться в различных других конструкциях языка. | | Сложнее всего обстоит дело со специальными знаками, поэтому их | |придется разобрать подробно, иногда забегая вперед, но вы пока можете | |пропускать мимо ушей непонятные термины, не забывая, однако, записывать все| |в тетрадь. Потом, при изучении соответствующих структур, вы будете иметь | |возможность заглянуть в этот раздел для того, чтобы уточнить какой знак в | |данном месте необходимо использовать. | | Наиболее часто употребляемым специальным символом является пробел (в | |значимых местах мы будем обозначать его в записях знаком "V"). Его | |использование связано с форматами основной структуры программы, разделов | |описаний, операторов. Не следует путать наличие пробела с отсутствием | |символа. | | . конец программы, разделение целой и дробной частей вещественного | |числа (десятичная точка), разделение полей в переменной типа Record; | | , разделение элементов списков; | | .. указание диапазона; | | : используется в составе оператора присваивания, а также для | |указания формата вывода в операторе Writeln; | | ; отделяет один раздел программы от другого, разделяет операторы; | | ' используется для ограничения строковых констант; | | - + * / ( ) арифметические знаки (используются по своему | |назначению); | | < > знаки отношений; | | = используется в составе оператора присваивания, в разделах | |описаний констант и типов, используется как знак отношения (равно); | | @ имя специального оператора определения адреса переменной, | |подпрограммы; | | ^ используется для именования динамических переменных; | | {} ограничение комментариев в программе; | | [ ] заключают в себе индексы элементов массивов; | | _ символ подчеркивания используется также как любая буква, | |например, в идентификаторах - вместо пробела; | | # обозначение символа по его коду; | | $ обозначение директивы компилятора, обозначение шестнадцатеричного| |числа. | | Возникает вопрос, а как же быть с русскими буквами и другими знаками, | |имеющимися на клавиатуре? Некоторые версии Паскаля допускают их | |использование в программе, но стандарт языка этого не подразумевает. | |Поэтому включать эти символы в программу можно только в качестве строковых | |констант или внутри комментария, то есть там, где транслятор при компиляции| |их игнорирует. При использовании этих знаков в качестве данных, они | |равноправны со всеми символами, которые может хранить в памяти и | |обрабатывать компьютер. | | | |Идентификаторы. | | Имена операторов, переменных, констант, типов величин, имя самой | |программы назначаются программистом и называются в Паскале | |идентификаторами. Существуют правила, которым должны отвечать все | |идентификаторы: | |идентификатор должен быть уникальным, то есть одним и тем же именем разные | |объекты не могут быть названы; | |идентификатор имеет ограничение по длине (зависит от конкретной реализации | |языка на компьютере); | |идентификатор может состоять только из символов латинского алфавита, цифр и| |знака подчеркивания ("_"); | |идентификатор не может начинаться с цифры. | | | |Константы. | | Из всех подразделов описаний сейчас мы рассмотрим только описание | |констант и переменных, остальные - позже. | | Вообще говоря, в Паскале константами являются любые явно заданные в | |программе данные (например, 7493, 'привет', 54.899). Следует обратить ваше | |внимание на то, что при записи числовых констант с дробной частью эта часть| |отделяется от целой не запятой, как, возможно, вы привыкли, а точкой. Для | |записи очень больших по модулю или очень малых (близких к нулю) чисел | |существует возможность записи их в так называемой экспоненциальной форме. С| |такой записью вы встречались в математике и физике, но называли ее | |стандартным видом числа. | | Пример: 2 . 4 5 6 7 Е - 0 6 | | ^мантисса ^порядок | | Здесь буква "Е" отделяет мантиссу (совокупность значащих цифр числа с | |десятичной точкой после первой) от порядка (показателя степени десятки в | |стандартном виде числа). Вам предстоит научиться как читать числа в таком | |виде, так и записывать. | | Константы, представляющие собой строковые величины, заключаются в | |апострофы. | | Если одна и та же величина используется в программе несколько раз, то | |удобнее было бы обозначить ее каким-нибудь именем и использовать это имя | |везде, где требуется записать соответствующую константу. Кроме сокращения | |размера исходного текста программы, это позволит избежать случайных ошибок,| |а также упростит отладку программы. Описание именованных констант | |начинается служебным словом Const. Далее следуют записи вида: | |<Идентификатор>=<значение>; | |Пример: | |Const | |Pi=3.14; | |Name1='Татьяна'; | |Name2='Виктор'; | |R21=6.33187E+03; | |W_W_W=934122; | |Понятие переменной. Типы. | | Данные, как вы знаете, хранятся в памяти компьютера, но для указания | |на конкретную информацию очень неудобно все время записывать физические | |адреса ячеек. Эта проблема в языках программирования высокого уровня, в | |частности в Паскале, решена введением понятия переменной. Переменная в | |Паскале - именованный участок памяти для хранения данных определенного | |типа. Значение переменной (информация в соответствующих ячейках памяти) в | |ходе выполнения программы может быть изменено. Константами же, как вы уже | |знаете, называются величины, значение которых в ходе выполнения программы | |изменено быть не может. Конкретные переменные и константы представляют | |собой объекты уникальные и отличаются друг от друга именем. | | В качестве данных в программах на языке Паскаль могут выступать числа,| |символы, целые строки символов. Заметьте, что с этими различными видами | |информации выполняются совершенно разные действия. Например, с числовыми | |величинами производятся арифметические операции, чего невозможно сделать с | |символьными. Кроме того, разные виды данных требуют различного объема | |памяти для хранения. В соответствии с этими соображениями в языке Паскаль | |введено понятие "Тип" (TYPE). Тип переменной указывает на то, какие данные | |могут быть сохранены в этом участке памяти, и в каких действиях эта | |переменная может участвовать. Существуют зарезервированные (базовые) типы в| |языке Паскаль, но, как далее вы убедитесь, есть также возможность создавать| |свои собственные, определяемые программистом типы переменных. | | К базовым типам относятся: | |тип целых чисел - Integer | |тип "длинных" целых чисел - Longint | |тип действительных (вещественных) чисел (то есть - с дробной частью) - Real| | | |тип неотрицательных целых чисел от 0 до 255 - Byte | |тип неотрицательных целых чисел от 0 до 65535 - Word | |символьный тип - Char | |строковый тип - String | |логический тип - Boolean | | Физически типы данных отличаются друг от друга количеством ячеек | |памяти (байтов), отводимых для хранения соответствующей переменной. | |Логическое же отличие проявляется в интерпретации хранящейся информации. | |Например, переменные типа Char и типа Byte занимают в памяти по одному | |байту. Однако в первом случае содержимое ячейки памяти интерпретируется как| |целое беззнаковое число, а во втором - как код (ASC) символа. | | В отличие от констант, неименованных переменных не существует. Все | |используемые в программе переменные должны быть описаны в соответствующем | |разделе описания. | | Раздел описания переменных начинается служебным словом Var, после | |которого следуют записи следующего вида: <Список имен переменных>:<Название| |типа>; | | Список может состоять из нескольких имен (при этом они разделяются | |запятыми), а также и из одного имени. Тип, указываемый после двоеточия, | |определяет, какие данные теперь могут храниться в описанных таким образом | |переменных. Для каждого используемого в программе типа переменных в разделе| |их описания должна быть, как минимум, одна собственная строка. | | Пример: | |Var | |A,B,H_22,Angle : Real; | |Name3 : String; | |Flag : Boolean; | |I,J,K,Count : Word; | |Оператор присваивания. Арифметические выражения. | | Самым простым действием над переменной является занесение в нее | |величины соответствующего типа. Иногда говорят об этом, как о присвоении | |переменной конкретного значения. Такая команда (оператор) в общем виде | |выглядит на языке Паскаль следующим образом: | | <Имя переменной>:=<Выражение>; | | Выражение, указанное справа от знака ":=", должно приводить к значению| |того же типа, какого и сама переменная, или типа, совместимого с переменной| |относительно команды присваивания. Например, переменной типа Real можно | |присвоить значение типа Integer или Word (впрочем, наоборот делать нельзя).| |Выражение будет сначала вычислено, затем, его результат будет положен в | |ячейки памяти, отведенные для переменной. | | Что же представляет собой выражение на языке Паскаль? Многое зависит | |от типа выражения. Рассмотрим сначала выражения арифметические, то есть те,| |результатом которых является число. | | В состав арифметического выражения на языке Паскаль могут входить: | |числовые константы; | |имена переменных; | |знаки математических операций; | |математические функции и функции, возвращающие число; | |открывающиеся и закрывающиеся круглые скобки. | | Правила построения выражений напоминают математические с некоторыми | |уточнениями. Выражение записывается в одну строку (никакой многоэтажности),| |между операндами обязательно должен стоять знак операции (Запись "2x" - не | |допускается), знаки некоторых операций и названия некоторых функций отличны| |от привычных вам. | | Операции: | |+ сложение; | |- вычитание; | |/ деление; | |* умножение; | |MOD остаток от деления (записывается так: A MOD B; читается: остаток от| |деления A на B); эта операция применима только к целым числам; | |DIV целочисленное деление (записывается так A DIV B; читается: | |результат деления A на B без дробной части); эта операция тоже применяется | |только для целых операндов. | | Аргументы функций всегда записываются в круглых скобках: | |SIN(X) sin x; | |COS(X) cos x; | |ARCTAN(X) arctg x; | |ABS(X) абсолютное значение x (в математике - |x|); | |SQR(X) возведение x в квадрат; | |SQRT(X) извлечение квадратного корня; | |TRUNC(X) отбрасывание дробной части х; | |ROUND(X) округление х до ближайшего целого числа; | | После выполнения второго оператора присваивания в участке памяти, | |отведенном под переменную R, окажется результат указанного выражения, | |однако, к сожалению, узнать его мы не сможем, поскольку пока не имеем | |возможности "заглянуть" в память машины, вывести значение переменной хотя | |бы на экран. | | | |Составной оператор | | Этот оператор, строго говоря, оператором не является. Дело в том, что | |также как арифметические действия иногда бывает необходимо заключать в | |скобки, последовательности команд (операторов) тоже иногда требуют | |объединения. Это позволяют сделать так называемые операторные скобки. | |Формат (общий вид) составного оператора таков: | |Begin | |<Оператор 1>; | |<Оператор 2>; | |...... | |<Оператор N> | |End; | | Возможно, такая структура напоминает вам основную структуру программы.| |Действительно, отличие только в том, что после End в конце составного | |оператора ставится точка с запятой, а в конце программы - точка. По своей | |сути вся программа представляет собой большой составной оператор. | | Обратите внимание на то, что точка с запятой перед End может не | |ставиться. | | Составной оператор предоставляет возможность выполнить произвольное | |количество команд там, где подразумевается использование только одного | |оператора. Как вы узнаете потом, такая необходимость встречается довольно | |часто. | | | |Операторы ввода и вывода информации | | Если вы помните, при рассмотрении примера работы оператора | |присваивания мы столкнулись с необходимостью узнать результат выполнения | |программы. Мы разобрались с тем, как информацию сохранять (в переменных), | |как обрабатывать (с использованием выражений), но два фундаментальнейших | |информационных процесса остались вне нашего внимания: получение информации | |и передача ее во внешний по отношению к компьютеру мир. Пока наши программы| |могут использовать лишь информацию, которая находится непосредственно в | |тексте программы. Узнать, какие значения в данный момент имеют переменные, | |также не представлялось возможным. Программирование в таких условиях теряет| |смысл. | | Взаимодействие устройств обработки и хранения информации с внешней | |средой (хотя бы с пользователем) является совершенно необходимым. За такой | |интерфейс в языке Паскаль отвечают операторы ввода-вывода информации. Эти | |инструкции позволяют ввести аргументы, параметры расчетов во время | |выполнения программы (а не на этапе ее написания), осуществить вывод | |рассчитанных данных в понятном человеку виде. | | Сначала операторы ввода (форматы операторов): | |Read(<Список ввода>); | |Readln(<Список ввода>); | | В таком формате эти команды позволяют вводить данные в переменные во | |время выполнения программы с клавиатуры. Элементами списка ввода могут быть| |имена переменных, которые должны быть заполнены значениями, введенными с | |клавиатуры. | | Выполнение операторов ввода происходит так: ход программы | |приостанавливается, на экран выводится курсор, компьютер ожидает от | |пользователя набора данных для переменных, имена которых указаны в списке | |ввода. Пользователь с клавиатуры вводит необходимые значения в том порядке,| |в котором они требуются списком ввода, нажимает Enter. После этого | |набранные данные попадают в соответствующие им переменные и выполнение | |программы продолжается. | | Примечание: данные при вводе разделяются пробелами. | | Разница между работой процедур Read и Readln (от Read line) состоит в | |следующем: после выполнения Read значение следующего данного считывается с | |этой же строчки, а после выполнения Readln - с новой строки. | | Для вывода информации в Паскале также есть две команды: | |Write(<Список вывода>); | |Writeln(<Список вывода>); | | Такой формат использования Write и Writeln позволяет выводить на экран| |монитора данные из списка вывода. Элементами списка вывода могут являться | |имена переменных, выражения, константы. Прежде чем вывести на экран | |компьютер значения выражений сначала вычислит. Элементы списка, также как и| |в операторах ввода, разделяются запятыми. | | Различие между двумя операторами вывода таково: после выполнения | |оператора Writeln (от Write line) происходит переход на новую строчку, а | |после выполнения инструкции Write, переход на новую строчку не происходит и| |печать по последующим командам вывода Write или Writeln будет происходить | |на той же строчке. При вызове оператора Writeln без параметров просто | |происходит переход на новую строчку. | | Приведем пример использования операторов ввода и вывода: | |Program Inteface; | |Var | | R,S : Real; | |Begin | | Write('Введите радиус круга '); {Печать на экране просьбы о вводе} | | Readln(R); Ввод значения в | | S:=4*ARCTAN(1)*SQR(R); {Вычисление площади круга (pR2)} | | Writeln('Площадь круга радиусом ',R,' равна ',S) | |End. | | Эта программа запрашивает у пользователя значение радиуса круга, | |обеспечивает возможность ввести его значение, рассчитывает и выводит на | |экран величину площади круга с таким радиусом. Таким образом, появляется | |возможность, не внося изменений в текст программы, вводить различные | |значения радиуса и получать, соответствующие им значения площади круга. Для| |этого достаточно несколько раз запустить программу. Также эта программа | |демонстрирует следующее правило: выдача результатов должна быть | |прокомментирована так, чтобы был ясен смысл напечатанных чисел. | |Действительно, ведь можно было бы ограничиться Writeln(S), но значение | |выведенного программой числа в этом случае было бы ясно только тому, кто | |эту программу написал. | | | |Метки. Оператор безусловного перехода. | | Каждый дом на улице имеет свой номер, все люди имеют собственные | |имена, даже ячейки памяти компьютера имеют каждая свой адрес. Все это | |принято для того, чтобы иметь возможность однозначно указать на | |определяемый объект. Точно также, для указания на операторы в программах | |применяются метки. | | Метка в стандарте языка Паскаль представляет собой целое | |неотрицательное число. Все используемые в программе метки должны быть | |перечислены в разделе описания меток, начинающемся служебным словом Label, | |например: | | Label 1, 2, 8; | | Одной меткой можно пометить только один оператор. Метка от помеченного| |оператора отделяется двоеточием. | |Пример: | | 6: Writeln(14/2); | | Во всех приведенных ранее программах операторы выполнялись один за | |другим в том порядке, в котором они были записаны в тексте. Такая | |алгоритмическая структура называется прямым следованием. Однако, в языке | |Паскаль изначально существует оператор, нарушающий прямолинейное выполнение| |программы, передающий управление в произвольную ее точку. Такая инструкция | |называется безусловным переходом и имеет такой формат: | | Goto <метка>; | | Оператор, к которому происходит переход должен быть помечен данной | |меткой. | | Использовать оператор безусловного перехода следует крайне осторожно | |во избежание получения ошибочных результатов или полного "зацикливания" | |программы. Вообще, употребление данной команды среди программистов | |считается дурным тоном. Как вы убедитесь, всегда существует возможность | |обойтись без него. | | | |Условный оператор | |Одной из основных алгоритмических структур является ветвление | |(альтернатива). | | Если условие выполняется, то будет выполнена инструкция "1", если нет,| |то - инструкция "2". Несмотря на то, что в схеме присутствуют два действия,| |выполнено будет только одно, так как условие либо ложно, либо истинно. | |Третьего не дано. Такая схема позволяет решать задачи, в которых в | |зависимости от сложившихся обстоятельств требуется совершить то или иное | |действие. Нет никакого сомнения, что число задач такого рода огромно. Более| |того, очень сложно придумать реально значимое задание, алгоритм выполнения | |которого содержал бы в себе простое прямое следование команд. Даже | |примитивный пример, взятый из курса математики, как вы увидите, не может | |быть решен без использования ветвления. Итак, необходимо вычислить значение| |выражения y=1/x. Вам известно, что данная функция не всегда имеет значение,| |то есть не для всех значений аргумента существует значение результата. Наша| |задача так составить алгоритм, чтобы исполнитель ни в коем случае не встал | |в тупик, даже при получении нуля в качестве аргумента. Сформулировать это | |на естественном языке не трудно: | |1. Получить значение x. | |2. Если x=0, то сообщить, что выражение значения не имеет, иначе - | |вычислить y как 1/x. | | Таким образом используется приведенная выше алгоритмическая структура.| |Она может быть выражена простыми словами: | | Если <усл.> {Если выполняется условие} | | то <действие 1> {то выполнить действие № 1 } | | иначе <действие 2> {иначе - выполнить действие № 2 } | |все | | Как это записать на Паскале? Да точно так же, только по-английски. | | Формат условного оператора на языке Паскаль: | | If <условие> | | Then <оператор 1> | | Else <оператор 2>; | | Обратите внимание на то, что в Then- и Else- части стоит только один | |оператор. Но что делать, чтобы решить задачу, в которой по выполнению или | |невыполнению условия нужно совершить не одно, а несколько действий? Здесь | |приходит на помощь уже известный вам составной оператор. В операторные | |скобки можно заключить любое количество операторов. | | Вариант условного оператора в этом случае: | |If <условие> | |Then Begin <группа операторов 1> end | |Else Begin < группа операторов 2> end; | | Знак "точка с запятой" не ставится перед служебным словом Else, но | |операторы в группах, естественно, отделяются друг от друга этим знаком. | | Теперь поговорим об условиях. В программах на языке Паскаль условия | |представляют собой выражения, значением которых является величина | |логического (Boolean) типа. Это может быть как просто переменная указанного| |типа, так и сложная последовательность высказываний, связанных логическими | |операциями. | | В простых условиях могут применяться знаки операций сравнения: | |>(больше), <(меньше), =(равно), <>(не равно), >=(больше или равно), | |<=(меньше или равно). | | Примеры простых условий: A=5 {Значение переменной А равно 5} | | (C+D3)>=(D1*(45-2)) Значение выражения в левой части больше либо | | S<>'ABC' {Значение переменной S не равно строковой константе 'ABC'} | | Приведем пример решения еще одной задачи: "Из двух чисел выбрать | |наибольшее". | | На первый взгляд решение очевидно, но оно не столь тривиально, как | |кажется. | |Program Example; | |Var A,B,C : Real; {A,B - для хранения аргументов, C - результат} | |Begin | |Writeln('Введите два числа'); | |Readln(A,B); {Вводим аргументы с клавиатуры} | |If A>B Then C:=A Else C:=B; B | |Writeln(C); {Выводим результат на экран} | |End. | | Еще один классический пример: "По заданным коэффициентам решить | |квадратное уравнение". Эта задача сложнее, поэтому перед тем как писать | |программу составим алгоритм, записав его в виде блок-схемы. | |Сначала вводим коэффициенты, затем вычисляем дискриминант. Теперь возникает| |две возможности: либо отсутствие действительных корней в случае | |отрицательного дискриминанта, либо эти корни можно все-таки вычислить и | |вывести на экран в случае неотрицательного дискриминанта (случай равенства | |дискриминанта нулю входит сюда же, корней - два, только они одинаковые J). | | При записи алгоритма на языке программирования следует учесть, что в | |ветви "нет" не одно действие, а три, поэтому следует применить составной | |оператор. Арифметические выражения не забывайте записывать в соответствии с| |правилами языка Паскаль. В остальном, эта программа не сложнее предыдущей. | | | | | | | |Program Sq1; | |Var A, B, C, D, X1, X2 : Real; | |Begin | |Writeln ('Введите коэффициенты квадратного уравнения'); | |Readln (A,B,C); | |D:=B*B-4*A*C; | |If D<0 Then Writeln ('Корней нет! ') | |Else | |Begin | |X1:=(-B+SQRT(D))/2/A; | |X2:=(-B-SQRT(D))/2/A; | |Writeln ('X1=', X1:8:3, ' X2=',X2:8:3) | |End | |End. | | Интересно, что в качестве оператора, который выполняется по выполнению| |или невыполнению условия, может выступать условный же оператор. В этом | |случае говорят о вложенности условных операторов. Я настоятельно рекомендую| |при решении такого рода задач составлять блок-схему алгоритма в тетради. | |Только потом, при составлении программы, вам остается лишь аккуратно | |прописывать сначала всю Then- часть, а затем переходить к Else- части. | |Обычно при записи условных операторов на языке Паскаль (особенно при | |множественных ветвлениях) команды записывают уступом вправо и вниз. Это | |повышает наглядность, и, поверьте, снижает потери времени на отладку. | | Для иллюстрации решим еще одну задачу: "решить уравнение вида A*x^2 + | |B*x + C = 0". Прошу не путать с квадратным уравнением, для которого нам | |было известно, что коэффициент А не равен нулю. Здесь же коэффициенты могут| |быть любыми числами. Исходя из элементарных математических рассуждений, | |получаем следующий алгоритм: | |[pic] | |Program Sq2; | |Var A, B, C, D, X, X1, X2 : Real; | |Begin | |Writeln ('Введите коэффициенты уравнения (A, B, C) '); | |If A=0 Then | | If B=0 Then | |If C=0 Then Writeln('X - любое число') | |Else Writeln('Корней нет! ') | | Else Begin X:=-C/B; Writeln('X=',X:8:3) End | |Else | |Begin | |D:=B*B-4*A*C; | |If D<0 Then Writeln ('Корней нет! ') | |Else | |Begin | |X1:=(-B+SQRT(D))/2/A; | |X2:=(-B-SQRT(D))/2/A; | |Writeln ('X1=', X1:8:3, ' X2=',X2:8:3) | |End | |End | |End. | | | |Цикл. Виды Циклов. | | Циклом называется многократное повторение однотипных действий. Телом | |же цикла будем называть те самые действия, которые нужно многократно | |повторять. | | Как вы понимаете, повторять одни и те же действия можно и при помощи | |оператора безусловного перехода. Если записать эти действия в программе | |одно за другим, а в конце поставить оператор перехода к началу этого блока.| |Однако таким образом можно получить только программу, которая работает | |вечно (зацикливается). Этого можно избежать, используя совместно с | |оператором перехода условный оператор, поставив выполнение перехода в | |зависимость от выполнения некого условия. Таким образом, мы получим | |структуру условного перехода и возможность организации конечного цикла. | |Вообще говоря, так мы можем решить практически любую задачу, требующую | |реализации циклического алгоритма. Конечно же, при помощи одного только | |топора можно построить дом. Поставим перед собой вопросы: "А будет ли этот | |дом красив? Сколько времени и сил можно сэкономить, используя всевозможные | |специальные инструменты?". Создатель языка Паскаль Никлаус Вирт также | |задался этими вопросами и решил их в пользу расширения языка тремя | |специальными возможностями организации циклов. Для чего? - Для удобства, | |краткости, простоты чтения программы и, не побоюсь этого слова, красоты. | |Итак, существует три вида цикла, имеющих собственные операторы на языке | |Паскаль для их записи. Эти виды имеют собственные условные названия: | |"Пока", "До", "С параметром". Друг от друга они несколько отличаются и | |используются каждый для своего класса задач. | | | |Цикл "ПОКА" | |Группа операторов, называемая "телом цикла", судя по этой схеме, будет | |выполняться пока истинно условие цикла. Выход из цикла произойдет, когда | |условие перестанет выполняться. | | Если условие ложно изначально, то тело цикла не будет выполнено ни | |разу. Если условие изначально истинно и в теле цикла нет действий, влияющих| |на истинность этого условия, то тело цикла будет выполняться бесконечное | |количество раз. Такая ситуация называется "зацикливанием". Прервать | |зациклившуюся программу может либо оператор (нажав Ctrl+C), либо аварийный | |останов самой программы, в случае переполнения переменной, деления на ноль | |и т.п., поэтому использовать структуру цикла следует с осторожностью, | |хорошо понимая, что многократное выполнение должно когда-нибудь | |заканчиваться. | | На языке Pascal структура цикла "Пока" записывается следующим образом:| | | | While <условие> Do <оператор>; | | Правда, лаконично? По-русски можно прочитать так: "Пока истинно | |условие, выполнять оператор". Здесь, так же как в формате условного | |оператора, подразумевается выполнение только одного оператора. Если | |необходимо выполнить несколько действий, то может быть использован | |составной оператор. Тогда формат оператора принимает такой вид: | |While <условие> Do | |Begin | |<оператор #1>; | |<оператор #2>; | |<оператор #3>; | |. . . | |End; | | | |Цикл "ДО" | | Этот вид цикла отличается от предыдущего в основном тем, что проверка | |условия повторения тела цикла находится не перед ним, а после. Поэтому цикл| |"До" называют циклом "с постусловием", а "Пока" - "с предусловием". | | Обратите также внимание на то, что новая итерация (повторное | |выполнение тела цикла) происходит не тогда, когда условие справедливо, а | |как раз тогда, когда оно ложно. Поэтому цикл и получил свое название | |(выполнять тело цикла до выполнения соответствующего условия). | | Интересно, что в случае, когда условие цикла изначально истинно, тело | |цикла все равно будет выполнено хотя бы один раз. Именно это отличие "до" | |от "пока" привело к тому, что в программировании они не подменяют друг | |друга, а используются для решения задач, к которым они более подходят. | | Формат цикла на языке Pascal: | |Repeat | |<оператор #1>; | |<оператор #2>; | |<оператор #3>; | |. . . | |Until <условие>; | | Читается так: "Выполнять оператор #1, оператор #2. : до выполнения | |условия". | | Здесь не требуется использование составного оператора, потому, что | |сами слова Repeat и Until являются операторными скобками. | | | |Цикл "С параметром". | | В данном случае параметром будет являться целочисленная переменная, | |которая будет изменяться на единицу при каждой итерации цикла. Таким | |образом, задав начальное и конечное значения для такой переменной, можно | |точно установить количество выполнений тела цикла. Нарисовать блок-схему | |такой структуры вы сможете сами после некоторых пояснений. | | Форматов у этого вида цикла предусмотрено два: | | For <И.П.>:=<Н.З.> To <К.З.> Do <оператор>; | | For <И.П.>:=<Н.З.> Downto <К.З.> Do <оператор>; | | Здесь И.П. - имя переменной-параметра, Н.З. - его начальное значение, | |К.З. - соответственно конечное значение параметра. В качестве начального и | |конечного значений | | Читается данная структура так: "Для переменной (далее следует ее имя) | |от начального значения до конечного выполнять оператор (являющийся телом | |цикла)". Иногда цикл с параметром даже называют "Для" или "For". В первом | |случае параметр с каждой итерацией увеличивается на единицу, во втором - | |уменьшается. | | Выполняется этот цикл по следующему алгоритму: | | 1. переменной-параметру присваивается начальное значение; | | 2. выполняется тело цикла; | | 3. переменная-параметр автоматически увеличивается на 1 (в первом | |случае формата); | | 4. если параметр превышает конечное значение, то происходит выход из | |цикла, иначе - переход к пункту 2. | | Примечание: при использовании Downto параметр автоматически | |уменьшается на 1, а выход из цикла происходит тогда, когда параметр | |становится меньше конечного значения. | | Таким образом, в отличие от первых двух видов цикла, этот цикл | |используется тогда, когда известно необходимое количество выполнений тела | |цикла. | | Вообще говоря, цикл "Пока" является универсальным, то есть любая | |задача, требующая использования цикла, может быть решена с применением этой| |структуры. Циклы "До" и "С параметром" созданы для удобства | |программирования. | | Пример. | | Найти сумму квадратов всех натуральных чисел от 1 до 100. | | Решим эту задачу с использованием всех трех видов циклов. | |I. С использованием цикла "Пока". | |Program Ex1; | |Var | | A : Integer; | | S : Longint; | |Begin | |A:=1; S:=0; | |While A<=100 Do | |Begin | |S:=S+A*A; | |A:=A+1 | |End; | |Writeln(S) | |End. | |II. С использованием цикла "До". | |Program Ex2; | |Var | | A : Integer; | | S : Longint; | |Begin | |A:=1; S:=0; | |Repeat | |S:=S+A*A; | |A:=A+1 | |Until A>100; | |Writeln(S) | |End. | |III. С использованием цикла "С параметром". | |Program Ex3; | |Var | | A : Integer; | | S : Longint; | |Begin | |S:=0; | |For A:=1 To 100 Do S:=S+A*A; | |Writeln(S) | |End. | | Теперь вам известны все основные алгоритмические структуры языка | |Паскаль. Комбинируя их, возможно запрограммировать решение любой задачи, | |конечно, если таковое существует. Тем не менее, изучение языка на этом не | |закачивается, так как для написания хороших программ по утверждению | |уважаемого Никлауса Вирта (за время моей работы у меня не появилось | |оснований в этом сомневаться) нужны кроме алгоритмических, еще удобные | |структуры данных. В рассматриваемом языке таких структур множество, для | |каждого вида определены свои команды и операции. К их рассмотрению мы и | |переходим. | | | |Строковые операции | | До сих пор мы с вами рассматривали программы, реализующие алгоритмы | |обработки числовых данных. Однако хоть ЭВМ изначально и были созданы только| |для этой цели, по мере развития аппаратной части появилась возможность | |оцифровывать данные других типов, хранить их в памяти машины, | |перерабатывать, выводить во внешний по отношению к компьютеру мир. Проще | |всего можно было так поступить с текстовой информацией. Если не ставить | |перед машиной задачу "понимания" смысла текста, то задача оцифровки | |сводится к установлению правил замены символов (литер) при вводе в | |компьютер на их коды и обратной замены при выводе информации на экран или | |принтер. Такие правила, конечно же, были составлены. Как водится, сначала | |их было множество (вспомните разнообразие таблиц кодировки), затем весь мир| |остановился на ASCII. | | Все языки программирования высокого уровня имеют средства работы с | |литерными величинами. Паскаль - не исключение. Как вам уже известно, в | |стандарте языка описаны два типа переменных для литерных величин. Это - | |String и Char. Напомню - переменная типа Char может содержать в себе только| |один единственный символ, тип String предназначен для хранения строковых | |величин до 255 символов длиною. Кстати, вы знаете не все о типе String. При| |описании переменной этого типа вы можете сами указать максимальное число | |символов, которое можно занести в нее. Конечно же, это число не должно | |превышать 255. Делается это так: | |Var | |S : String[30]; | | Для чего это нужно? | | Дело в том, что при компиляции для каждой переменной отводится свой | |участок памяти. Если мы будем выделять для всех переменных типа String по | |256 байт, то это приведет к тому, что при использовании достаточно большого| |их количества, памяти может и не хватить? Но если в переменной мы | |собираемся хранить, например, фамилию пользователя, то тридцати символов | |(тридцати байт) для этого вполне достаточно. Таким образом, экономится | |память и увеличивается быстродействие программ. | | Переменным строкового типа можно присваивать строковые величины | |(внутри программы они заключаются в апострофы), значения выражений, которые| |приводят к строковым величинам. Значения можно также вводить с клавиатуры. | |При этом апострофы не используются. Как вам известно, в числовую переменную| |нельзя ввести строковую величину. Сделать наоборот - возможно, однако | |число, находящееся в строковой переменной представляет собой просто | |последовательность символов (цифр), поэтому в арифметических выражениях | |участвовать не может. | | Также, новым для вас явится то, что при использовании строковой | |переменной, к каждому ее символу можно обратиться отдельно. Необходимо | |только знать номер нужного символа от начала строки. Его достаточно | |поставить после имени переменной типа String в квадратных скобках. | | Пример: S[5] - пятый символ строки S. | | С отдельным символом строки можно производить все действия, которые | |можно производить с любой символьной переменной (ввод, присвоение, вывод на| |экран, участие в выражениях и т.д.). | | Обратите внимание на то, что нумерация символов в строке начинается с | |единицы. Внутри квадратных скобок вместо числа может находиться выражение, | |результатом которого является целое число. Главное чтобы символ с таким | |номером в строке существовал. Но как же узнать, сколько символов в данный | |момент находится в строковой переменной? Для этого существует специальная | |функция, которая возвращает длину строковой переменной в символах. Это | |функция Length. Ее формат: Length(S) | | Здесь S - либо строковая величина, либо строковая переменная. | | Приведенная далее программа выводит на экран длину введенной | |пользователем строковой величины. | |Program Str1; | |Var | |S : String; | |Begin | |Writeln('Введите последовательность символов'); | |Readln(S); | |Writeln('Вы ввели строку из ',Length(S), ' символов') | |End. | | Другой пример: | |Решим задачу: "Введенную строку вывести на экран по одному символу в строке| |экрана". | |Program Str2; | |Var | |S : String; | |I : Byte; | |Begin | |Writeln('Введите строку'); | |Readln(S); | |For I:=1 to Length(S) do {организуем цикл, начиная с первого символа} | |Writeln(S[I]) {строки, до последнего (номер последнего} | |{совпадает с количеством символов строки S) } | |End. | | Какие же еще действия можно выполнять с переменными строкового типа? | | Две строковые величины можно состыковывать. Эта операция называется | |конкатенацией и обозначается знаком "+". | | Например, результатом выполнения следующих команд: | | R:= 'kadabra'; | | H:= 'abra'; | | S:=H+R; | |в переменной S будет значение 'abrakadabra'. | | Для конкатенации результат зависит от порядка операндов (в отличие от | |операции сложения). Следует помнить о том, какой максимальной длины может | |быть результирующая переменная, так как в случае превышения значением | |выражения числа, указанного после String в описании переменной, "лишние" | |символы в переменную не попадут. | | Строковые величины можно сравнивать между собой. Это относится также и| |к строковым переменным. Но как же компьютер определяет, какая строка | |больше: | |та, которая длиннее? | |та, которая содержит больше заглавных букв? | | На самом деле такая проверка проходит довольно сложно: компьютер | |сравнивает сначала первые символы строк. Большим из двух считается тот, код| |которого больше (вспомните, что такое код символа). Если равны первые | |символы, то так же анализируется следующая пара до тех пор, пока не будет | |найдено различие. Если начало строк совпадает, а одна из них кончается | |раньше, то вторая автоматически называется большей. | | Код символа в Паскале можно определить при помощи функции Ord. | | Ее формат: Ord(C), где С - либо непосредственно указанный символ, либо| |переменная символьного типа, либо один символ строковой переменной. Вообще,| |функция Ord имеет более глубокий смысл, но об этом - позже. Есть и обратная| |функция, которая возвращает символ по известному коду. Это функция Chr(N), | |где N - выражение, приводящее к целому числу в интервале от 0 до 255 | |(возможные значения кода символа). Очевидно, что Chr(Ord(C))=C, | |Ord(Chr(N))=N. | | Следующая маленькая программа выводит на экран кодовую таблицу: | |Program Str3; | |Var | | I : Byte; | |Begin | |For I:=32 to 255 do | |Write('VV',I:4, '-',Chr(I)) | |End. | | Цикл в программе начинается с 32 потому, что символы с кодами от 0 до | |31 являются управляющими и не имеют соответствующего графического | |представления. | | Задача: "Определить, является ли введенная строка "перевертышем". | |Перевертышем называется такая строка, которая одинаково читается с начала и| |с конца. Например, "казак" и "потоп" - перевертыши, "канат" - не | |перевертыш". | | Поступим следующим образом: из введенной строки сформируем другую | |строку из символов первой, записанных в обратном порядке, затем сравним | |первую строку со второй; если они окажутся равны, то ответ положительный, | |иначе - отрицательный. Естественно, предложенный способ решения не является| |единственно возможным. | |Program Str4; | |Var | | S,B : String; | | I : Byte; | |Begin | |Writeln('Введите строку'); | |Readln(S); | |B:=''; {Переменной B присваиваем значение "пустая строка"} | |For I:=1 to Length(S) do | |B:=S[I]+B; {Конкатенация. Символы строки S пристыковываются к} | |{переменной B слева. Самым левым окажется последний.} | |If B=S Then Writeln('Перевертыш') Else Writeln('Не перевертыш') | |End. | | Число, записанное в строковую переменную, естественно числом не | |является, но очень часто требуется его все же использовать в качестве | |числа. Для этого нужно произвести преобразование типа. Перевод строкового | |представления числа в числовое выполняет в Паскале оператор Val. | |Его формат: | |Val(S,X,C); | | Здесь S - строка, содержащая число, X - числовая переменная, в которую| |будет помещен результат, С - переменная целочисленного типа, в которую | |помещается первого встреченного в S отличного от цифры символа. Если после | |выполнения оператора Val переменная С имеет значение 0, то это означает, | |что преобразование типа прошло совершенно успешно и в строке нецифровых | |символов не встретилось. | | Противоположное действие осуществляет оператор Str. Формат оператора: | | Str(X,S); | |X - число (либо арифметическое выражение), S - строковая переменная. | | В переменную S попадает строковое представление числа X. Это нужно, | |например, при необходимости выводить на экран числа в графическом режиме | |(будет изучено позже), так как стандартные процедуры вывода на экран там | |работают только со строковыми величинами. | | Для иллюстрации рассмотрим такую задачу: "Найти сумму цифр введенного | |натурального числа". Используя только числовые переменные, решить ее можно,| |но предлагаемое здесь решение, по-моему, проще. | |Program Str5; | |Var | |S : String; | |I,X,A,C : Integer; | |Begin | |Writeln('Введите натуральное число'); | |Readln(S); {Число вводится в строковую переменную} | |A:=0; | |For I:=1 To Length(S) Do | |Begin | |Val(S[I],X,C); {Цифровой символ превращается в число} | |A:=A+X {Цифры суммируются} | |End; | |Writeln('Сумма цифр равна ',A) | |End. | | Теперь рассмотрим еще несколько действий над строками: | |оператор DELETE(S,I,C) из строковой переменной S удаляет C символов, | |начиная с I-того; | |оператор INSERT(SN,S,I) вставляет подстроку SN в строковую переменную S | |перед символом с номером I; | |функция COPY(S,I,C) возвращает подстроку строки S из C символов, начиная с | |символа с номером I; | |функция Pos(SN,S) возвращает номер символа, с которого в строке S | |начинается подстрока SN (позицию первого вхождения подстроки в строку). | |Если такой подстроки нет, то возвращается ноль. | | Пример их использования: | |"Во введенной строке заменить все вхождения подстроки 'ABC' на подстроки | |'KLMNO'". | |Program Str6; | |Var | |S : String; | |A : Byte; | |Begin | |Writeln('Введите строку'); | |Readln(S); | |While Pos('ABC',S)<>0 Do | |Begin | |A:= Pos('ABC',S); | |Delete(S,A,3); | |Insert('KLMNO',S,A) | |End; | |Writeln(S) | |End. | | | |Определение типов | | Как было упомянуто ранее, в изучаемом языке возможно определять новые | |типы переменных. После определения этот тип становится доступным для | |описания переменных, также как и стандартные типы. | | Новый тип перед первым его использованием должен быть описан в | |соответствующем разделе описаний. Его заголовок - служебное слово Type. | |Type | | <Имя типа> = <Описание типа>; | | Есть несколько способов описания. Иногда говорят даже о видах типов | |(как бы это странно ни звучало). | | Итак, первым рассмотрим так называемый перечисляемый тип. | | Перечисляемый тип используется для повышения наглядности программ, | |позволяя записывать в переменные этого типа названия разнообразных | |объектов, исследуемых программой. Этот тип представляет собой набор | |идентификаторов, с которыми могут совпадать значения параметров. | | Формат описания следующий: <Имя типа> = (<Ид.1>, <Ид.2>,? <Ид.n>); | | Далее можно определить любое число переменных уже описанного типа. | |Обратите внимание на то, что каждый идентификатор может участвовать в | |описании только одного перечисляемого типа. | | Этим переменным можно присваивать только значения из списка, | |определенного при описании типа. Эти значения не являются ни числами, ни | |строковыми величинами, ни даже величинами логического типа, поэтому они не | |могут участвовать в арифметических, строковых, логических выражениях, а | |также не могут быть выведены на экран или принтер. Величины перечисляемого | |типа можно сравнивать между собой, над их множеством в языке Паскаль | |определены несколько функций: | | Ord(X) - порядковый номер значения переменной X в списке | |идентификаторов. | | Succ(X) - следующее значение для величины Х. | | Pred(X) - предыдущее значение данного типа. | | Обратите внимание на то, что для функции Ord нумерация среди значений | |идет, начиная от нуля. Для последнего значения нельзя применять функцию | |Succ, для первого - Pred. | | Переменные различных перечисляемых типов несовместимы друг с другом. | | Множество стандартных порядковых типов в языке Паскаль на самом деле | |определены как перечисляемые. Это типы Char, Integer, другие. Достоинства | |стандартных порядковых типов лишь в том, что над каждым из них уже | |определены специфические действия. Например, тип Boolean описан так: | |Type | |Boolean = (False, True); | | Единственное его отличие от перечисляемых типов, определяемых | |программистом, состоит в том, что значения типа Boolean можно выводить на | |экран. Можете проверить, Ord(False)=0. | | Интересно, что переменная перечисляемого типа может быть счетчиком в | |цикле "с параметром". | |Пример: | |Program T1; | |Type | | Colors = (Black, Blue, Green, Cyan, Red, Magenta, Brown, Yellow, | |White); | |Var | | C1,C2 : Colors; | |Begin | |C1:=Green; | |C2:=Red; | |Writeln(Ord(C1), Ord(Succ(C2))) | |End. | | Во время выполнения на экране появятся числа "2" и "5", что | |соответствует номерам значений Green и Magenta. | | Следующий тип, который можно определить в программе - тип-диапазон. | | Здесь не нужно перечислять все значения этого типа, потому, что | |возможными для него являются значения поддиапазона уже определенного до | |него любого порядкового типа (стандартного или описанного ранее | |перечисляемого типа). Достаточно лишь указать начальную и конечную величину| |отрезка порядкового типа. Единственное условие: начальное значение не | |должно превышать конечное. | | Формат описания отрезочного типа: | |Type | | <Имя типа>=<Нач.>..<Кон.>; | |Примеры: | |Type | |Age=0..150; {Целое число в интервале от 0 до 150} | |Lat='A'.. 'Z'; {Заглавные буквы латинского алфавита} | |Month=(January, February, March, April, May, June, July, August, September,| |October, November, December); | |Spring=March..May; {Весенние месяцы} | | Есть еще одна возможность определить новый тип, о существовании | |которой можно было бы и догадаться. | |Type | | <Имя типа>=<Имя ранее определенного или стандартного типа>; | |Пример: | |Type | | Number=Byte; | | | |Массивы | | До сих пор мы рассматривали переменные, которые имели только одно | |значение, могли содержать в себе только одну величину определенного типа. | |Исключением являлись лишь строковые переменные, которые представляют собой | |совокупность данных символьного типа, но и при этом мы говорили о строке, | |как об отдельной величине. | | Вы знаете, что компьютер предназначен в основном для облегчения работы| |человека с большими информационными объемами. Как же, используя только | |переменные известных вам типов, сохранить в памяти и обработать данные, | |содержащие десяток, сотню, тысячу чисел или, к примеру, строк? А ведь такие| |задачи встречаются в любой области знания. Конечно, можно завести столько | |переменных, сколько данных, можно даже занести в них значения, но только | |представьте, какой величины будет текст такой программы, сколько времени | |потребуется для его составления, как много места для возможных ошибок? | |Естественно, об этом задумывались и авторы языков программирования. Поэтому| |во всех существующих языках имеются типы переменных, отвечающие за хранение| |больших массивов данных. В языке Паскаль они так и называются: "массивы". | | Массивом будем называть упорядоченную последовательность данных одного| |типа, объединенных под одним именем. Кстати, под это определение подходит | |множество объектов из реального мира: словарь (последовательность слов), | |мультфильм (последовательность картинок) и т. д. Проще всего представить | |себе массив в виде таблицы, где каждая величина находится в собственной | |ячейке. Положение ячейки в таблице должно однозначно определяться набором | |координат (индексов). Самой простой является линейная таблица, в которой | |для точного указания на элемент данных достаточно знания только одного | |числа (индекса). Мы с вами пока будем заниматься только линейными | |массивами, так как более сложные структуры строятся на их основе. | | Описание типа линейного массива выглядит так: | | Type <Имя типа>=Array [<Диапазон индексов>] Of <Тип элементов>; | | В качестве индексов могут выступать переменные любых порядковых типов.| |При указании диапазона начальный индекс не должен превышать конечный. Тип | |элементов массива может быть любым (стандартным или описанным ранее). | | Описать переменную-массив можно и сразу (без предварительного описания| |типа) в разделе описания переменных: | | Var <Переменная-массив> : Array [<Диапазон индексов>] Of <Тип | |элементов>; | | Примеры описания массивов: | |Var | |S, BB : Array [1..40] Of Real; | |N : Array ['A'..'Z'] Of Integer; | |R : Array [-20..20] Of Word; | |T : Array [1..40] Of Real; | | Теперь переменные S, BB и T представляют собой массивы из сорока | |вещественных чисел; массив N имеет индексы символьного типа и целочисленные| |элементы; массив R может хранить в себе 41 число типа Word. | | Единственным действием, которое возможно произвести с массивом целиком| |- присваивание. Для данного примера описания впоследствии допустима | |следующая запись: | | S:=BB; | | Однако, присваивать можно только массивы одинаковых типов. Даже | |массиву T присвоить массив S нельзя, хотя, казалось бы, их описания | |совпадают, произведены они в различных записях раздела описания. | | Никаких других операций с массивами целиком произвести невозможно, но | |с элементами массивов можно работать точно также, как с простыми | |переменными соответствующего типа. Обращение к отдельному элементу массива | |производится при помощи указания имени всего массива и в квадратных скобках| |- индекса конкретного элемента. Например: | |R[10] - элемент массива R с индексом 10. | | Фундаментальное отличие компонента массива от простой переменной | |состоит в том, что для элемента массива в квадратных скобках может стоять | |не только непосредственное значение индекса, но и выражение, приводящее к | |значению индексного типа. Таким образом реализуется косвенная адресация: | |BB[15] - прямая адресация; | |BB[K] - косвенная адресация через переменную K, значение которой будет | |использовано в качестве индекса элемента массива BB. | | Такая организация работы с такой структурой данных, как массив, | |позволяет использовать цикл для заполнения, обработки и распечатки его | |содержимого. | | Если вы помните, с такой формой организации данных мы встречались, | |когда изучали строковые переменные. Действительно, переменные типа String | |очень близки по своим свойствам массивам типа Char. Отличия в следующем: | |строковые переменные можно было вводить с клавиатуры и распечатывать на | |экране (с обычным массивом это не проходит); длина строковой переменной | |была ограничена 255 символами (255 B), а для размера массива критическим | |объемом информации является 64 KB. | | Теперь рассмотрим несколько способов заполнения массивов и вывода их | |содержимого на экран. В основном мы будем пользоваться числовыми типами | |компонент, но приведенные примеры будут справедливы и для других типов | |(если они допускают указанные действия). | |Program M1; | |Var | | A : Array [1..20] Of Integer; | |Begin | |A[1]:=7; {Заполняем массив значениями (отдельно каждый компонент)} | |A[2]:=32; | |A[3]:=-70; | |.............. {Трудоемкая задача?} | |A[20]:=56; | |Writeln(A[1],A[2],A[3], ?,A[20]) | |End. | | Как бы ни был примитивен приведенный пример, он все же иллюстрирует | |возможность непосредственного обращения к каждому элементу массива | |отдельно. Правда, никакого преимущества массива перед несколькими простыми | |переменными здесь не видно. Поэтому - другой способ: | |Program M2; | |Var | |A : Array [1..20] Of Integer; | |I : Integer; | |Begin | |For I:=1 To 20 Do {Организуем цикл с параметром I по всем возможным} | |Readln(A[I]); {значениям индексов и вводим A[I] с клавиатуры } | |For I:=20 Downto 1 Do {Распечатываем массив в обратном порядке} | |Write(A[I],'VVV') | |End. | | Эта программа вводит с клавиатуры 20 целых чисел, а затем | |распечатывает их в обратном порядке. Теперь попробуйте написать такую же | |программу, но без использования структуры массива. Во сколько раз она | |станет длиннее? Кстати, введение язык Паскаль цикла с параметром было | |обусловлено во многом необходимостью обработки информационных | |последовательностей, т. е. массивов. | | Следующая программа заполняет массив значениям квадратов индексов | |элементов: | |Program M3; | |Const | |N=50; {Константа N будет содержать количество элементов массива} | |Var | |A : Array [1..N] Of Integer; | |I : Integer; | |Begin | |For I:=1 To N Do | |A[I]:=I*I | |For I:=1 To N Do | |Write(A[I],'VVV') | |End. | | В дальнейшем для учебных целей мы будем использовать массивы, заданные| |с помощью генератора случайных чисел. В языке Паскаль случайные числа | |формирует функция Random. Числа получаются дробными, равномерно | |расположенными в интервале от 0 до 1. Выражение, дающее целое случайное | |число в интервале [-50,50] будет выглядеть так: | |Trunc(Random*101)-50 | |Зададим и распечатаем случайный массив из сорока целых чисел: | |Program M4; | |Const | |N=40; {Константа N будет содержать количество элементов массива} | |Var | |A : Array [1..N] Of Integer; | |I : Integer; | |Begin | |For I:=1 To N Do | |Begin | |A[I]:= Trunc(Random*101)-50 | |Write(A[I],'VVV') | |End | |End. | | С обработкой линейных массивов связано множество задач. Их мы | |рассмотрим на практических занятиях. | | | |Двумерные и многомерные массивы | |Представьте себе таблицу, состоящую из нескольких строк. Каждая строка | |состоит из нескольких ячеек. Тогда для точного определения положения ячейки| |нам потребуется знать не одно число (как в случае таблицы линейной), а два:| |номер строки и номер столбца. Структура данных в языке Паскаль для хранения| |такой таблицы называется двумерным массивом. Описать такой массив можно | |двумя способами: | |I. | |Var | | A : Array [1..20] Of Array [1..30] Of Integer; | |II. | |Var | | A : Array [1..20,1..30] Of Integer; | |В обоих случаях описан двумерный массив, соответствующий таблице, состоящей| |из 20 строк и 30 столбцов. Приведенные описания совершенно равноправны. | |Отдельный элемент двумерного массива адресуется, естественно, двумя | |индексами. Например, ячейка, находящаяся в 5-й строке и 6-м столбце будет | |называться A[5][6] или A[5,6]. | |Для иллюстрации способов работы с двумерными массивами решим задачу: | |"Задать и распечатать массив 10X10, состоящий из целых случайных чисел в | |интервале [1,100]. Найти сумму элементов, лежащих выше главной диагонали." | |При отсчете, начиная с левого верхнего угла таблицы, главной будем считать | |диагональ из левого верхнего угла таблицы в правый нижний. При этом | |получается, что элементы, лежащие на главной диагонали будут иметь | |одинаковые индексы, а для элементов выше главной диагонали номер столбца | |будет всегда превышать номер строки. Договоримся также сначала указывать | |номер строки, а затем - номер столбца. | |Program M5; | |Var | |A : Array[1..10,1..10] Of Integer; | |I, K : Byte; | |S : Integer; | |Begin | |S:=0; | |For I:=1 To 10 Do | |Begin | |For K:=1 To 10 Do | |Begin | |A[I,K]:=Trunc(Random*100)+1; | |Write(A[I,K]:6); | |If K>I Then S:=S+A[I,K] | |End; | |Writeln | |End; | |Writeln('Сумма элементов выше гл. диагонали равнаV',S) | |End. | |Если модель данных в какой-либо задаче не может свестись к линейной или | |плоской таблице, то могут использоваться массивы произвольной размерности. | |N-мерный массив характеризуется N индексами. Формат описания такого типа | |данных: | |Type | |<Имя типа>=Array[<диапазон индекса1>,<диапазон индекса2>,... | |<диапазон индекса N>] Of <тип компонент>; | |Отдельный элемент именуется так: | | <Имя массива>[<Индекс 1>,<Индекс 2>,...,<Индекс N>] | | | |Процедуры и функции | |При решении сложных объемных задач часто целесообразно разбивать их на | |более простые. Метод последовательной детализации позволяет составить | |алгоритм из действий, которые, не являясь простыми, сами представляют собой| |достаточно самостоятельные алгоритмы. В этом случае говорят о | |вспомогательных алгоритмах или подпрограммах. Использование подпрограмм | |позволяет сделать основную программу более наглядной, понятной, а в случае,| |когда одна и та же последовательность команд встречается в программе | |несколько раз, даже более короткой и эффективной. | |В языке Паскаль существует два вида подпрограмм: процедуры и функции, | |определяемые программистом. Процедурой в Паскале называется именованная | |последовательность инструкций, реализующая некоторое действие. Функция | |отличается от процедуры тем, что она должна обязательно выработать значение| |определенного типа. | |Процедуры и функции, используемые в программе, должны быть соответствующим | |образом описаны до первого их упоминания. Вызов процедуры или функции | |производится по их имени. | |Подпрограммы в языке Паскаль могут иметь параметры (значения, передаваемые | |в процедуру или функцию в качестве аргументов). При описании указываются | |так называемые формальные параметры (имена, под которыми будут фигурировать| |передаваемые данные внутри подпрограммы) и их типы. При вызове подпрограммы| |вместе с ее именем должны быть заданы все необходимые параметры в том | |порядке, в котором они находятся в описании. Значения, указываемые при | |вызове подпрограммы, называются фактическими параметрами. | |Формат описания процедуры: | |Procedure <Имя процедуры> (<Имя форм. параметра 1>:<Тип>; | |< Имя форм. параметра 2>:<Тип>?); | |<Раздел описаний> | |Begin | |<Тело процедуры> | |End; | |Раздел описаний может иметь такие же подразделы, как и раздел описаний | |основной программы (описание процедур и функций - в том числе). Однако все | |описанные здесь объекты "видимы" лишь в этой процедуре. Они здесь локальны | |также, как и имена формальных параметров. Объекты, описанные ранее в | |разделе описаний основной программы и не переопределенные в процедуре, | |называются глобальными для этой подпрограммы и доступны для использования. | |Легко заметить схожесть структуры программы целиком и любой из ее процедур.| |Действительно, ведь и процедура и основная программа реализуют некий | |алгоритм, просто процедура не дает решения всей задачи. Отличие в заголовке| |и в знаке после End. | |Формат описания функции: | |Function <Имя функции> (<Имя форм. параметра 1>:<Тип>; | |< Имя форм. параметра 2>:<Тип>?) : <Тип результата>; | |<Раздел описаний> | |Begin | |<Тело функции> | |End; | |В теле функции обязательно должна быть хотя бы команда присвоения такого | |вида: <Имя функции>:=<Выражение>; | |Указанное выражение должно приводить к значению того же типа, что и тип | |результата функции, описанный выше. | |Вызов процедуры представляет в программе самостоятельную инструкцию: | |<Имя процедуры>(<Фактический параметр 1>, < Фактический параметр 2>?); | |Типы фактических параметров должны быть такими же, что и у соответсвующих | |им формальных. | |Вызов функции должен входить в выражение. При вычислении значения такого | |выражения функция будет вызвана, действия, находящиеся в ее теле, будут | |выполнены, в выражение будет подставлено значение результата функции. | |Приведем простейший пример использования подпрограммы. | |Задача: "Найти максимальное из трех введенных чисел". Для решения | |воспользуемся описанием функции, принимающей значение максимального из двух| |чисел, которые передаются в нее в виде параметров. | |Program Fn; | |Var | |A,B,C :Real; | |Function Max(A,B:Real):Real; {Описываем функцию Max с формальными} | |Begin {параметрами A и B, которая принимает } | |If A>B Then Max:=A {значение максимального из них } | |Else Max:=B {Здесь A и B - локальные переменные } | |End; | |Begin | |Writeln('Введите три числа'); | |Readln(A,B,C); | |Writeln('Максимальным из всех является ', Max(Max(A,B),C)) | |End. | |Обратите внимание на краткость тела основной программы и на прозрачность | |действий внутри функции. Формальные параметры A и B, используемые в | |подпрограмме, не имеют никакого отношения переменным A и B, описанным в | |основной программе. | |Существует два способа передачи фактических параметров в подпрограмму: по | |значению и по ссылке. В первом случае значение переменной-фактического | |параметра при вызове подпрограммы присваивается локальной переменной, | |являющейся формальным параметром подпрограммы. Что бы потом ни происходило | |с локальной переменной, это никак не отразится на соответствующей | |глобальной. Для одних задач это благо, но иногда требуется произвести в | |подпрограмме действия над самими переменными, указанными в качестве | |фактических параметров. На помощь приходит второй способ. Происходит | |следующее: при обращении к подпрограмме не происходит формирования | |локальной переменной-формального параметра. Просто на время выполнения | |подпрограммы имя этой локальной переменной будет указывать на ту же область| |памяти, что и имя соответствующей глобальной переменной. Если в этом случае| |изменить локальную переменную, изменятся данные и в глобальной. | |Передача параметров по ссылке отличается тем, что при описании подпрограммы| |перед именем переменной-формального параметра ставится служебное слово Var.| |Теперь использование в качестве фактических параметров выражений или | |непосредственных значений уже не допускается - они должны быть именами | |переменных. | |Еще один классический пример. Задача: "Расположить в порядке неубывания три| |целых числа". | |Program Pr; | |Var | | S1,S2,S3 :Integer; | |Procedure Swap(Var A,B: Integer);{Процедура Swap с параметрами-переменными}| | | |Var C : Integer; {C - независимая локальная переменная} | |Begin | | C:=A; A:=B; B:=C {Меняем местами содержимое A и B} | |End; | |Begin | |Writeln('Введите три числа'); | |Readln(S1,S2,S3); | |If S1>S2 Then Swap(S1,S2); | |If S2>S3 Then Swap(S2,S3); | |If S1>S2 Then Swap(S1,S2); | |Writeln('Числа в порядке неубывания:V',S1,S2,S3) | |End. | | | |Работа с файлами | |Тип-файл представляет собой последовательность компонент одного типа, | |расположенных на внешнем устройстве (например, на диске). Элементы могут | |быть любого типа, за исключением самого типа-файла. Число элементов в файле| |при описании не объявляется. Работа с физическими файлами происходит через | |так называемые файловые переменные. | |Для задания типа-файла следует использовать зарезервированные слова File и | |Of, после чего указать тип компонент файла. | |Пример: | |Type | |N = File Of Integer; {Тип-файл целых чисел} | |C = File Of Char; {Тип-файл символов} | |Есть заранее определенный в Паскале тип файла с именем Text. Файлы этого | |типа называют текстовыми. | |Введя файловый тип, можно определить и переменные файлового типа: | |Var | |F1 : N; | |F2 : C; | |F3 : Text; | |Тип-файл можно описать и непосредственно при введении файловых переменных: | |Var | | Z : File Of Word; | |Файловые переменные имеют специфическое применение. Над ними нельзя | |выполнять никаких операций (присваивать значение, сравнивать и т.д.). Их | |можно использовать лишь для выполнения операций с файлами (чтение, запись и| |т.д.). | |Элементы файла считаются расположенными последовательно, то есть так же, | |как элементы линейного массива. Отличие же состоит в том, что, во-первых, | |размеры файла могут меняться, во-вторых, способ обращения к элементам | |совсем другой: невозможно обратиться к произвольному элементу файла; | |элементы его просматриваются только подряд от начала к концу, при этом в | |каждый момент времени доступен только один элемент. Можно представить себе,| |что для каждого файла существует указатель, показывающий в данный момент на| |определенный компонент файла. После проведения операции чтения или записи | |указатель автоматически передвигается на следующий компонент. | |Перед тем, как осуществлять ввод-вывод, файловая переменная должна быть | |связана с конкретным внешним файлом при помощи процедуры Assign. | |Формат: | | Assign(<Имя файловой переменной>,<Имя файла>); | |Имя файла задается либо строковой константой, либо через переменную типа | |Sting. Имя файла должно соответствовать правилам работающей в данный момент| |операционной системы. Если строка имени пустая, то связь файловой | |переменной осуществляется со стандартным устройством ввода-вывода (как | |правило - с консолью). | |После этого файл должен быть открыт одной из процедур: | |Reset(<Имя файловой переменной>); | |Открывается существующий файл для чтения, указатель текущей компоненты | |файла настраивается на начало файла. Если физического файла, | |соответствующего файловой переменной не существует, то возникает ситуация | |ошибки ввода-вывода. | |Rewrite(<Имя файловой переменной>); | |Открывается новый пустой файл для записи, ему присваивается имя, заданное | |процедурой Assign. Если файл с таким именем уже существует, то он | |уничтожается. | |После работы с файлом он, как правило, должен быть закрыт процедурой Close.| | | |Close(<Имя файловой переменной>); | |Это требование обязательно должно соблюдаться для файла, в который | |производилась запись. | |Теперь рассмотрим непосредственную организацию чтения и записи. | |Для ввода информации из файла, открытого для чтения, используется уже | |знакомый вам оператор Read. Правда, в его формате и использовании вы | |заметите некоторые изменения: | |Read(<Имя файловой переменной>, <Список ввода>); | |Происходит считывание данных из файла в переменные, имена которых указаны в| |списке ввода. Переменные должны быть того же типа, что и компоненты файла. | | | |Вывод информации производит, как можно догадаться оператор Write(<Имя | |файловой переменной>, <Список вывода>); | |Данные из списка вывода заносятся в файл, открытый для записи. | |Для текстовых файлов используются также операторы Readln и Writeln с | |соответствующими дополнениями, относящимися к файловому вводу-выводу. | |Любопытно, что вывод данных на монитор и ввод с клавиатуры в языке Паскаль | |тоже являются действиями с файлами. Они даже имеют свои предопределенные | |файловые переменные текстового типа: Output и Input соответственно. | |Переменная Output всегда открыта для записи, Input - для чтения. Если не | |указывать файловые переменные в операторах ввода-вывода (придем к формату, | |рассмотренному в теме "Операторы ввода-вывода"), то в случае записи по | |умолчанию выбирается файл Output, в случае чтения - Input. | |Как вы знаете, любой файл конечен и продолжать чтение из него информации | |можно лишь до определенного предела. Как этот предел установить? Проверить,| |окончен ли файл, можно вызовом стандартной логической функции Eof(<Имя | |файловой переменной>) | |Она вырабатывает значение True, если файл окончен, и False - в противном | |случае. | |Решим следующую задачу: "Написать программу, которая вводит с клавиатуры | |список фамилий учащихся, а затем распечатывает его, кроме тех учащихся, у | |которых фамилия начинается с буквы 'Ш'". | |Так как заранее количество данных не известно, то для их хранения | |используем файл. Тип элементов - строковый. | |Program L; | |Var | |I,N : Integer; | |F : File Of String; | |S : String; | |Begin | |Assign(F,'Spis.lst'); {Связываем переменную F с файлом Spis.lst} | |Writeln('Введите количество учащихся'); | |Readln(N); {Вводим количество учащихся} | |Rewrite(F); {Создаем файл для записи в него данных} | |For I:=1 To N Do {Для всех учащихся} | |Begin | |Writeln('Введите фамилию'); | |Readln(S); | |Write(F,S) | |End; | |Close(F); | |Reset(F); | |Writeln; Writeln('Список учащихся:'); | |While Not(Eof(F)) Do | |Begin | |Read(F,S); | |If S[1]<>'Ш' Then | |Writeln(S) | |End; | |Close(F) | |End. | |
РЕКЛАМА
|
|||||||||||||||||
|
БОЛЬШАЯ ЛЕНИНГРАДСКАЯ БИБЛИОТЕКА | ||
© 2010 |