Здесь использован новый оператор halt. Он завершает выполнение программы.
"Защиту от дурака" надо использовать во всех мало-мальски серьёзных программах. Используйте её во всех своих программах, ведь вы потихоньку теряете статус начинающего программиста!
5.6. Вложенные условные операторы
Оператор, записанный в условном предложении после then или else, тоже может быть условным оператором. Так получаются вложенные условные операторы.
Например:
ProgramMaximal_of_3_numbers;
Var a, b, c : integer;
write (’Введите три числа через пробел: ’);
readln (a, b, c);
write (’Максимальное число – ’);
if a > b
Then if a > c { Случай, когда a > b }
Then writeln (a)
Else writeln (c)
Else if b > c { Случай, когда a <= b }
Then writeln (b)
Else writeln (c) ;
End.
В этом примере оператор writeln(a) выполнится только в том случае, если а будет больше b, и a будет больше c.
5.7. Оператор выбора Case
Попробуйте самостоятельно решить такое задание:
Дан номер месяца m. Вывести на экран название этого месяца.
Если бы вы начали решать это задание, то столкнулись бы с необходимостью много раз использовать условный оператор:
if m = 1 then write (’Январь’);
if m = 2 then write (’Февраль’);
if m = 3 then write (’Март’);
и так далее.
В таких случаях значительно удобней использовать оператор выбора Case.
Формат записи оператора case:
Case <переменная> of
<список1 возможных значений> : <оператор1> ;
<список2 возможных значений> : <оператор2> ;
...
<списокN возможных значений> : <операторN> ;
else<операторN+1>
Здесь <список возможных значений> - одно или несколько значений, разделенные запятыми, которые может принимать <переменная>.
Оператор выбора Case работает так. Сначала компьютер берёт значение переменной, которая записывается после служебного слова case, и проверяет, входит ли она в <список1 возможных значений>. Если да, то выполняется <оператор1>, после чего выполнение оператора выбора заканчивается. В противном случае, компьютер проверяет, входит ли значение переменной в <список2 возможных значений>. Если да, то выполняется <оператор2>, после чего выполнение оператора выбора заканчивается. В противном случае проверка продолжается дальше до тех пор, пока есть списки возможных значений. Если значение переменной не вошло ни в один из этих списков, то выполняется <операторN+1>, записанный после слова else.
Как и в условном операторе, в операторе выбора строка со словом else и оператором может отсутствовать. Это будет укороченный вариант записи оператора выбора.
Вернёмся к списку возможных значений. В нём можно указывать не только отдельные числа, но и целые промежутки, например, следующие <списки возможных значений> идентичны, хотя записаны по разному:
1, 2, 3, 4, 7, 8
1..4, 7, 8
1..4, 7..8
8, 2..4, 1, 7
Вспомним задачу, сформулированной вначале. Смотрите, как просто она решается с оператором выбора!
Program All_months;
Var mesiac : integer;
Write (’Введите номер месяца: ’);
Readln (mesiac);
case mesiac of
1 : write (’Январь’);
2 : write (’Февраль’);
3 : write (’Март’);
4 : write (’Апрель’);
5 : write (’Май’);
6 : write (’Июнь’);
7 : write (’Июль’);
8 : write (’Август’);
9 : write (’Сентябрь’);
10 : write (’Октябрь’);
11 : write (’Ноябрь’);
12 : write (’Декабрь’);
else write (’Задан неверный номер месяца.’)
end { Если mesiac не совпал ни с одной переменной }
end.
Теперь сами попробуйте составить программу, которая по заданному номеру месяца выведет время года.
Ниже показан один из способов решения этой задачи. В нём продемонстрированы все особенности оператора выбора.
Program Vremena_goda;
Var mesiac : integer;
Write (’Введите номер месяца: ’);
Readln (mesiac);
case mesiac of
3, 4, 5: write (’Весна’);{Можно перечислить все возможные значения}
6 : write (’Лето’); { Можно указать только одно значение }
7 : write (’Лето’); { Можно указать только одно значение }
8 : write (’Лето’); { Можно указать только одно значение }
9..11 : write (’Осень’); { Можно задать промежуток }
1..2,12: write (’Зима’);
else write (’Задан неверный номер месяца.’)
{ Если mesiac не совпал ни с одной переменной }
end.
Остаётся добавить, что если в оператора case после двоеточия нужно указать более одного оператора, то надо использовать составной оператор.
5.8. Самостоятельные задания
Во всех заданиях используйте «защиту от дурака», если это уместно.
· Составить программу, которая запрашивает два положительных числа и находит наибольшее.
· Дано два чётных числа. Вывести сначала то, что меньше, потом то, что больше.
· Найти сумму цифр введенного трёхзначного числа.
· Дано два целых числа: a, b. Найти:
a) min (a, b) ;
b) max (a+b, a–b) ;
c) min (a*b, a+b, 2*a–b) .
· Даны длины трёх отрезков. Определить, можно ли из них составить треугольник.
· Ввести с клавиатуры дату (день, месяц, год), записать ее, назвав месяц словами. Например: Введите день месяц год через пробел: 22 9 1978 Это 22 сентября 1978 года!
· Придумать интересное задание на использование оператора case.
6.Стандартные типы переменных
6.1. Общий обзор стандартных типов.
До сих пор мы работали только с переменными целого типа. Сейчас мы кратко познакомимся со всеми стандартными типами. Более подробно они будут рассмотрены далее. В нижеследующей таблице приведены характеристики всех стандартных типов.
Таблица5. Стандартные типы
Вид типа
Имятипа
Диапазон возможных значений
Объём памяти
Значащих цифр
Целые типы
Byte
0 … 255
1 байт
-
Shortint
-128 … 127
1 байт
-
Word
0 … 65535
2 байта
-
Integer
-32768 … 32767
2 байта
-
Longint
-2147483648…2147483647
4 байта
-
Веществен-ные типы
Single
1.5e-45 … 3.4e38
4 байта
7 – 8
Real
2.9e-39 … 1.7e38
6 байт
11-12
Double
5.0e-324 … 1.7e308
8 байт
15-16
Extended
3.4e-4932 … 1.1e4932
10 байт
19-20
Comp
-263 … 263-1
8 байт
целые числа
Логический тип
Boolean
False и True
1 байт
-
Символьные типы
Char
один любой символ
1 байт
-
String
Строка символов
256 байт
-
6.2. Целые типы
Для разных целей нужны разные диапазоны возможных значений. Скажем, если в переменной хранится возраст человека в годах, то для хранения этого значения вполне достаточно интервала от 0 до 150. Для того чтобы разумно распределить память компьютера используют различные целые типы.
6.2.1. Тип byte
Переменная этого типа может принимать значения от 0 до 255. Если вы попробуете присвоить ей большее значение, то компьютер вместо этого значения возьмёт остаток от деления на 256. Это происходит из-за того, что в представлении компьютера числа идут «по кругу» и после 255 идёт 0. Эmоm нюанс иллюстрирует программа, которая пытается прибавить к 250 число 10.
Program Byte_Example;
Var b : byte;
b := 250;
writeln (b);
{$R-} { Выключить проверку границ, см. ниже }
b := b + 10;
writeln (b);
End.
На экране будут напечатаны два числа: 250 и 4. На самом же деле, 250+10=260. Это число в переменной типа byte компьютер запомнить не может, потому записывает 260 mod 256 = 4. Эти опасные случаи надо учитывать, создавая свои программы.
Впрочем, компьютер может сам следить за этим. Вы наверное уже обратили внимание на строку {$R–}. Это директива компилятору. Она используется для того, чтобы компилятор знал каким способом компилировать программу. В данном случае он отключает проверку на превышения границ. Если вместо этого написать {$R+}, то программа напечатает только одно число 250, после чего компьютер выдаст сообщение об ошибке: "Range check error" – превышение границ. Это позволяет избежать ошибок связанных с переполнением, однако при такой проверке программа работает немного медленней.
Так зачем же надо использовать тип byte, если он имеет такой маленький диапазон значений? Ответ прост: для экономии памяти. Переменная такого типа занимает в памяти компьютера всего 1 байт.
6.2.2. Тип shortint
Этот тип также позволяет сохранять только 256 разных целых чисел, но уже и с отрицательными значениями. Его диапазон от –128 до 127. В памяти компьютера этот тип также занимает один байт. При переполнении (попытке записать число, выходящее за диапазон возможных значений) компьютер начнёт считать от –128. Например, в его «арифметике»: 127 + 1 = –128, поэтому:
127 + 10 = (127+1) + 9 = –128 + 9 = –119.
Имейте это ввиду!
6.2.3. Тип word
Если целой переменной выделить не 1 байт, а 2 байта, то она сможет принимать в 256 раз больше разных значений, то есть числа от 0 до 65535 (65536 = 2562). При попытке присвоить такой переменной большее значение, будет использован лишь остаток от деления на 65536.
6.2.4. Тип integer
Integer – первый тип, с которым мы познакомились. Уже упоминалось, что он позволяет хранить числа от –32768 до 32767. Для этого типа есть даже специально определённая константа maxint, которая хранит максимальное целое число, представимое этим типом. Попробуйте выполнить:
Program Maxint_Demo;
Writeln (maxint); { Напечатает 32767 }
end.
Однако избавиться от переполнения условием
if a > maxint
Then ... ...
невозможно, так как если переменная a имеет тип integer, то она не может быть больше, чем maxint. А при попытке записи большего значения получится неверный результат. Поэтому если ваша программа выдаёт заведомо неверный ответ (слишком маленький или даже отрицательный), первым делом проверьте, не происходит ли переполнения. Для контроля ставьте автоматическую проверку переполнения. Если в самом деле причина в этом, то задайте другие начальные данные или используйте целый тип longint.
6.2.5. Тип longint
Это целый тип, который работает с самым большим диапазоном
от –2147483648 до 2147483647
Максимальное значение хранится в константе maxlongint. Этого диапазона хватает для многих практических целей, но для хранения переменной этого типа необходимо уже 4 байта.
6.3. Вещественные типы
Переменные этого типа могут хранить рациональные (дробные) числа с разной степенью точности. Точность зависит от выбранного типа. Всего существует 5 вещественных типов. В таблице №5 наглядно показано, какой тип какой точностью обладает и сколько ему требется памяти.
6.3.1. Способ записи вещественных чисел
Запись вещественных чисел отличается от записи целых. Вещественное число, как известно, состоит из целой и дробной части. Они разделяются не запятой, как в математике, а точкой. Причём десятичная точка должна быть использована в любой вещественной константе, даже если задаётся целое число (так как иначе компьютер не сможет отличить константу целого типа от константы вещественного типа).
Например: 2.2 2.0 0.35 12.84 0.3333
Ещё раз обратите внимание, что запись 2.0 обозначает вещественную константу, а просто 2 – целую.
Вещественные числа можно ещё записывать в стандартном виде с использованием степени числа 10. Эта форма удобна для записи очень больших и очень маленьких чисел. Числа в стандартном виде записываются в таком формате:
<мантисса> ∙ 10<порядок> — в математике
<мантисса>e<порядок> — в информатике
Число состоит из двух частей: мантиссы и порядка. Например:
5,32 ∙ 106 = 5,3 ∙ 1000000 = 5 320 000,0
Здесь 5,32 – мантисса, а 6 – порядок числа.
В Паскале сначала записывается мантисса, потом ставится английская буква e, после которой указывается порядок числа, то есть на какую степень числа 10 надо умножить мантиссу, чтобы получить значение записываемого числа:
5.32e6 – эта запись обозначает число, равное 5,32 ∙ 106
2.12e-5 – эта запись обозначает число, равное 2,12∙10 –5 = = 2,12 ∙ 0,00001 = 0,0000212
Мантисса числа всегда больше либо равна 1, но меньше 10 (за исключением представления числа 0,0 = 0.0e0).
Разберите ещё несколько примеров перевода чисел из обычной формы записи в стандартную. Обратите внимание на запись отрицательных чисел.
45.2 = 4.52e1
1235.0 = 1.235e3
100.0 = 1.0e2
5.0 = 5.0e0
0.03 = 3.0e-2
0.0012 = 1.2e-3
0.0 = 0.0e0
25000.0= 2.5e4
-28.17 =-2.817e1
-1.0 =-1.0e0
Закройте один из столбиков и поупражняйтесь в переводе чисел из стандартной записи в обычную и наоборот, контроллируя свои результаты.
Решите следующие примеры. Для этого переведите числа в обычную форму, сложите их и запишите результат в стандартном виде. В конце пункта 6.3 найдёте ответ.
1) 2.2e1 + 3.08e2 = ?
2) 5.53e15 + 2.34e14 = ?
3) 2.11e-10 + 1.01e-12 = ?
4) 1.52e10 + 2.42e-8 = ?
6.3.2. Вывод на экран вещественных чисел
Нет ничего удивительного в том, что вещественные числа можно выводить на экран оператором writeln. Наберите и запустите следующую простую программку, которая выводит на экран вещественное число.
program Real_Writing_Demo;
var d : real;
d := 575.22;
writeln (d);
end.
И вот тут начнутся неожиданности. Вместо ожидаемого «575.22» на экране появится «абракадабра»:
5.75219999999739E+0002
Однако, если внимательней присмотреться, то можно заметить, что это и в самом деле наше число, но «округленное» и записанное в стандартном виде. «Округление» происходит из-за особенности представления числа в памяти, более подробно об этом будет рассказано в следующем пункте.
Для того чтобы компьютер печатал число в более привычном для нас виде, надо сообщить ему об этом следующим образом:
writeln (d : <всего символов> : <дробная часть>);
Параметр <всего символов> показывает, сколько надо выделить символов (знакомест, позиций) экрана для вывода числа, а параметр <дробная часть> – сколько знаков после десятичной точки необходимо отобразить. Этот способ вывода называет форматированным выводом.
Если в предыдущем примере оператор вывода сделать форматированным:
writeln (d : 6 : 2);
то компьютер напечатает долгожданное
575.22
Можно ещё поэкспериментировать с этими параметрами вывода на экран вещественного числа. Только надо знать, что если вы зададите слишком маленькое значение параметра <всего символов> и число не влезет в ваше прокрустово ложе, то оно займёт больше места на экране. Если же вы выделите для числа места больше, чем ему необходимо, то слева к этому числу будет добавлены пробелы: столько, сколько не хватает длине числа до выделенного вами места. Параметр <дробная часть> можно менять как угодно, компьютер в каждом случае будет соответствующим образом округлять число. Если этот параметр будет слишком большим, то к дробной части числа компьютер добавит необходимое количество нулей. Можно также задать значение 0 – на экране напечатается только целая часть числа.
Вот несколько примеров, иллюстрирующих всё сказанное (для наглядности символ пробела здесь обозначается квадратиком □):
Таблица6. Форматированный вывод
Оператор
Результат выполнения
Write(48024.32:10:3);
□48024.320
Write(405.39:10:3);
□□□□□405.4
Write(1024.0:10:7);
1024.0000000
Write(-869.91:5:0);
□-870
Write(0:10:1);
□□□□□□□0.0
Write(67222.4445:10:3);
□67222.445
Примечание. Форматированный вывод можно употреблять и для целых чисел. Но для них задаётся только один параметр – <всего символов>.
6.3.3. Точность и диапазон вещественных чисел различных типов
Теперь поговорим о точности и диапазоне чисел вещественного типа. Под точностью понимают число значащих цифр (см. соответствующий столбец в таблице №5). В мантиссе не должно быть цифр больше, чем это возможно для данного типа. В противном случае число будет округлено. Например:
program Single_Demo;
var d : single; { вещественный тип с точностью 7-8 цифр }
d:=9.87654321e5;{попытка записать число с мантиссой из 9 цифр}
writeln (d);
end.
Эта программа печатает на экран:
9.87654312500000E+0005
На первый взгляд кажется, что запомнено достаточно много цифр, но при детальном анализе выясняется, что точно записаны лишь 7 первых цифр. Если вместо типа single использовать тип real, то получим следующий результат:
9.87654321000099E+0005
Как видите, точность первых 11 цифр обеспечена (такую точность и гарантирует тип real), однако та небольшая погрешность, которая возникает в результате «машинного округления» может немного повлиять на точность результата. Для точных вычислений лучше всего, конечно, использовать тип double или extended. Они великолепно проходят этот небольшой тест:
9.87654321000000E+0005
Теперь поговорим о диапазоне возможных значений. В таблице указано, какое максимальное и минимальное положительное значение позволяет записать каждый тип. Другими словами – это допустимый диапазон порядка числа. При попытке сохранить значение больше максимального произойдет ошибка «Floating point overflow» - «переполнение в операции с плавающей точкой». При попытке сохранить значение меньше минимального[4], появится так называемый «машинный нуль» – компьютер посчитает это значение равным нулю.
6.3.4. Тип comp
Об этом вещественном типе стоит поговорить особо… Дело в том, что этот тип по своей сути является целым, но с очень большим диапазоном значений. А именно:
от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807,
всего 18 446 744 073 709 551 615 возможных значений.
Посмотрите внимательно на последнее число! Именно столько зёрен пшеницы должен был выдать падишах Индии изобретателю шахмат по легенде. Изобретатель попросил за первую клетку шахматной доски одно зерно пшеницы, за вторую – две, за третью – четыре. И так далее: за каждую следующую – в два раза больше, чем за предыдущую. Падишах только посмеялся над столь мизерной просьбой, сказав: «Житницы мои не оскудеют! Завтра тебе вынесут твой мешок пшеницы». Однако такого количества зёрен не найдётся и на всей матушке-земле. Теперь я надеюсь вам ясно, что этого типа данных вполне хватит для практических целей. Кстати, именно из-за такого гигантского диапазона его и отнесли к вещественным типам.
6.3.5. Вещественные функции
Так как вещественные числа охватывают всё множество действительных чисел, то для них существует значительно больше стандартных функций, нежели для целых чисел. Все они, вместе с обычными математическими операциями, перечислены в таблице.
Таблица7. Математические операции и функции
Название
Обозначение
Способ записи
Сложение
x + y
x + y
Вычитание
x – y
x – y
Умножение
x ∙ y
x * y
Деление
x / y
x / y
Квадратный корень
Ö x
sqrt (x)
Квадрат числа
x2
sqr (x)
Модуль числа
| x |
abs (x)
Синус
sin x
sin (x)
Косинус
cos x
cos (x)
Тангенс
tg x
tan (x)
Арктангенс
arctg x
arctan (x)
Степень числа e
ex
exp (x)
Натуральный логарифм
ln x
ln (x)
Целая часть
[x]
int (x)
Дробная часть
{x}
frac (x)
Случайное число от 0 до 1
random
Возведение в степень
xy
Нет[5]
Примечание 1: тригонометрические функции работают с углами, выраженными в радианах.
Примечание 2: все эти функции работают только с вещественными переменными. Для целых переменных можно использовать только sqr и abs, а также операции +, –, * (об этом говорилось ранее).
6.3.6. Линейная запись математических выражений
Математические выражения на языке Паскаль должны быть записаны в так называемой линейнойзаписи, которая состоит из цепочки символов без всяких индексов, например, вместо x1, x2 надо писать x1, x2.
Надо уметь переводить любую формулу из обычной записи в линейную и наоборот. Например:
Выполните следующие два упражнения:
1. Перевести из линейной записи в обычную:
1. (a+b)/c
2. a+b/c
3. a/b/c
4. 1/sqr(1+x)
5. 1/sqrt(1+x)
6. a+b/c+d
7. (a+b)/(c+d)
8. arctan(x/sqrt(1-x*x))
9. 2*sin((a+b)/2)*
10. sqr(sin(abs(x+int(x)))/
cos((a-b)/2)
2*x)
2. Перевести из обычной записи в линейную:
Ответ на задание к пункту 6.3.1:
1) 3.3e2, 2) 5.764e15, 3) 2.1201e-10,
4) 1.52e10 (маленькое число почти не влияет на результат).
6.4. Логический тип
Условия, которые мы записывали после слова if, оказывается тоже можно сохранять. Для этого существуют переменные логического типа boolean. Например:
Program Boolean_Variable;
var b : boolean ;
b := 23 > 10 ; { b = true }
writeln (b) ;
end.
Выражение 23>10, как вы уже знаете, называется высказыванием или условием. Оно может быть истинно или ложно. Переменные логического типа могут принимать только два значения: True и False, то есть "истина" и "ложь". Поэтому нет ничего удивительного в таком операторе присваивания, ведь здесь переменная b определена логическим типом в разделе описания.
Над логическими переменными можно производить такие же действия, как и над условиями. Можно также выводить на экран значения логических переменных, используя оператор write. А вот вводить значения логических переменных оператором readln нельзя. Смыслу этого абзаца уместно вторит нижеследующая программа:
Program Boolean_Demo;
var b1, b2 : boolean;
b1 := 5 >= 3; { b1 = True }
b2 := not b1; { b2 = False }
ifb1 { так как b1 может быть истинно или нет, }
{ то его можно использовать вместо условия }
then writeln (b2); { Напечатается False }
b1 := b1 or b2; { b1 = True or False = True }
writeln (b1) { Напечатается True }
end.
Так как логическая переменная может хранить одно из двух значений True или False, то для хранения её значения достаточно 1 бита, но для удобства реализации в памяти компьютера ей выделяется 1 байт.
6.5. Символьные типы
До сих пор мы работали только с числами. Строчки нам встречались только в операторе write при выводе сообщений на экран. Теперь мы научимся работать со строчками и отдельными символами.
6.5.1. Тип string
Этот тип предназначен для хранения строк. Вспомним ещё раз, как мы употребляли в операторе write строчки или, по-научному, string-константы:
write (’Какой чудесный день! Какой чудесный пень!’);
Здесь строкой является весь текст, заключенный в апострофы. Таким способом, правда, не удастся в строке задать сам апостроф, так как компьютер под этим символом подразумевает либо начало, либо конец строки. Для использования апострофа в строке надо написать его два раза, например:
оператор
write (’Don’’t worry!’);
напечатает:
Don’t worry!
Итак, если мы опишем переменную типа string, то мы сможем сохранять в этой переменной строки текста:
Program String_Example;
var s1, s2 : string ;
s1 := ’Тра-ля-ля!’;
s2 := ’А вот и я!’;
writeln (s2);
writeln (s1);
writeln (s1, s2)
end.
Эта программа напечатает следующее:
А вот и я!
Тра-ля-ля!
Тра-ля-ля!А вот и я!
В строке может быть записано от 0 до 255 символов. Строка длиной 0 символов называется пустой и обозначается парой кавычек, между которыми нет других символов: ’’.
Строки можно не только выводить на экран, используя оператор write, но и вводить с клавиатуры оператором Readln. Например:
ProgramString_Example2;
Var s, otvet :string;
Write (’Введите ваше имя: ’);
Readln (s); { Ввод строки символов }
If s = ’’ { Введена пустая строка (просто нажали Enter) }
Then s:=’Ипполит Матвеевич’; { … если имя введено не было }
Write (s, ’, вас поздравить с Новым годом? (d/n) ’);
Readln (otvet);
If otvet = ’d’
Then writeln (s, ’! Поздравляю вас с Новым годом!’)
Else writeln (’Не хотите, как хотите...’);
End.
Работа с этой программой может происходить так:
Введите ваше имя: Женя
Женя, вас поздравить с Новым годом? (d/n) d
Женя! Поздравляю вас с Новым годом!
6.5.2. Стандартные функции для работы со строками
Строки сами по себе не представляли бы наверное большого интереса, если бы не существовало средств для их обработки. Рассмотрим самые полезные функции для работы со строками.
Одна из главных характеристик строки – это её длина. Длину строки можно вычислить с помощью функции
Length (st)
Например:
Length (’kolobok’) - результат 7 ;
Length (’’) - результат 0.
Любые две cтроки можно сложить (склеить). Для этого используется знак операции +. Например:
st := ’Д’ + ’a’ ; { st = ’Да’ }
st := st + ’ или нет.’; { Теперь st = ’Да или нет’ }
В одной строчке можно склеивать сразу несколько строк, например:
Program Plus_Demo ;
var s1, s2 : string;
s1 := ’Мир ’; { Обратите внимание на пробел в конце! }
s2 := s1 + s1 + ’и еще раз ’ + s1 + ’!’ ;
writeln (s2); { Напечатается: Мир Мир и еще раз Мир! }
end.
Следующая важная функция для выделения подстроки (т. е. части строки)
Этой функции, как вы видите, требуется три аргумента. Первый – строка символов – переменная типа string, из которой и производится «выуживание» подстроки; следующий параметр – <первый символ> – целое число, указывающее, начиная с какого символа надо начинать выделение подстроки; последний параметр – <сколько символов> – задаёт длину выделяемого фрагмента строки.
Например:
Program CopyDemo;
vars1, s2 : string;
s1 := 'doroga';
s2 := copy (’doroga’, 3, 4);
writeln (s2); { Будет напечатана строка ’roga’ }
end.
В этом примере из слова doroga выделяется 4 символа, начиная с третьего.
Вот ещё один пример:
program Copying;
var s1, s2 : string;
s1 := ’Раз Два Три!’;
s2 := copy (s1, 5, 3);
writeln (s2) { ’Два’ }
end.
Едем дальше. При помощи квадратных скобок можно обратиться к одному символу строки:
st [<номер символа>]
Например, если st = ’Раз Два Три!’ , то:
st[1] равно ’Р’,
st[2] равно ’а’,
st[3] равно ’з’,
st[9] равно ’Т’.
Номером символа может быть и переменная целого типа, например:
program SymbolsNr;
var s : string;
i : integer;
s := ’Красота!’;
i := length (s); { Вычисление длины }
writeln (s[i]) { Напечатается '!' }
end.
Используя квадратные скобки можно не только читать значение указанного символа, но и записывать на его место новый символ. Например:
st:= ’Раз Два Три!’; { st = ’Раз Два Три!’ }
st [4] := ’-’; { st = ’Раз-Два Три!’ }
st [8] := ’-’; { st = ’Раз-Два-Три!’ }
st [1] := ’Щ’; { st = ’Щаз-Два-Три!’ }
6.5.3. Тип Char
Символ – это любая буква, цифра, пробел или значок, который можно вывести на экран компьютера.
Переменные типа char могут хранить только один какой-нибудь символ. Символы на языке Паскаль записываются при помощи одинарных кавычек.
Например:
’a’ - символ – маленькая латинская буква а,
’Б’ - символ – большая русская буква б,
’$’ - символ – знак доллара,
’”’ – символ – двойная кавычка,
’’’’ - символ – одинарная кавычка.
Примеры ошибочного определения символа:
’zx’ – вместо одного символа – два.
”a” - символ должен быть в апострофах, а не в кавычках.
& - символ должен быть в кавычках, а не просто так.
’’ - так обозначается пустая строка. Длина пустой строки ноль символов, а не один.
Вы наверняка знаете, что каждый символ имеет свой собственный код от 0 до 255 (в так называемой кодовой таблице ASCII). Поэтому любой символ можно задать по его коду в таблице ASCII. Для этого ставится значок решётки #, после которого пишется номер символа (в десятичной системе счисления), например:
#33 символ ’!’;
#65 символ ’А’;
#255 символ с кодом 255.
Для любопытных приведу фрагмент таблицы ASCII, может пригодится.
Так как каждый символ имеет свой собственный код, то их можно сравнивать друг с другом. Считается, что символы равны, если равны их коды. Из двух символов больше тот, чей код в таблице ASCII больше. Поэтому хоть внешне некоторые символы похожи (например: ноль и буква О, русская В и английская B) или имеют одну и ту же смысловую нагрузку (например, большая и маленькая буква d), но для компьютера они являются разными символами.
Вот пример программы с переменной типа char.
ProgramChar_Example;
Var c : char;
Write (’Вас поздравить с Новым годом? (d/n)’);
Readln (c); { Ввод одного символа }
If (a = ’d’) or (a = ’D’)
then writeln (’Поздравляю вас с Новым годом!’);
End.
В этой программе оператором readln с клавиатуры вводится какой-нибудь символ. Предполагается, что это будет символ ’d’ или ’n’. В программе предусмотрен случай ввода большой буквы D.
6.5.4. Стандартные функции для типа char
Есть несколько функций для работы с переменными типа char. Самая простая из них – это функция
UpCase (ch)
Эта функция переделывает строчную английскую букву в заглавную. Если аргумент не является буквой, символ остается без изменения. Например:
UpCase (’a’) результат ’A’
UpCase (’#’) результат ’#’
UpCase (’ф’) результат ’ф’
(функция обрабатывает только английские буквы)
Вот как можно использовать эту функцию в предыдущей программе:
ProgramChar_Example2;
Var c : char;
Write (’Вас поздравить с Новым годом? (d/n)’);
Readln (c); { Ввод одного символа }
If UpCase (a) = ’D’
then writeln (’Поздравляю вас с Новым годом!’);
End.
Как видите, здесь пользователь может ввести как маленькую букву d, так и большую. Компьютер всё равно поймёт правильно.
Следующая функция
Ord (ch) определяет код символа. Каждый символ, имеет свой номер от 0 до 255.
Например: Ord (’A’) равно 65. То есть символ А имеет код 65.
Обратная ей функция
Chr (nr) находит символ по его коду.
Например:
Chr (65) равно ’A’,
Так как функции ord и chr взаимно обратные, то
Ord (Chr (83)) равно 83,
Chr (Ord (’S’)) равно ’S’.
1.Подпрограммы
1.1. Зачем нужны подпрограммы?
В практике программирования часто встречаются случаи, когда по ходу выполнения программы приходится производить однотипные вычисления, с различными исходными данными. Чтобы исключить повторение одинаковых записей и сделать тем самым программу проще и понятнее, можно выделить эти повторяющиеся вычисления в самостоятельную часть программы, которая будет использоваться многократно по мере надобности. Такая отдельная часть программы, допускающая обращение к ней из различных частей основной программы, называется подпрограммой.
Подпрограммы оформляются в виде замкнутых участков программы, имеющих чётко обозначенные вход и выход. Самостоятельный характер подпрограмм позволяет поручать их составление различным авторам. При этом осуществляется разделение работы по программированию и ускоряется разработка программного продукта. Для удобства этой работы имена переменных в основной программе и в подпрограммах не зависят друг от друга. Если, например, в основной программе фигурирует переменная с именем А, то переменная с таким же именем А, но используемая в подпрограмме, может иметь совершенно другое значение, никак не связанное со значением переменной А в основной программе.
Этим не исчерпываются положительные стороны применения подпрограмм. Можно ещё указать на экономию памяти, так как память для хранения переменных, используемых в подпрограммах, выделяется только на время её работы и освобождается, как только заканчивается её выполнение; кроме того, сам код подпрограммы хранится в единственном экземпляре, а не повторяется для каждого её вызова.
Использование подпрограмм позволяет реализовать один из самых прогрессивных методов программирования – структурное программирование.
В языке Паскаль выделяют два вида подпрограмм: процедуру (Procedure) и функцию (Function).
1.2.Процедуры
Процедура – эта независимая часть программы, которая имеет своё имя. По этому имени её можно вызывать из различных участков программы для выполнения записанных в ней действий. Структура процедуры повторяет структуру программы:
Формат записи процедуры:
procedure<Имя> ; { заголовок процедуры }
... ... { секция описаний процедуры }
... { операторы }
end;
В программе процедуры записываются сразу после описания переменных:
program Р;
{pаздел описаний данных основной пpогpаммы Р}
procedure К;
{pаздел описаний пpоцедуpы К}
{pаздел опеpатоpов пpоцедуpы К}
end;
{pаздел опеpатоpов основной пpогpаммы Р}
end.
В секции описаний процедуры могут быть описаны локальные переменные[6], локальные константы и другие элементы (в том числе и внутренние процедуры и функции).
Пример. Давайте составим программу с процедурой, которая будет приостанавливать работу программы.
programProcedure_Demo;
vara, b, s : integer;
procedure Pausa;
{так как в процедуре не используются переменные, секция описаний пропущена}
writeln (’Нажмите ENTER для продолжения!’);
readln;
end;
write (’Введите первое число: ’);
readln (a);
a := a*a;
writeln (’Квадрат этого числа равен: ’, a);
Pausa;{ Вызов процедуры Pausa }
write (’Введите второе число: ’);
readln (b);
b := b*b;
writeln (’Квадрат этого числа равен: ’, b);
Pausa;
s := a + b;
writeln (’Сумма квадратов введенных чисел равна ’, s);
Pausa;
end;
Команды вызова процедуры из основной программы подчёркнуты. Когда компьютер при выполнении этой программы дойдет до строчки Pausa он начнет выполнять те действия, которые записаны в процедуре Pausa, то есть выведет на экран строчку и будет ждать нажатия клавиши Enter. После завершения работы процедуры компьютер продолжит выполнять программу с того места, откуда была вызвана подпрограмма.
1.3.Аргументы процедуры
В процедуры можно передавать аргументы (параметры) – своего рода начальные данные для процедуры. Вот как изменится от этого заголовок процедуры:
Procedure Name (arg1 : type_arg1; arg2 : type_arg2; ... );
где argN – имя переменной-аргумента, type_argN – тип этой переменной (integer, real, string и т.д). Если среди аргументов есть несколько переменных одного типа, то их можно все перечислить через запятую, а потом указать тип:
Procedure Primer (a, b : integer; s : real);
Описанные в заголовке переменные используются в процедуре как обычные переменные. Например:
ProgramWith_Procedure_Summa;
Var x, y : integer;
Procedure Summa (a, b : integer);
var s : integer; { использована локальная переменная }
s := a + b;
writeln (’Сумма чисел ’, a, ’ и ’, b, ’ равна ’, s);
end;
Summa (4, 7);
write (’Введите два числа: ’);
readln (x, y);
Summa (x, y)
end.
Как видите, для вызова такой процедуры надо после её имени указать в скобках значения, которые будут переданы в процедуру. Это могут быть как конкретные числа, так и переменные.
Во время выполнения этой программы на экране будет напечатано:
Сумма чисел 4 и 7 равна 11
После этого компьютер запросит ввод двух чисел, сложит их и выведет сумму на экран.
1.4.Результаты процедуры
Процедура может ещё обладать результатами – это значения, которые возвращаются из процедуры в программу. В предыдущем примере у процедуры тоже был результат – сумма двух чисел. Однако он нигде не сохранялся, а только выводился на экран.
Чтобы оформить переменную-результат, надо в заголовке процедуры перед описанием переменной-результата приписать слово var. Вот пример полной программы с процедурой Summa, у которой два аргумента и один результат.
ProgramProcedure_with_arguments_and_result;
Varp, q, r : integer;
Procedure Summa (a, b : integer; var s : integer);
s := a + b;
end;
write (’Введите два числа: ’);
readln (p, q);
Summa (p, q, r ); { p,q - аргументы, r - результат }
Writeln (’Сумма введённых чисел: ’, r);
end.
При вызове процедуры переменные a,b внутри процедуры примут те же значения, что и переменные p,q в основной программе. По окончании работы в глобальную переменную r запишется то число, которое будет в переменной s (результате) процедуры.
Попробуйте ответить на вопрос: почему при вызове процедуры в качестве аргументов можно указывать конкретные числа, а в качестве результатов – нет?
Процедура может иметь сколько угодно аргументов и сколько угодно результатов. Главное, при вызове процедуры строго соблюдать порядок следования всех параметров!
Вот ещё один пример, который запрашивает координаты концов отрезка и находит координату точки, которая делит этот отрезок в отношении 1:3. Здесь используется процедура Seredina для нахождения середины отрезка, по заданным координатам его концов.
program Geometry;
var ax, ay, bx, by : integer;
cx, cy, dx, dy : real;
Procedure Seredina (x1, y1, x2, y2 : integer;
var x, y : real);
x := (x1+x2) / 2;
y := (y1+y2) / 2;
end;
write (’Введите координаты концов отрезка: ’);
readln (ax, ay, bx, by);
Seredina (ax, ay, bx, by, cx, cy);
{ точка (cx,cy) - середина отрезка ab }
Seredina (bx, by, cx, cy, dx, dy);
{ точка (dx,dy) - середина отрезка bc }
Writeln (’Точка (’, dx, ’, ’, dy,
’) делит отрезок в отношении 1:3’);
Так как процедуры могут возвращать результаты в виде переменных, то отпадает необходимость выводить их на экран внутри процедуры. Мало того, это опасно делать, так как если ваша процедура будет вызываться много раз подряд, то представьте, сколько ненужных промежуточных данных будет выведено на экран!
Запомните: подпрограммы должны только вычислять, и ничего лишнего не выводить на экран!!!
1.5.Функции
Другой вид подпрограммы – функция оформляется, в таком виде:
Function <имя> (<параметры>): <тип>;
... ... { секция описаний функции }
... { раздел операторов }
End;
Отличительные особенности функции:
1. функция имеет только один результат (но может иметь несколько входных параметров – аргументов);
2. вызывать функции можно только из выражений;
3. результат обозначается именем функции и передаётся в вызываемое место.
Во всём остальном функция похожа на процедуру: она может иметь локальные переменные, обладает аргументами, можно даже оформлять дополнительные результаты так же, как и у процедуры.
Пример описания функции:
Function min (a, b : integer) : integer;
Ifa > b
then min := a
else min := b
end;
Функция находит меньшее из двух целых чисел. Здесь min - имя функции, оно же является одновременно и результатом этой функции – целое число. Формальными параметрами (аргументами функции) являются переменные целого типа a и b. Вызывается функция по своему имени с указанием фактических параметров. При этом вызов функции нужно делать непосредственно внутри выражения, например:
y := min(x,y) + min(k,l);
Нужно иметь ввиду, что при оформлении функции её результату (то есть её имени) можно только присваивать значения и нельзя его использовать как переменную, так как в этом случае компьютер подумает, что вы хотите этой записью снова вызвать функцию!
Например:
Function SummaCifr (a : integer) : integer;
SummaCifr := a mod 10;
SummaCifr := SummaCifr + a div 10; { Ошибка! }
end;
Эта запись является ошибочной. В таких случаях нужно использовать промежуточные переменные:
Function SummaCifr (a : integer) : integer;
varc : integer;
c := a mod 10;
c := c + a div 10;
SummaCifr := c;
end;
1.6.Самостоятельные задания
1) Составьте программу нахождения суммы двух чисел с использованием функции.
2) Составьте программу нахождения площади круга по заданному целому значению радиуса. Решите это задание двумя способами: с использованием процедуры; с использованием функцией. Обратите внимание на оформление программы, не забывайте, что подпрограммы должны только вычислять, но не выводить сообщений на экран.
3) Составьте процедуру поиска суммы цифр двузначного числа. Если задано не двузначное число, вернуть результат 0.
4) Составить функцию для поиска суммы цифр трёхзначного числа.
2.Циклы
Определение.
Цикл – это структура языка, которая предписывает многократное выполнение указанного оператора.
Говоря проще, цикл - это такой оператор, который заставляет компьютер многократно повторять некоторые действия. Образно это можно записать так: