Добавлен: 05.04.2023
Просмотров: 289
Скачиваний: 2
Здесь ключевое слово const показывает начало раздела описаний именованных констант. Ясно, что зачастую удобнее обращаться к константе по имени, чем каждый раз переписывать ее числовое или строковое значение. Пример раздела констант:
const e=2.7182818285;
lang='Turbo Pascal 7.1';
Здесь описана числовая константа e со значением основания натурального логарифма и строковая константа с именем lang, содержащая строку 'Turbo Pascal 7.1'.
Каждое даваемое программистом имя должно быть уникальным в пределах одной программы. Если мы включим этот раздел в свою программу, мы уже не сможем создать в ней других объектов с именами e и lang.
2.3 Переменные и типы переменных
Переменными называют величины, значения которых могут изменяться в процессе выполнения программы. Каждая переменная задается своим уникальным именем, построенным по правилам, указанным в начале главы. Максимально возможная длина имени зависит от реализации Паскаля, теоретически можно давать переменным имена вплоть до 63 символов длиной, что едва ли актуально – обычно имена не длиннее 5-10 символов.
Поскольку любые данные в памяти компьютера хранятся в числовой форме и двоичной системе счисления, кроме имени, переменной обязательно следует присвоить и тип, определяющий диапазон значений, принимаемых переменной, и способ ее обработки машиной. Поясним сказанное на примере. Как видно из Приложения 1, латинская большая буква 'A' имеет десятичный код 65, или 01000001 в двоичном представлении. Без дополнительной информации о типе данных, хранящихся в некоторой ячейке памяти, компьютеру было бы невозможно решить, что именно представляют из себя эти данные – число 65, код символа 'A' или что-то еще. В любом языке программирования, в том числе и в Паскале, существует стандартный набор типов, к которым может быть отнесена та или иная совокупность ячеек памяти. Информацию о типах данных Паскаля удобно свести в таблицу. Строки этой таблицы будут упорядочены по старшинству типов, от самого "младшего", требующего наименьшее число байт для представления, и, соответственно, представляющего наименьший диапазон возможных значений, до самого "старшего", представляющего наибольший диапазон значений. В таблице представлены не все возможные, а лишь основные типы данных Паскаля.
|
Ключевое слово Паскаля |
Название и описание типа |
Объем памяти, байт |
Диапазон возможных значений |
|
Boolean |
Логический: хранит одну логическую переменную |
1 |
true и false |
|
Char |
Символьный: хранит код одного символа из набора ASCII-кодов |
1 |
от 0 до 255 включительно (28=256) |
|
Integer |
Целочисленный |
2 |
±215 |
|
Word |
Целочисленный без знака |
2 |
±216 - диапазон вдвое больше, так как 16-й бит не занят под знак числа |
|
Longint |
Длинное целое: для представления больших целочисленных значений |
4 |
±231 |
|
Real |
Вещественное число с точностью представления до 11-12 знака в дробной части |
6 |
~ 2.9*10-39 - 1.7*1038 |
|
Double |
Вещественное число с точностью представления до 15-16 знака в дробной части |
8 |
~ 5*10-324 – 1.7*10308 |
|
String |
Последовательность символов типа Char длиной от 1 до 255 |
2-256 (данные строки + 1 байт для хранения ее длины) |
Любые строки текста, состоящие из печатаемых символов |
Теоретически для записи переменной типа Boolean было бы достаточно 1 бита, но минимальная адресуемая единица памяти – 1 байт.
Целочисленные и символьные типы обобщенно называют порядковыми, подчеркивая этим, что данные типы имеют конечный набор значений, которые могут быть упорядочены или перечислены. Напомним, что вещественные значения хранятся в памяти компьютера иначе, чем целые – а именно, как совокупность мантиссы и порядка.
Разумеется, задача правильного выбора типов данных целиком ложится на программиста. Например, если некоторый счетчик в программе может принимать целочисленные значения от 1 до 100000, неправильно было бы описывать его как переменную типа Integer – ведь 215=32768 и при достижении счетчиком этой величины произойдет сброс его значения, которое станет равно -32768. Разумным в данном случае было бы описание счетчика как переменной типа Longint.
Переменные описываются в программе оператором следующего вида:
var Список1:Тип1;
Список2:Тип2;
. . .
СписокN:ТипN;
Здесь список – набор имен переменных, разделенных запятыми (или одна переменная), а тип – любой из рассмотренных выше типов данных. Например, конструкция
var t,r:real;
i:integer;
Описывает 2 вещественных переменных с именами t и r, а также целочисленную переменную с именем i. Ключевое слово var можно и продублировать, но обычно такой необходимости нет. Сокращение var образовано от английского слова "Variable" (переменная).
2.4 Матрицы и типовые алгоритмы обработки матриц
Многие задачи связаны с обработкой многомерных массивов данных. Наиболее распространены при этом двумерные массивы.
В математике двумерные массивы представляются матрицей:
или, в сокращенной записи,
, где
где n - число строк матрицы, m - число столбцов, индексы (номера) текущих строки и столбца, на пересечении которых находится элемент .
Как и другие объекты данных, матрица описывается в разделе var. От вектора ее описание отличается тем, что в квадратных скобках перечисляются два оператора диапазона, указывающие, соответственно, нумерацию строк и столбцов матрицы:
var ИмяМатрицы: array [n1..n2, m1..m2] of Тип;
Здесь
n1..n2 – диапазон значений номера строки, n1 и n2 – целочисленные константы;
m1..m2 – диапазон значений номера столбца, значения m1 и m2 также целочисленные.
Как и векторы, матрицы могут быть образованы из элементов любого существующего в языке типа данных.
Под матрицу выделяется область памяти размерностью n*m*k байт, где k – размерность в байтах одного элемента. Для известных нам типов данных эту размерность можно узнать из таблицы в разделе 2.2. В оперативной памяти матрица хранится построчно.
Например, для матрицы A, описанной оператором вида
var A:array [1..5,1..4] of real;
выделяется 20 ячеек памяти по 6 байт, причем в следующей за элементом A1,4 ячейке хранится значение элемента A2,1.
Обращение к отдельным элементам матрицы осуществляется с помощью переменной с двумя индексами, например:
ai,j a[i,j]
a2,1 a[2,1]
a2n,k a[2*n,k]
Первый индекс, как и в математике, всегда показывает номер строки, а второй – номер столбца.
Поскольку адресация памяти в любом случае линейна, следует понимать матрицу как удобный для программиста структурный тип данных. В отдельных случаях использование матрицы может быть заменено использованием вектора с тем же количеством элементов: так, матрице An,m всегда может быть сопоставлен вектор b размерностью n*m, а обращение к элементу A[i,j] при нумерации строк и столбцов с единицы может быть заменено на обращение к элементу b[(i-1)*m+j].
Подобно тому, как любая последовательная обработка вектора выполняется в цикле for, обработка матрицы выполняется в двойном цикле for:
for i:=1 to n do
for j:=1 to m do
{Обработка элемента A[i,j]}
Согласно правилу выполнения кратных циклов, переменная j меняется в этом двойном цикле быстрее, чем i, таким образом, обработка всех элементов матрицы будет выполнена построчно. Для последовательной обработки всех элементов матрицы по столбцам достаточно поменять местами циклы по i и j:
for j:=1 to m do
for i:=1 to n do
{Обработка элемента A[i,j]}
Теоретически мы могли бы решить эту же задачу и перестановкой индексов в обращении к элементу матрицы (A[j,i] вместо A[i,j]), однако, во избежание путаницы, делать этого не рекомендуется.
Приведем примеры использования двойного цикла for для ввода и вывода элементов матрицы. Пусть матрица C размерностью 4*2 (как мы помним, это означает, что в матрице 4 строки и 2 столбца) описана оператором вида
var c:array [1..4,1..2] of real;
В программе предусмотрено также 2 целочисленных счетчика для строк и столбцов матрицы:
var i,j:integer;
В этом случае типовой ввод матрицы с клавиатуры мог бы выглядеть так:
writeln ('Введите матрицу C размерностью 4*2');
for i:=1 to 4 do
for j:=1 to 2 do read (c[i,j]);
Иногда удобнее печатать отдельное приглашение к вводу каждого элемента:
writeln ('Введите матрицу C размерностью 4*2');
for i:=1 to 4 do
for j:=1 to 2 do begin
write ('C[',i,',',j,']=');
readln (c[i,j]);
end;
Например, в качестве приглашения к вводу элемента C1,1 на экране будет напечатано:
C[1,1]=
Оператор readln используется, поскольку элементы вводятся по одному.
Как и для векторов, возможны альтернативные способы ввода – описание матрицы в разделе констант и формирование ее элементов из случайных чисел. Приведем пример описания матрицы констант размерностью 2*3:
const d:array [1..2,1..3] of integer=(
(1,2,3),
(4,5,6)
);
Как видно из примера, для описания матрицы констант создается список ее строк, каждая строка, в свою очередь, представляет собой список значений элементов.
Вывод на экран матрицы небольшой размерности бывает удобно реализовать в виде "одна строка матрицы на одной строке экрана". Для этого элементы матрицы во внутреннем цикле печатаются оператором write, не переводящим строку на экране, а во внешнем цикле выполняется writeln:
writeln ('Матрица C:');
for i:=1 to 4 do begin
writeln;
for j:=1 to 2 do write (c[i,j]:4:1);
end;
Разумеется, при выводе элементов матрицы можно использовать константы ширины и точности.
Базовые алгоритмы обработки матриц – те же, что мы изучили в темах "Циклы" и "Одномерные массивы". Отличие состоит в том, что реализацию этих алгоритмов можно условно рассматривать для двух типов задач:
- Алгоритмы реализуются при обработке всех элементов матрицы.
- Алгоритмы реализуются внутри каждой строки или каждого столбца матрицы.
В первом случае задача отличается от задачи с вектором лишь тем, что используются двойные циклы ввода, обработки и вывода.
Пр. В матрице A размерностью 4*4 найти сумму ее положительных элементов, произведение элементов, значения которых попадают в интервал [2,10], а также отношение этих двух величин.
var a:array [1..4,1..4] of real;
i,j:integer;
s,p,z:real;
begin
{Цикл ввода}
writeln ('Ввод матрицы размерностью 4*4');
for i:=1 to 4 do
for j:=1 to 4 do read (a[i,j]);
{Начальные значения и цикл обработки}
s:=0;
p:=1;
for i:=1 to 4 do
for j:=1 to 4 do begin
if a[i,j]>0 then s:=s+a[i,j];
if (a[i,j]>=2) and (a[i,j]<=10) then p:=p*a[i,j];
end;
{Вывод результатов}
writeln ('Сумма=',s:6:2);
writeln ('Произведение=',p:6:2);
if p<>0 then begin
z:=s/p;
writeln ('Отношение=',z:6:2);
end
else writeln ('p=0, отношение вычислить нельзя');
reset (input); readln;
end.
Поскольку о типе матрицы в условии ничего не сказано, выбран "более общий" тип real. Способ ввода также выбран "по умолчанию" – пользователь вводит значения элементов матрицы с клавиатуры. Искомые сумма, произведение и отношение обозначены, соответственно, s, p и z.