Лекция 3. Целые и вещественные типы. Процедуры и функции

Здесь вы познакомитесь с целыми и вещественными типами данных. Напишите программу с использованием этих типов. Затем мы разберем, что такое функции и процедуры, внедрим их в написанную ранее программу. Познакомимся с понятием "Событие".

Целые числа

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

-12

В прошлой лекции мы упомянули лишь тип Integer, как основной тип целых чисел. Действительно, этот тип приходится использовать чаще всего, однако существуют и другие типы целых чисел. В таблице 3.1 представлены целые типы:

Таблица 3.1. Целые типы данных
Тип Диапазон возможных значений Размер памяти под переменную Примечание
Integer -2147483648 .. 2147483647 4 байта Знаковое
Cardinal 0 .. 4294967295 4 байта Без знака
Shortint -128 .. 127 1 байт Знаковое
Smallint -32768 .. 32767 2 байта Знаковое
Longint -2147483648 .. 2147483647 4 байта Знаковое
Int64 -263 .. 263 - 1 8 байт Знаковое
Byte 0 .. 255 1 байт Без знака
Word 0 .. 65535 2 байта Без знака
Longword 0 .. 4294967295 4 байта Без знака

Давайте разберемся, как работает любая программа. Когда мы загружаем программу, она считывается в оперативную память компьютера. Туда же считываются и данные, с которыми программа работает. Только после этого программа начинает выполняться. Если современные жесткие диски имеют достаточно большой размер, этого нельзя сказать об оперативной памяти. Поэтому ее следует экономить везде, где только можно.

Чаще всего вам придется работать с переменными типа Integer, это самый распространенный тип целых чисел, он годится почти для всех расчетов. Однако бывают моменты, когда не нужно такого большого диапазона значений. Например, вы будете использовать переменную для счетчика какого-то цикла, и знаете, что он будет длиться, к примеру, от 1 до 100. В таком случае, указав в качестве счетчика тип Integer, мы зря украдем у оперативной памяти 3 байта! 3 байта – это немного, но ведь в большой программе переменных будет очень много, и если все они будут тратить память попусту, то такая программа будет, мягко говоря, непрофессиональной. Приучайтесь сразу тратить столько байт оперативной памяти, сколько нужно. Не зря ведь придумали столько типов! Если Вы знаете, что в переменной будут числа от нуля и выше, то нет никакой необходимости брать знаковый тип, ведь отрицательным Ваше число все равно не будет!

Вещественные числа

Как мы уже говорили раньше, вещественные числа – это числа с запятой, после которой идут десятичные значения. Еще говорят, что они имеют плавающую точку (запомните это определение, оно будет часто встречаться). Некоторые начинающие программисты считают, что лучше такой тип переменных использовать всегда, даже при обработке целых чисел. Это большое заблуждение! Операции над числами с плавающей точкой отнимают у процессора гораздо больше времени, и требуют больше памяти. Компьютер воспринимает вещественное число, как два целых, и делает двойную работу при обработке чисел до запятой, и после нее. Однако иной раз бывает необходимо использовать именно такой тип данных. К примеру, если нужно поделить одно целое на другое. Хорошо, если это будет "4/2", результат тоже будет целым – 2. А если "4/3"? Тогда результатом будет 1,3333… и уж тут без вещественного числа не обойтись! А ведь мы заранее не знаем, какие числа будет делить пользователь, поэтому лучше сразу иметь в виду, что результат может быть не целым числом.

Как и целые, вещественные числа имеют несколько типов. В таблице 3.2 они представлены:

Таблица 3.2. Вещественные типы данных
Тип Диапазон возможных значений Значащих цифр максимально Размер в байтах
Real48 2.9 * 10-39 .. 1.7 * 1038 11-12
Real 5.0 * 10-324 .. 1.7 * 10308 15-16
Single 1.5 * 10-45 .. 3.4 * 1038 7-8
Double 5.0 * 10-324 .. 1.7 * 10308 15-16
Extended 3.6 * 10-4951 .. 1.1 * 104932 19-20
Comp -263+1 .. 263-1 19-20
Currency -922337203685477.5808 .. 922337203685477.5807 19-20

Третий столбец таблицы указывает количество максимально значащих цифр. Цифры, которые выходят за этот предел, будут игнорироваться. Тут важно помнить, что вещественные числа не равны целым. То есть, число 3,0 не будет равно 3! Чтобы сравнить оба эти числа, придется округлить вещественное число.

Изучим целые и вещественные типы на практике. Для этого создадим простую программу, которая делит одно целое число на другое. Результат будет выводиться, как вещественное число.

Откройте Delphi, создайте новый проект. На форму нужно поместить три компонента Label, три компонента Edit и одну кнопку, чтобы получилась такая картина:

Лекция 3. Целые и вещественные типы. Процедуры и функции - student2.ru

Рис. 3.1. Внешний вид формы

Совет: чтобы выполнить одинаковую операцию над несколькими компонентами сразу, их можно выделить один за другим, удерживая клавишу <Shift>. Например, если таким образом выделить все три компонента Edit, то затем можно разом очистить их свойство Text.

Сохраните проект под именем MyCalc. Затем дважды щелкните по кнопке, чтобы создать обработчик нажатия на кнопку.

Перед begin процедуры следует создать раздел var, и объявить там три переменных:

var

Perem1, Perem2 : Integer;

Perem3 : Double;

Затем вернемся в тело процедуры (между командами begin и end), и присвоим целым переменным введенные пользователем значения. Здесь нужно понять одну важную вещь. Пользователь будет вводить значения в компоненты Edit, и там они будут храниться в свойстве Text в виде строкового типа данных. Строку нельзя будет присвоить переменной какого-либо другого типа данных, присвоение

Perem1 := Edit1.Text; //ошибочное присвоение

//– несовместимость типов данных

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

то компьютер видит строку символов, а вовсе не число:

'123'

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

StrToInt('String');

В качестве параметра (в скобках) указывается строка. Функция преобразует ее в целое число и вернет его как результат. Примеры использования функции (эти примеры не нужно вводить в редактор кода):

var

s: String;

i: Integer;

begin

s := '1234';

i := StrToInt(s); //параметр – строковая переменная

i := StrToInt(‘123456’); //параметр – строка

i := StrToInt(Edit1.Text); //параметр – свойство Text

//компонента Edit, имеющее строковый тип

end;

Как видно из примера, имеется масса возможностей передать в функцию строку. В первом случае преобразования мы передаем строковую переменную s, в которой хранится строка '1234'. Функция преобразует эту строку в целое число, и в результате в переменнуюi попадет уже число 1234.

Во втором случае мы передаем непосредственно строку '123456', а в переменную i попадает преобразованное из этой строки число. В третьем случае мы в качестве параметра передаем тот текст, который пользователь ввел в поле ввода Edit1. Здесь следует сделать оговорку. Функция сработает правильно, если пользователь ввел туда действительно целое число. В противном случае возникнет ошибка. Пользователь – личность непредсказуемая, поэтому программист в таких случаях перед преобразованием типов всегда делает проверку – а действительно ли в поле ввода имеются только цифры от 0 до 9? Нет ли там случайно буквы или запятой? Такую проверку мы научимся делать позднее. Пока что придется самим следить, чтобы в этих полях ввода были только целые числа.

Вернемся к программе. Сразу после begin присваиваем целым переменным значения, которые ввел пользователь:

Perem1 := StrToInt(Edit1.Text);

Perem2 := StrToInt(Edit2.Text);

В третью, вещественную переменную, мы должны записать результат деления первого числа на второе. Тут может крыться еще один "подводный камень" - что, если во второе поле пользователь ввел число 0? Еще со школы все мы знаем, что на ноль делить нельзя. Если же мы попробуем это сделать, то компьютер, в лучшем случае, зависнет. Здесь опять придется делать проверку на правильность введенных данных, ставить, как говорят, "защиту от дураков". Подробнее о таких проверках мы поговорим на следующих лекциях, когда изучим условные конструкции. А пока просто наберите этот код:

{защита от дураков:}

If Perem2 = 0 then begin //если это ноль, то:

ShowMessage('На ноль делить нельзя!'); //выводит сообщение

Edit3.Text := '0'; //как результат записываем ноль

end

else begin //иначе:

Perem3 := Perem1 / Perem2; //делим

Edit3.Text := FloatToStr(Perem3); //преобразуем вещественное в

//строку и записываем результат

end;

Здесь следует обратить внимание на предпоследнюю строку. Функция FloatToStr() в качестве параметра принимает вещественное число, и возвращает это же число в виде строки. Например, в результате преобразования

s := FloatToStr(123.45);

переменной s будет присвоена строка '123.45', которую затем уже можно будет вывести пользователю в качестве результата. В нашем примере мы результат деления двух целых чисел преобразуем в строку и выводим его в поле Edit3. Справедливости ради следует заметить, что в качестве параметра можно передавать не только значение, но и выражение. Например, если указать

Edit3.Text := FloatToStr(Perem1 / Perem2);

то надобность в использовании вещественной переменной Perem3 отпадает. Попробуйте, как работают оба варианта.

Процедуры

Это очень важная тема, обратите на нее особое внимание!

Раньше языки программирования были построчными. Единственным вариантом возврата к нужной строке был оператор GO. Очень много ошибок было сделано этим оператором! Современные языки программирования также имеют этот оператор, но применять его считается дурным тоном.

Иногда бывает необходимо выполнять часть кода неоднократно. Этот самый код выносят в отдельную подпрограмму – процедуру.

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

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

procedure NameProc(Param : Тип);

var

//объявление переменных(необязательно)

begin

//тело процедуры

end;

Вызвать такую процедуру можно, просто указав ее имя. Проверим это на практике. Вернемся к нашему проекту, и выше процедуры обработки кнопки создадим такую процедуру:

procedure Soobshenie;

begin

ShowMessage('Ошибка! На ноль делить нельзя!');

end;

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

Soobshenie;

Теперь сохраните проект, скомпилируйте его и посмотрите, что получилось. Не забудьте, что вводить в Edit1 и Edit2 можно только цифры от 0 до 9.

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

procedure Primer(a,b : Integer);

begin

a := a * b;

end;

Обратите внимание, что обязательно нужно указывать тип параметров. Теперь мы можем вызвать эту процедуру, указав ей, какие цифры нужно перемножить. Примеры вызова процедуры:

Primer(10, 20); //передаем целые числа

Primer(a, 100); //передаем переменную a с целым числом, и целое число

Primer(c, d); //передаем две переменных с целым числом

Сразу следует сказать об области видимости переменных. Бывают переменные глобальные и локальные. Глобальные переменные видны во всей программе, их мы будем использовать позже. А локальные переменные создаются внутри процедуры, в разделе var, и видны только в этой процедуре. Локальные переменные создаются в памяти в то время, когда процедура начинает работу, и уничтожаются, когда процедура закончила работу. Таким образом, мы можем сделать две или более процедур, и указать в них переменные с одинаковым именем. Это будут разные переменные, и они не будут мешать друг другу.

Функции

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

function NameFunc(Param : Тип) : Тип_возвращаемого_значения;

var

//объявление переменных (необязательно)

begin

//тело функции

Result := результат вычислений;

end;

Здесь следует обратить внимание на два момента: после имени функции и параметров в круглых скобках, после двоеточия, указывается тип возвращаемого значения. Кроме того, в каждой функции по умолчанию имеется переменная Result, которая имеет тот же тип, что и тип возвращаемого значения. Эту переменную специально объявлять не нужно, она уже готова к работе. В отличие от других языков, в Delphi этой переменной можно присваивать значение неоднократно. Результатом будет последнее присвоенное значение.

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

Result := результат вычислений;

будет полностью идентичной строке

NameFunc := результат вычислений;

Какой из способов использовать – решайте сами, оба способа правильны. Снова вернемся к нашей программе, и для закрепления знаний добавим в нее функцию. Функция также должна быть описана выше того места, где мы будем ее вызывать. Можете создать ее между нашей процедурой и процедурой нажатия на кнопку.

function Delenie(a,b : Integer) : Real;

begin

Result := a / b;

end;

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

Perem3 := Delenie(Perem1, Perem2);

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

События

В Delphi событие означает, что какой то компонент, которому мы назначили событие, изменился. Событие – это процедура, которой передается управление в случае, если произошли запрограммированные изменения. События могут быть самыми разными – изменение текста в поле Edit, нажатие кнопки мыши или клавиши, или просто мышь оказалась над компонентом.

Давайте улучшим наш пример, введем в него событие. Выделите компонент Edit1. Сейчас мы зададим ему событие OnChange, которое происходит всякий раз при изменении текста в этом компоненте. Давайте представим себе пользователя, работающего с нашей программой. Ему будет приятно, если он начнет менять текст в первом поле, а остальные поля автоматически очистятся, чтобы быть готовыми для новых расчетов!

Выделим компонент Edit1.

Перейдем в инспекторе объектов на вкладку Events (события).

Дважды щелкнем по событию OnChange (Изменение).

Создастся процедура обработки события, и мы попадем в редактор кода. Там мы впишем две строки:

Edit2.Clear;

Edit3.Clear;

Теперь вставим еще одну "защиту от дураков". Ведь третье поле нужно только для результата? А вдруг пользователь начнет там вводить данные? Страшного ничего не произойдет, в расчетах это поле не участвует, но все равно неприятно, когда твою программу используют неправильно.

Выделите компонент Edit3.

На вкладке Properties (свойства) найдите свойство ReadOnly (только для чтения), и вместо False (ложь), поставьте True (истина). Все, теперь пользователь не сможет вводить данные в это поле, только программа сможет выводить в него результат.

Сохраните проект, выполните Run и убедитесь в этом.

Наши рекомендации