- •Примеры и решения
- •1. Рассмотрим следующую известную задачу: имеются два кувшина емкостью 3 и 8 л. Необходимо составить алгоритм, с помощью которого, пользуясь только этими двумя кувшинами, можно набрать 7 л воды.
- •Глава 4. Язык программирования basic
- •Стандартные функции для работы со строками
- •Visual Basic позволяет также создавать многомерные массивы. При объявлении многомерного массива верхние границы каждой размерности разделяются запятыми:
- •Приоритет выполнения операций
- •Арифметические операции
- •Операции сравнения
- •Операторы цикла
- •3. Найти максимальный делитель d нахурального числа к (за исключением самого к):
- •I Закрытие файла с закрытием файла связано освобождение канала ввода-вывода и, возможно, дальнейшее использование этого канала для связи с другим внешним файлом.
Операторы цикла
В языке Visual Basic реализовано три разновидности оператора цикла — операторы For...Next, Do...Loop и While...Wend.
<Переменная цикла>, <начало>, <конец> и <шаг> должны принадлежать числовому множеству значений. Общий алгоритм выполнения оператора совпадает с алгоритмом выполнения оператора For языка Pascal. Основное отличие состоит, во-первых, в возможности задать шаг изменения переменной цикла (необязательная конструкция Step <шаг>) и, во-вторых, — в возможности использования оператора Exit For внутри тела цикла.
Использование конструкции Step <шаг> позволяет управлять изменением значений переменной цикла. Значение шага изменения может быть как положительным, так и отрицательным. В случае отсутствия конструкции в заголовке цикла по умолчанию принимается значение шага, равное 1. Рассмотрим действие конструкции Step <шаг> на примере простого цикла, увеличивающего значение переменной J (считаем, что начальное значение J равно 0):
Для значений <начало> и <конец> должно выполняться следующее правило:
при отрицательном значении шага <начало> > <конец>;
при положительном значении шага <начало> < <конец>. Если указанные правила в заголовке цикла не выполняются, то не
выполняются и операторы тела цикла.
Оператор For...Next можно использовать для программирования вложенных циклов, например, используя следующую конструкцию:
Использование в теле цикла оператора Exit For позволяет программировать альтернативный путь для выхода из цикла. При его выполнении управление немедленно передается первому оператору, следующему за предложением Next, т.е. происходит выход из цикла. Например, в приведенном ниже операторе выход из цикла произойдет, как только очередное вычисленное значение переменной J станет больше 5 (т.е. при J = 7):
Любая другая последовательность применения операторов Next будет некорректной, например, вложенный оператор, приведенный ниже вызовет ошибку:
Если при этом в предложении Next не указывается переменная цикла, то очередное предложение Next считается относящемся к первому (по направлению вверх) предложению For ... То.
Примеры применения оператора For ... То:
1. Вычислить значение функции у = N! (у= 1х2хЗх ... xN)zumN = 100.
3. Найти максимальный делитель d нахурального числа к (за исключением самого к):
Оператор
Do...Loop
Оператор предназначен для повторения выполнения тела цикла до тех пор, пока значение некоторого логического выражения истинно или до тех пор, пока это значение не станет истинным.
Оператор может быть записан в двух формах: в форме проверки условия до выполнения тела цикла и в форме проверки условия после выполнения тела цикла
Синтаксис оператора с проверкой условия до выполнения тела цикла:
Do [{While | Until} <условие>][<тело цикла>]Ьоор
Синтаксис оператора с проверкой условия после выполнения тела ■ цикла:
Бо[<тело цикла>]Ьоор [{While | Until} <условие>]
Алгоритм выполнения оператора совпадает с алгоритмом выполнения операторов While и Repeat языка Pascal: максимальное число шагов Цикла заранее неизвестно, а изменение значения переменных, входящих в логическое выражение, должно программироваться внутри тела цикла.
Необязательное <условие> выполнения цикла может быть задано со словом While, и тогда тело цикла выполняется до тех пор, пока значение условия — истина, или со словом Until, и тогда тело цикла вы-
полняется до тех пор, пока значение условия — ложь. Необязательность задания условия выполнения цикла объясняется тем, что тело цикла (как и тело цикла оператора For...Next) может содержать оператор Exit Do, позволяющий завершить цикл принудительно.
Рассмотрим опять в качестве примера задачу нахождения максимального делителя (пример 3 предыдущего пункта). Алгоритм решения задачи с использованием оператора Do...Loop выглядит следующим образом:
Оператор While... Wend
По результату действия оператор аналогичен оператору While языка Pascal. Синтаксис оператора следующий:
While <условие> [<тело цикла>] Wend
Рассмотрим следующий пример.
1. Член ряда с номером п для п = 1,2,3,... определяется выражением
— (х > 1). Написать последовательность операторов для вычисления
суммы членов ряда от первого до (включительно) члена с наименьшим номером, не превосходящего 10"6.
S = О N - 1
SN = 1 ^Задание начального значения
'для члена ряда (больше, чем 10 ")
■ 4.6. Процедуры и функции
В языке Basic (так же как и в языке Pascal) существуют две разновидности подпрограмм — процедуры и функции. Каждое объявление процедуры или функции содержит обязательный заголовок, за которым следует последовательность операторов и обязательный признак завершения подпрограммы.
Передача управления в подпрограмму происходит с помощью оператора процедуры или функции.
В отличие от языка Pascal, процедуру (функцию) в языке Basic нельзя объявить внутри другой процедуры (функции).
Объявление процедуры
Обобщенный синтаксис объявления процедур в Basic следующий:
[Private | Public] [Static] Sub имя_процедуры [{список_параметров)]
[операторы]
[Exit Sub] [операторы]
End Sub
Необязательные операторы Private и Public имеют смысл для вер-
( сий расширения Visual Basic:
• оператор Public делает процедуру доступной для использования не только модулем, в котором она объявлена, но и всеми другим модулями;
| • оператор Private служит для объявления процедуры, доступной для использования только текущему модулю (и его процедурам).
Необязательный оператор Static позволяет сохранять значения локальных переменных процедуры между ее вызовами. Если предложение [ Static не используется, значения локальных переменных не сохраняются. Рассмотрим простой пример объявления процедуры:
Каждый раз при вызове процедуры с помощью оператора ExampleProc будет выводиться на экран число 1. Если же модифицировать объявление процедуры следующим образом:
то всякий раз при вызове процедуры на экран будет выводиться значение, увеличенное на единицу (1, 2, 3 и т.д.).
Оператор Exit Sub в теле процедуры может встречаться произвольное число раз и всякий раз вызывает немедленное завершение процедуры.
Оператор вызова процедуры имеет следующий синтаксис:
имя процедуры [список_параметров]
Необязательный список фактических параметров (через запятую) приводится после имени процедуры без круглых скобок (в качестве разделителя имени и списка параметров выступает знак пробела):
Proc Parl, Par2, РагЗ Объявление функций
В отличие от синтаксиса объявления процедуры объявление функции может содержать в заголовке явное указание типа возвращаемого значения (предложение As тип).
Использование операторов Public, Private и Static аналогично использованию этих операторов при объявлении процедуры.
Действие оператора Exit Function аналогично действию оператора Exit Sub.
Возвращаемое функцией значение должно быть представлено выражением в правой части оператора присваивания {имя_функции = выражение}
Приведем пример объявления функции вычисления квадратного корня действительного числа:
Оператор вызова функции отличается от оператора вызова процедуры тем, что список фактических параметров при вызове функции заключается в круглые скобки:
С = CalculateSquareRoot (Arg)
Объявление параметров
Процедуры и функции могут использовать параметры, список которых (при необходимости с указанием типа), размещают в скобках после имени подпрограммы, например:
Sub Factorial (N As Integer)
End Sub
При необходимости в объявлении указывается тип данных для параметров. В приведенном выше примере параметр N имеет тип Integer.
В версиях языка Visual Basic появилась возможность использовать обе категории вызова параметров: по значению и по наименованию. Обобщен-I ный синтаксис объявления параметра в списке параметров следующий:
Передача параметров по значению (параметры-значения)
Для передачи параметров-значений перед именем параметра в заголовке процедуры следует указывать ключевое слово ByVal. В этом случае процедуре передается копия этого значения. При передаче параметров-значений ключевое слово ByVal должно указываться обязательно:
Передача параметров по наименованию (параметры-переменные)
Для того чтобы передать параметр-переменную, следует перед параметром в объявлении указать ключевое слово ByRef. По умолчанию (т.е. без указания способа передачи) параметры в Visual Basic передаются по наименованию.
Если параметр передается по наименованию, то вызванная процедура получает физический адрес памяти передаваемой переменной и может изменять значение этого параметра.
Запишем алгоритм вычисления факториала в виде процедуры:
Необязательные параметры
Если при вызове процедуры в качестве фактических параметров указать не все формальные параметры, то последует сообщение об ошибке. Однако в Visual Basic существует возможность в заголовке подпрограммы объявить так называемые необязательные параметры (т.е. параметры, которые при вызове подпрограммы можно не указывать в списке фактических параметров).
Для того чтобы параметр стал необязательным, перед его именем ставится ключевое слово Optional. Для параметров типа Optional (и только для них) можно указать значение по умолчанию (например, Optional Param = 5). После первого необязательного параметра все последующие должны быть также необязательными, например:
В результате выполнения первого оператора на экране появится значение " One Two Three", в результате второго — "One And Three" и в результате третьего — "ABC".
■ 4.7. Организация ввода-вывода. Работа с файлами
Для работы с файлами в Basic определено понятие канала ввода-вывода. При открытии файлу ставится в соответствие канал с определенным номером. Таким образом, каждый открытый файл имеет собственный канал, с помощью которого записываются или считываются данные. В операциях ввода и вывода данных для задания связи с физическим файлом используется номер канала.
В Basic реализованы три типа доступа к файлам:
последовательный (Sequential) — для чтения и записи тексто вых файлов;
произвольный (Random) — для чтения и записи структуриро ванных файлов с записями фиксированной длины (аналогично типизированным файлам в Pascal);
двоичный (Binary) — для чтения и записи неструктурирован ных файлов (аналогично нетипизированным файлам в Pascal).
При создании коммуникационных каналов система должна знать, какой тип доступа к каждому конкретному файлу нужно использовать и какова структура данных этого файла.
Общий алгоритм работы с внешними файлами состоит из нескольких этапов:
определение номера канала ввода-вывода;
открытие файла;
чтение или запись данных;
закрытие файла.
Определение номера канала ввода-вывода
Номер свободного канала, который можно использовать для работы с файлом, вычисляется с помощью функции FreeFile:
FreeFile [(область^изменения)]
Необязательный параметр область_изменения позволяет опреде. лить диапазон значений, из которого выбирается очередной свободный номер канала. Если его значение равно 0 (по умолчанию), то возвращается номер канала из диапазона 1-255, если 1, то из диапазона 256-511 например:
Открытие файла
Связь внешнего файла с выбранным каналом осуществляется с помощью оператора открытия файла, общий синтаксис которого (для всех типов доступа) следующий:
Open ид_файла For тип [Access доступ] [блокировка] As \#]номер_канала [Ъеп=длина_записи]
Здесь:
ид_файла — полный идентификатор внешнего файла (например, C:\EXAMPLE\DATE.DAT);
тип — ключевое слово, специфицирующее тип доступа к файлу (Append, Input, Output — для последовательного доступа, Binary — для двоичного и Random — для произвольного доступа);
доступ — необязательное указание уровня доступа к файлу (Read — только чтение, Write — только запись, Read Write — чтение-запись; по умолчанию устанавливается уровень Read Write);
блокировка — необязательный параметр, определяющий возможность совместного использования файла несколькими процессами (Shared — разделенный доступ; Lock Read, Lock Write, Lock Read Write — локальный доступ);
номер_канала — номер выделенного канала ввода-вывода, знак «#» ставится при числовом константном значении (#1);
длина_записи — необязательное числовое значение (меньше либо равное 32767 байтам), задающее длину записи для файлов произвольного (random) доступа или размер текстового буфера для текстовых файлов последовательного доступа (для файлов двоичного доступа параметр игнорируется).
В случае работы с файлом последовательного доступа ключевое слово типа доступа одновременно задает и уровень доступа к данным:
Input — только чтение из файла;
Output — запись в файл;
Append — добавление к файлу.
При попытке открытия для чтения (input) несуществующего файла
I выдается сообщение об ошибке. При открытии несуществующего файла I для записи или добавления (Output или Append) создается новый файл. Если файл с указанным именем существует, то в режиме Output его содержимое удаляется, а в режиме Append файл открывается для добавления, например:
Open "C:\EXAMPLE\USERS.TXT" For Append As #3
С помощью такого оператора канал ввода-вывода под номером 3 I связывается с размещенным на диске файлом
C:\EXAMPLE\USERS.TXT для добавления информации.
Чтение (запись) данных
Процессы чтения-записи при работе с файлами различного типа
■ доступа управляются разными процедурами.
Считывание данных из файла, открытого для последовательного 1 или двоичного доступа, осуществляется с помощью оператора Input:
Input #номер_канала, список_переменных
Список переменных содержит разделенные запятой имена перемен-I ных, в которые заносятся значения, последовательно считываемые из Вфайла. В списке запрещено использовать переменные типа массив или I объект.
Элементы данных в файле должны быть записаны в том же поряд-I ке, в котором запрашивается их чтение. Двойные кавычки (" ") внутри
■ вводимых данных игнорируются.
Считывание данных из текстового файла, открытого для последо-щвательного доступа, может быть проведено также с помощью оператора I Line Input:
Line Input #номер_канала, строковая_переменная
В строковую переменную заносится последовательность символов ■текстового файла до признака конца строки (код возврата каретки — ■Chr(I3) или возврат каретки — перевод строки — Chr(13) + Chr(lO)). ■Признаки конца строки пропускаются и следующее считывание из фай-Ила осуществляется с начала следующей строки.
Запись данных в файл последовательного доступа должна происхо-Вдить с использованием операторов Print и Write. Синтаксис оператора Print:
Print #яомер_канала, [список_вывода]
Список^вывода — необязательный параметр, который задает выраже-
ние (или список выражений) для вывода в файл последовательного доступа. Если параметр отсутствует, в файл выводится признак перевода строки.
В список вывода, помимо выражений, могут входить следующие параметры:
Spc(n) — задает вывод последовательности символов «пробел» длиной п;
Tab(n) — задает позицию вывода следующих данных (п — позиция от начала строки; при использовании Tab без параметра очередной вывод начинается с начала следующей зоны).
Для форматирования записываемой в файл информации следует по-разному разделять выражения в операторе Print. Если выводные данные в операторе разделять запятыми, то в файле они будут разделены символами табуляции. Если же в операторе для разделения данных использовать точку с запятой, то данные в файл записываются без разделителей:
Данные, записанные в файл с помощью оператора Print, должны быть прочитаны из файла с помощью операторов Input или Line Input.
Синтаксис оператора Write: Write #номер_канала, \список_вывода\
Список_вывода — необязательный параметр, который задает выражение (или список выражений) для вывода в файл последовательного доступа. Выражения в списке могут разделяться запятой, пробелом или двоеточием. Если параметр отсутствует, в файл выводится признак перевода строки.
Данные, записанные в файл с помощью оператора Write, должны быть прочитаны из файла с помощью оператора Input.
Для считывания данных из файла произвольного или двоичного доступа используется оператор Get:
Get [Щно.иер_канала, {количество_записей], имя_переменной
В соответствии с синтаксисом оператора из файла считывается указанное количество записей (при произвольном доступе) или байтов (при двоичном доступе) и помещается в переменную. Нумерация записей (байтов) внутри файла начинается с единицы. Если число записей (байтов) не указано, считывается одна запись (или один байт). Разделитель параметров при этом в операторе должен присутствовать:
Get #2 , , RecordBuffer
Запись данных в файл произвольного или двоичного доступа осуществляется с помощью оператора Put, синтаксис которого сходен с синтаксисом оператора Get:
Put
[#~\номер_канала,
[количество ^записей], имя переменной
Чтение данных из файла с помощью оператора Get предполагает,
|что запись данных в файл проводилась с использованием оператора Put, и наоборот: данные, записанные в файл посредством оператора Put, должны быть прочитаны оператором Get.
