Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Демидов Основы программирования в примерах на языке ПАСЦАЛ 2010

.pdf
Скачиваний:
128
Добавлен:
16.08.2013
Размер:
1.28 Mб
Скачать

Рис. 1. ASCII-таблица

Примеры использования типа char и функций ord и chr:

var

 

c: char;

 

a, b: byte;

 

begin

 

c := 'Z';

// a = 122

a := ord(c);

b := 32;

// с = ' ' – пробел

c := chr(b);

с := #32;

// тоже самое

write(chr(10)+chr(13));

end.

31

Следует отметить, что в языке Си используется один и тот же тип char для представления чисел от 0 до 255 и символов.

Значениями встроенного строкового типа string, по сути, являются последовательностями значений символьного типа, т.е. строка в Паскале – 0 и более символов, идущих один за другим. Внутреннее представление строк – последовательность байт, причём первый байт отводится для хранения реальной длины строки. Уже упоминалось, что максимальное значение, представимое в ячейке памяти размером в 1 байт, равно 255. Поэтому максимальная длина строки ограничивается 255 символами. Программист может ещё больше ограничить длину строки, указав максимальное число символов при объявлении переменной строкового типа. Строковые константы записываются в одинарных кавычках, как и символьные константы. Для помещения в строку одинарной кавычки (апострофа) его следует записать дважды.

Примеры объявления и задания переменных строкового типа:

var

 

s: string;

 

c: char;

 

fio: string[60];

 

leng: byte;

 

begin

// строка с апострофом

s := 'Don''t do it';

fio := 'Niklaus Wirth';

 

writeln(s + ' ' + fio);

// 'o'

c := s[2];

leng := ord(s[0]);

// определение длины строки

leng := length(s);

// определение длины строки

//Строка с непечатаемыми символами перевода строки

//и возврата каретки

s := 'string 1'#10#13'string 2'; end.

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

32

Структурированные типы данных

Для чего вводятся структурированные типы данных? Любая программа оперирует данными, но данные вовсе не обязаны быть такими же простыми, как числа или символы. В реальности это самые разнообразные структуры, которые программисты пытаются разложить на простейшие элементы и построить программу для их обработки.

Представьте, что нужно представить и обработать результаты сотен измерений температуры. Каждое измерение представимо в виде вещественного числа, но не объявлять же для этого сотни разных переменных? Для этого есть массивы.

Массивы

Массив представляет собой последовательность элементов одного типа. Для объявления массива необходимо указать число и тип элементов массива. Для обращения к элементу массива необходимо указать имя переменной-массива и в квадратных скобках индекс элемента. Например,

var

m, n: array[1..100] of real; x: array[1..100] of real;

begin

for i:=1 to 100 do m[i] := random;

n := m;

// допустимо

x := m;

// недопустимо, при компиляции будет ошибка

end.

 

Здесь число элементов массива указывается с помощью диапазона, причём минимальное число будет соответствовать минимальному индексу элемента, а максимальное – максимальному индексу элемента.

Следует отметить, что при таком объявлении массивов не работает механизм контроля типов, так как типы переменных считаются различными, несмотря на то, что их структура идентична. Поэтому хорошим тоном считается объявление типа-массива:

type

arr = array[1..100] of real; var

m, n, x: arr;

33

При таком подходе переменные можно будет присваивать, передавать в виде параметров в функции и процедуры.

Массивы могут иметь и несколько размерностей. В этом случае необходимо через запятую указать диапазоны индексов для каждой размерности. В частности, для представления матриц 100х200 можно использовать следующее объявление:

type

Matrix = array[1..100, 1..200] of real; var

m: Matrix; begin

// инициализируем элемент 23 строки в 48 столбце m[23,48] := -4.89;

end.

С точки зрения структур данных здесь объявляется двумерная матрица вещественных чисел, у которой 100 строк и 200 столбцов. Для обращения к элементу этой матрицы следует записать что-то вроде m[i, j].

Рассмотрим далее следующий пример:

type

Arr = array [1..200] of real; Matrix = array[1..100] of Arr;

var

m: Matrix; a: Arr;

i,j: integer; begin

//в а копируется 23-я строка матрицы a := m[23];

//48-й элемент в массиве, но не в матрице! a[48] := -4.89;

//48-й элемент 23-его массива матрицы m[23][48] := -4.89;

end.

Казалось бы, массив массивов можно считать матрицей, но это не так. Структурно элементом Matrix здесь является массив, а не вещественное число. Обратите внимание на синтаксические различия в записи при доступе к элементам m.

34

Записи

Представьте, что в программе требуется описать некоторый объект реального мира, например запись в телефонной книжке, и далее работать с ним как с единым целым. Это возможно только с помощью совокупности переменных. В Паскале для этого введён тип-запись, в Си – тип-структура. Для объявления типа-записи следует использовать ключевое слово record и далее описать составляющие запись переменные, которые называются полями записи. Например,

type

phone_rec = record of fio: string[60]; phone: string[20]; e_mail: string[50];

end; var

pr1,pr2: phone_rec; begin

pr1.fio := 'Ivanon Ivan'; pr1.phone := '89169110203'; pr1.e_mail := 'ivanov88@mail.ru'; pr2 := pr1;

writeln('fio: ' + pr1.fio); writeln('phone: ' + pr1.phone); writeln('e-mail: ' + pr1.e_mail);

end.

Доступ к полям записи осуществляется через символ '.' после имени переменной типа-записи. Значением переменной типазаписи является совокупность значений полей записи.

Телефонная книга на 200 номеров может быть определена с помощью массива записей:

type

phone_book = array [1..200] of phone_rec; var

pb: phone_book; begin

pb[i].fio := …

end.

35

Файлы

Понятно, что хранить телефонную книгу в памяти программы неудобно, так как при завершении работы программы все данные будут потеряны. Чтобы избежать утраты данных, необходимо записать их во внешнюю память (жесткий диск). Для этого используются файлы. В языке Паскаль предусмотрены средства для работы с файлами разного типа. Телефонная книга в нашем примере представляет собой последовательность однотипных записей, поэтому удобно объявить типизированный файл.

В языке Паскаль существуют и другие типы данных – последовательности, множества, классы. Первые два используются сравнительно редко, поэтому оставлены на самостоятельное изучение. Рассмотрение классов и объектно-ориентированного подхода в программировании выходит за рамки данного пособия.

36

Глава 4. Присваивание и ветвление

Оператор присваивания

Оператор присваивания – один из базовых в императивном программировании. Происходит он из команды процессора по копированию содержимого одной ячейки памяти в другую (mov в ассемблере). Вот несколько применений оператора присваивания:

инициализация значений переменных;

запоминание (в некоторой области памяти) промежуточных результатов вычислений для последующего использования;

создание копии значения (копии содержимого в области

памяти).

Оператор действует над двумя аргументами: первый аргумент – некоторая переменная, второй – вычислимое выражение. В языке Паскаль оператор обозначается «:=» (двоеточие равно). Обычно используется инфиксная запись оператора, т.е. сначала записывается переменная, затем оператор, а потом – присваиваемое выражение. Например,

beta := 180/n;

height := (0.5 + sin(beta)) * tg(alpha);

При компиляции проверяется соответствие типов выражения и переменной. Если типы не совместимы, то возникает ошибка преобразования типов. Например, нельзя число с плавающей запятой присвоить целочисленной переменной.

Операционная семантика2 оператора присваивания:

1)во время выполнения программы вычисляется присваиваемое выражение по правилам вычисления выражений. Если при вычислении выражения возникает ошибка, то выполнение прекращается;

2)если требуется приведение типов, то оно выполняется, т.е. полученное значение преобразуется в формат типа переменной;

2 Операционная семантика описывает то как следует интерпретировать фрагмент программы в виде последовательности вычислительных шагов.

37

3)если объём области памяти, отведённой для значения переменной, не равен объему, необходимому для хранения нового значения, то память, выделенная под предыдущее значение переменной, возвращается программному окружению, и выделяется область памяти для нового значения переменной;

4)полученное значение помещается в область памяти, вы-

деленную для переменной.

Пояснения:

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

На втором шаге может потребоваться преобразовать, например, число 500 к типу byte, с помощью которого можно представить числа от 0 до 256, тогда возникает ошибка переполнения типа. Если же переменная имеет тип real, то число 500 будет успешно преобразовано в формат числа с плавающей запятой 5.0e+2.

Третий шаг выполняется при присваивании строк или динамических массивов, так как выделяемая область памяти зависит от их текущей длины. Для остальных типов объём памяти, необходимый для хранения значения данного типа, вычисляется еще на этапе компиляции.

Применение оператора связано с побочным эффектом, возникающем на третьем и четвёртом шаге: предыдущее значение переменной безвозвратно теряется. Этот эффект негативно проявляется в случаях, когда память под значение переменной выделяется динамически в самой программе. Если выделенную память не вернуть программному окружению до присваивания, то после присваивания она так и будет считаться занятой и будет потеряна для дальнейшего использования. Это распространённая ошибка программистов приводит к так называемой утечке памяти.

В Java реализован механизм автоматической сборки «мусора», который возвращает неиспользуемые более области памяти программному окружению (менеджеру памяти).

Неявное присваивание

Присваивание может происходить неявно, т.е. без применения оператора присваивания.

38

Рассмотрим пример:

var

a,b: integer;

function Sum(arg1,arg2: integer): integer; begin

Sum := arg1 + arg2; end;

begin

a := 5; b := 3;

writeln(sum(a,b));

end;

В этой программе определена функция суммирования двух чисел, в которой выражение arg1 + arg2 присваивается возвращаемому значению функции. В начале работы программы происходит инициализация значений переменных a и b. Далее на экран печатается значение, возвращаемое функцией sum. При этом функции передаются два аргумента: a и b. В момент вызова функции sum вычисляются аргументы и осуществляется их неявное присваивание локальным переменным функции, т.е. значение переменной a присваивается переменной arg1, а значение переменной b присваивается переменной arg2.

Оператор ветвления if

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

Для чего используется ветвление?

Рассмотрим пример вычисления корней квадратного уравнения ax2+bx+c=0. Как известно, решение существует только в том случае, если дискриминант уравнения неотрицателен, в противном случае под корнем возникнет число меньше 0. В программе это не-

39

допустимо, поскольку приведёт к ошибочному завершению работы программы. Уместно использовать ветвление. На псевдокоде алгоритм для вычисления корней уравнения может выглядеть так:

установить d = b2-4ac

если d >= 0

то

установить x1 = (-b + √d)/2a установить x2 = (-b - √d)/2a

вывести значения x1 и x2 на экран

иначе

сообщить, что корней нет

Конструкция «если – то – иначе» используется для того, чтобы разделить два возможных случая и выполнить различный набор действий. В языке Паскаль имеется аналогичный оператор ветвления, записываемый с помощью ключевых слов if then else. Данный оператор позволяет записать две альтернативных ветви, причём ветвь else является необязательной. В условии выбора должно стоять выражение, имеющее логический тип (Boolean), т.е. значением выражения должна быть либо истина, либо ложь.

Операционная семантика оператора ветвления if:

1)вычислить условное выражение оператора;

2)если получена истина, то выполнить оператор в основной ветви (после then). Если получена ложь и предусмотрена альтернативная ветвь (после else), то выпол-

нить оператор в альтернативной ветви.

Блок-схема алгоритма приведена на рис. 2. В нашем случае основная ветвь содержит в себе несколько инструкций, поэтому её следует поместить в операторные скобки begin end (так называемый составной оператор):

var

a,b,c,d,x1,x2: real; begin

readln(a,b,c); d := b*b-4*a*c;

if d >= 0 then begin

x1 := (-b + sqrt(d))/(2*a);

x2 := (-b – sqrt(d))/(2*a); writeln(x1, x2);

end else

40

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]