Тайник "Программист в Санино".

Тайник создан 3 марта 2007 года. Основатель - Tol.
Информация о тайнике и правила игры на http://www.geocaching.su.


Это только справочник для программистов-геокешеров. Остальная информация на http://www.geocaching.su.

 

Введение в программирование на Turbo Pascal для не-программистов.

Основные понятия.

Турбо Паскаль - один из наиболее простых языков программирования, поэтому именно его обычно изучали в школах и на первых курсах институтов (сейчас уже вряд ли, так как DOS потерял актуальность уже более десятилетия назад, хотя Windows все еще имеет возможность запускать программы, скомпилированные под DOS). Программирование под DOS представляет собой линейное задание команд, где каждая следующая команда выполняется только по завершении предыдущей. В качестве команд, в основном, используются вызовы процедур и функций, операторы присваивания, операторы цикла и условные операторы. Команды разделяются между собой точкой с запятой. Очень часто при наступлении некоторого условия необходимо выполнить не одну команду, а группу команд. При этом такая группа команд помещается между словами begin и end с точкой с запятой на конце. Вся же программа также размещается между этими словами, но с точкой на конце. Для временного хранения данных используются переменные, значения которых можно многократно изменять в ходе выполнения программы. Прежде чем рассмотреть все подробнее, давайте ознакомимся с двумя процедурами:

write(p1, p2, p3) - выводит на экран строки и числа, перечисленные через запятую. Положение текста на экране определяется текущим положением курсора, который при выводе каждого знака сдвигается на одно положение вправо. На закате эпохи ДОСа экраны мониторов вмещали 25 текстовых строк по 80 символов в каждой. Вы и сейчас можете видеть работу монитора в этом текстовом режиме, когда включаете компьютер (POST, BIOS, и т.п.).
writeln(p1, p2, p3) - аналогично предыдущей процедуре, но после вывода всех значений параметров курсор перемещается в начальную позицию следующей строки. То есть вывод данных в следующий раз будет происходить с новой строки.

Переменные.

Переменные используются для хранения данных во время выполнения программы. Они называются любыми латинскими буквами и могут также содержать цифры (но не в первой позиции). Для названия переменных не годятся некоторые зарезервированные слова и названия операторов и функций. Регистр названий переменных (как и всех прочих слов в Pascal) не имеет значения, то есть MyNumber и mynumber - это одна и та же переменная. Переменные бывают нескольких типов. Для взятия этого тайника вам необходимо знать о трех наиболее часто используемых типах.

Тип Integer - целое число. Может принимать любые значения от -32768 до 32767 (включая ноль).

Тип String - сторка. Может содержать 255 любых символов.

Тип Boolean - булева логика. Может содержать одно из двух значений: True (истина) или False (ложь).

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

var
myint1, myint2, myint3: integer;
mystr1, mystr2, mystr3: string;
mybool: boolean;

Операции присваивания.

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

myint1:=15;
myint2:=20;
myint3:=myint1+myint2;

Вероятно, вы уже догадались, что myint3 теперь содержит значение 35. Возможно, следующий пример удивит вас больше.

mystr1:='15';
mystr2:='20';
mystr3:=mystr1+mystr2;

Если вы думаете, что результат будет '35', то вы ошибаетесь! Ведь теперь мы работали со строками, а оператор + в данном случае является оператором объединения строк. То есть в действительности mystr3 содержит значение '1520'.

Разумеется, строки дают вам куда больше возможностей, чем просто работа с символами цифр. Вы можете работать с любым текстом:

a:='hello';
b:='world';
c:=a+', '+b+'!';
{теперь c = 'hello, world!'. В Паскале любой текст, указанный в фигурных скобках, является комментарием для программиста и игнорируется компилятором}

Доступ к символам строки осуществляется заданием номера позиции символа в квадратных скобках, где 1 - это первый символ. Пример:

s:='Only Programmers Know It!';
s1:='And it is '+s[1]+s[18]+s[25];
{значение переменной s1 теперь 'And it is OK!'}

s[0] представляет собой битовое представление длины строки, но правильнее получать ее длину с помощью функции length(s:string). Если взять строки из предыдущего примера, то вот что мы получим:

i:=length(s); {i=25}
i1:=length(s1); {i1=13}

Важно понимать, что значения string не могут быть присвоены переменным типа integer, а значения integer не могут присваиваться переменным типа string, хотя последняя операция всегда проходит безболезненно с помощью процедуры str, первым параметром которой является исходный integer, а вторым - переменная string, в которую будет помещен результат. Параметры разделяются между собой запятыми:

myint1:=156+3;
str(myint1, mystr1);
{сейчас mystr1='159'}

Для обратной конвертации используют процедуру val, первым параметром которой является строковая переменная для конвертации, вторым - числовая переменная, в которую нужно поместить результат, третим - числовая переменная, в которую будет помещена позиция символа исходной строки, не являющегося числом (в случае ошибки):

St:='15';
val(st, i1, i2);
{i1=15, i2=0}

St:=15w6;
Val(st, i1, i2);
{ошибка: i1=0, i2=3}

С булевой логикой все проще. Булевы переменные обычно используются, когда переменная может иметь одно из двух взаимоисключающих значений. Довольно часто эти переменные используются для хранения состояния чекбоксов (checkbox - визуальный компонент в виде квадратика, в котором либо стоит галочка, либо нет). Присваивание булевых значений происходит так же, как и присваивание любых других значений, но здесь еще появляется полезный оператор not, который инвертирует значение переменной (true становится false, а false становится true):

a:=true;
b:=not a;
{сейчас b=false}


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

i:=5+10*sqr(3)-50 div 2 + 2*(10+5);

Если производить действия по порядку, то получится неправильное значение. Чтобы посчитать правильно, сначала вычисляем действия в скобках 10+5=15, затем рассчитываем значения функции sqr(3), получаем 9. Затем умножаем 9 на 10, получаем 90. Затем делим 50 на 2, получаем 25. Теперь умножаем 2 на 15, получаем 30. В последнюю очередь производим операции сложения и вычитания: 5+90-25+30. Теперь мы знаем, что i=100. Короче, обычная школьная математика, но ошибиться из-за невнимательности - проще простого.

Массивы переменных.

Представьте, что у вас есть несколько сотен данных одного типа. Задавать все v1, v2, v3 ... v100 в секции VAR было бы проблематично, а еще сложнее было бы обрабатывать все эти данные. Для таких случаев используются массивы. Массив - это блок из нескольких переменных одного типа. Синтаксис задания массива:

var
array_name: array[
min..max] of type;

Здесь min - минимальный индекс, обычно 1, а max - максимальный индекс, при min=1 он равен количеству переменных в массиве. Type - тип переменных - integer, string, boolean и т.п. Пример:

arr: array[1..100] of string; {описывает 100 переменных типа string}

Обращение к переменной массива происходит путем задания номера этой переменной в квадратных скобках. В остальном, переменные массива можно использовать так же, как и обычные переменные. Обращение к символам строковой переменной массива осуществляется во вторых квадратных скобках:

arr[1]:='Hello, World!'; arr[2]:=arr[1]; writeln(arr[2]+arr[1][13]+ arr[1][13]);
{ здесь arr[1][13]='!'. Результат: Hello, World!!! }

Условный оператор IF.

Программирование было бы во многих случаях бесполезным, если бы программа не имела возможность изменять свое поведение в различных ситуациях. Для контроля таких ситуаций используются условные операторы. Мы рассмотрим здесь лишь один из них:
if выражение then действие-1 else действие-2;
при этом часть else - необязательная, то есть можно ограничиться и следующим:
if выражение then действие-1;

Что делает этот код? Если "выражение" истинно (=true), выполняется "действие-1", иначе выполняется "действие-2".

Довольно часто некоторое действие должно выполняться только при истинности нескольких условий сразу, либо при истинности одного из нескольких условий. В таких случаях эти условия помещают в скобки и указывают отношение между ними - and (и) или or (или):
{действие-1 сработает, только если оба выражения 1 и 2 истинны}
if (выражение-1) and (выражение-2) then действие-1;
{действие-1 сработает, если хотя бы одно из двух выражений истинно}
if (выражение-1) or (выражение-2) then действие-1;

В более сложных случаях операторы and и or комбинируются, просто к сведению, для взятия тайника вам это не понадобится:

{если истинно выражение-1 ЛИБО выражение-2 И В ТО ЖЕ ВРЕМЯ истинно выражение-3, то выполнится действие-1}
if ((выражение-1) or (выражение-2)) and (выражение-3) then действие-1;

Давайте рассмотрим несколько простых примеров.

{1} if i>=10 then writeln('значение слишком велико') else writeln('значение меньше десяти');

Первый вопрос, который у вас, вероятно, возникает, это недоумение, почему в выражении нет булева сравнения для определения истинности. Ответ прост: если его нет в явном виде, то оно подразумевается! В полном виде выражение выглядело бы так:

if (i>=10) = true then writeln('значение слишком велико') else writeln('значение меньше десяти');

В этом примере использовался оператор сравнения "больше либо равно". Если значение i больше либо равно 10, то на экран выводится текст 'значение слишком велико', а если значение i меньше 10, то выводится текст 'значение меньше десяти'. Для сравнения переменных вы можете использовать и другие варианты, такие как
= равно
<> не равно
> больше
>= больше или равно
< меньше
<= меньше или равно.

Важно осознавать, что строковые переменные сравниваются не так, как числовые. Сравнение строковых переменных основывается на порядке символов в таблице ASCII. Чтобы не забивать вам голову этой таблицей, я лишь упомяну, что из полезных нам символов сначала идут цифры от '0' до '9', затем буквы от 'A до Z', далее буквы от 'a' до 'z'; Посмотрите, как по-разному сравниваются строки и числа:

var s1, s2: string;
i1, i2: integer;
begin

i1:=123; i2:=56;
s1:='123'; s2:='56';

writeln(i1>i2);
writeln(s1>s2);

end.

Данная программа выведет на экран:
TRUE
FALSE

Почему так произошло? Ну, в первом случае, все очевидно: 123 действительно больше 56, что и дает истину в качестве результата (true). Но во втором случае мы имеем дело со строками, где каждый символ первой строки сравнивается с каждым символом второй строки. Уже при сравнении первых символов мы видим, что '1' меньше '5', поэтому и утверждение, что '123'>'56' не является истинным, то есть является ложным (что и выводится на экран - false). При сравнении строк используются не только числовые символы, а вообще любые символы из таблицы ASCII. Например, 'abc' меньше 'bcd', в то же время 'ABC' меньше 'abc', но '123' меньше 'ABC'.

{2} if (odd(i)) and (i>=0) then writeln('значение нечетное и положительное: ', i) else begin i:=1; writeln('значение было либо четное, либо меньше нуля, либо и то, и другое. Теперь i=1.');end;

Как вы помните, значение "выражения" сравнивается со значением True, то есть
If odd(i) then…
Равносильно
if odd(i)=true then…

odd(i:integer) - это стандартная функция определения нечетности числа, которая возвращает true, если i - нечетное, и false, если i - четное. Результат выполнения этого примера вполне предсказуем.

Надеюсь, вы еще не забыли, что группы команд, которые выполняются по достижении некоего условия, помещают между словами begin и end, что мы и сделали после слова else. В первом же случае (после then) мы использовали только одну команду, поэтому указание begin end там было необязательным, хотя и возможным.

Цикл FOR.

Синтаксис цикла следующий:

for присвоение переменной начального значения to конечное значение переменной do действие;

Проще понять, рассмотрев реальный пример:
for i:=1 to 5 do write(i);

Данный цикл заменяет нам следующие действия:
write(1); write(2); write(3); write(4); write(5);

Оба примера выводят на экран 12345. Разумеется, если бы надо было сосчитать до 10000, то без цикла эта работа, выполненная вручную, заняла бы весь день!

Смысл нашего цикла в том, что сначала переменной i присваивается значение 1, после чего выполняется команда, указанная за ключевым словом do, у нас это write(i). Когда эта команда будет выполнена, управление передается на начало цикла, к переменной i прибавляется единица и снова запускается тело цикла - write(i) - уже с новым значением i=2. Так продолжается до тех пор, пока i не достигнет значения, указанного после ключевого слова to (у нас это 5). Тогда тело цикла выполнится в последний раз, и управление перейдет на следующую за циклом команду. При обратном отсчете, например от 5 до 1, вместо to используется ключевое слово downto:

for i:=5 downto 1 do write(i);

Не забывайте, что при необходимости выполнить в цикле несколько команд, нужно оборачивать их в begin end. Вот еще два примера:

{пример-1}
a:=2; c:=0;
for b:=1 to 5 do c:=c+b*a;
if odd(a) then a:=2 else a:=1;
writeln('a=',a,' c=',c);
{вывод на экран: a=1 c=30}

{пример-2}
a:=2; c:=0;
for b:=1 to 5 do
begin
c:=c+b*a;
if odd(a) then a:=2 else a:=1;
end;
writeln('a=',a,' c=',c);
{вывод на экран: a=1 c=24}

Как видите, формулы одни и те же, а результаты разные, потому что в первом примере строка

if odd(a) then a:=2 else a:=1;

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

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

for i:=1 to 5 do
begin
for i1:=1 to 5 do write(i1, '-', i, ' ');
writeln;
end;
writeln('Вот такая матрица!');

Этот вложенный цикл выполняется так: сначала срабатывает внешний цикл и производит действия для i=1. Эти действия подразумевают полную прогонку внутреннего цикла (i1) и перенос курсора на начало новой строки. Затем внешний цикл прибавляет к i единицу и снова запускает внутренний цикл (i1), после чего снова осуществляется перенос курсора на новую строку. Последний раз внешний цикл сработает, когда i будет равной 5. После этого цикл завершится, и управление будет передано следующей за циклом команде, то есть в нашем случае это writeln('Вот такая матрица!'); Теперь посмотрим на результат выполнения программы:

1-1 2-1 3-1 4-1 5-1
1-2 2-2 3-2 4-2 5-2
1-3 2-3 3-3 4-3 5-3
1-4 2-4 3-4 4-4 5-4
1-5 2-5 3-5 4-5 5-5
Вот такая матрица!

Цикл WHILE.

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

while (выражение_истинно) do действие;

Пример:

myint:=1;
while myint<=128 do
begin
write(myint, ' '); myint:=myint*2;
end;
writeln('Цикл завершен! Текущее значение myint = ', myint);

Результат выполнения программы показан ниже:

1 2 4 8 16 32 64 128
Цикл завершен! Текущее значение myint = 256

Обратите внимание, что последнее значение в ряду цифр - 128, потому что когда мы умножили 128 на 2 и получили 256, новый круг цикла не мог начаться, так как (256<=128) = false. Еще важно отметить, что при изначальной ложности выражения, указанного между while и do, цикл вообще не выполнится ни одного раза.

На этом можно завершить обзор основ программирования на Turbo Pascal для геокешеров. Разумеется, данный язык имеет много других полезных средств для быстрой и удобной разработки программ, но на эту тему пишут многотомные учебники, мне же пришлось ограничиться только тем, что вам в действительности понадобится для взятия данного тайника. Если у вас появился интерес к программированию, вы вполне можете скачать или купить учебники по Си++ или Delphi (аналог Pascal для программирования под Windows) и углубить свои знания.

-= EOF =-

Читать интернет-блокнот посетителей тайника.
Другие интересные тайники от tol.