Начнем, разумеется, с заголовка функции, дадим ей имя Count (подсчет).
>function Count(const Str : string; Ch : char): integer;
Функция принимает два параметра: ссылку на строку и символ, который надо подсчитать. Напомню, что ключевое слово CONST в объявлении параметра позволяет ссылаться и на константу, и на переменную. Тело функции строим на базе цикла со счетчиком.
>function Count(const str : string; ch: char): integer;
>var N, i: integer;
>begin
>N:=0; { обнуляем счетчик }
>for i:=1 to Length(str) do
> if str[i]=ch then N:= N+1;
>Count:= N; { определяем результат функции }
>end;
Подсчет символов в массиве ведется в локальной переменной N, и лишь по завершении цикла результат копируется в имя функции. Грубой ошибкой было бы накапливать счетчик прямо в имени функции:
> if str[i]=ch then Count:= Count+1; { – это ошибка! }
Запомните: в теле функции её имя применяется только слева от оператора присваивания! Есть исключения из этого правила, но мы пока не будем их касаться.
И, наконец, напишем программу «P_22_1» для проверки функции Count. В главной программе функция вызывается сначала для переменной S, а затем для константы «BANAN». Причем во втором случае она вызывается дважды, а результат суммируется. Испытайте эту программу.
>{ P_23_1 – подсчет заданных символов в строке }
>function Count(const str : string; ch: char): integer;
>var N, i: integer;
>begin
>N:=0; { обнуляем счетчик }
>for i:=1 to Length(str) do
> if str[i]=ch then N:= N+1;
>Count:= N; { передаем результат через имя функции }
>end;
>var S: string;
>begin {--- главная программа ---}
>S:='PASCAL';
>Writeln( Count(S, 'A'));
>Writeln( Count('BANAN', 'N') + Count('BANAN', 'B'));
>Readln;
>end.
Возврат строк
Вернемся к программе «P_20_1», заменяющей символы «A» на символы «B». Помните сколько крови она попортила прежде чем заработать? Заменив процедуру Scan на функцию с тем же именем, мы решим проблему возврата результата. Результат, разумеется, должен иметь строковый тип. Обратите внимание на то, что ключевые слова VAR или CONST в заголовке не указаны, а потому параметр arg можно употребить в теле функции в качестве локальной переменной.
>{ P_23_2 – замена символов в строке с применением функции }
>function Scan(arg : string): string;
>var k: integer;
>begin
> for k:=1 to Length(arg) do
> if arg[k]=’A’ then arg[k]:=’B’; { замена в параметре arg }
> Scan:= arg;
>end;
>var S: string; k: integer;
>begin {--- главная программа –--}
> for k:=1 to 3 do begin
> Write(’Введите строку: ’); Readln(S);
> Writeln(Scan(S));
> end;
> Readln;
>end.
Когда результат не важен
Хорошая функция возвращает правильный результат, а отличная делает ещё что-нибудь полезное. Программисты нередко поручают одной функции несколько дел, вот пример: напишем функцию Swap (обмен) булевого типа, принимающую ссылки на две переменные. Функция должна сравнить эти переменные и вернуть TRUE, если первая из них окажется больше второй. Мало того, в этом случае она должна обменять значения этих переменных (как в процедуре Swap, рассмотренной ранее). Короче, функция будет такой.
>function Swap( var a1, a2 : integer) : Boolean;
>var t: integer;
>begin
> if a1 > a2
> then begin
> { обмен значений переменных }
> t:=a1; a1:=a2; a2:=t;
> Swap:= true
> end
> else Swap:= false
>end;
Где применить такую функцию? Пусть переменные N1, N2, N3 содержат три разных числа. Переложим эти числа так, чтобы в N1 оказалось наименьшее, а в N3 – наибольшее число, то есть, чтобы соблюдалось условие: N1 < N2 < N3. Такая сортировка выполняется тремя вызовами функции Swap (в комментариях показаны результаты обмена).
> Swap(N1, N2); { N1 < N2 }
> if Swap(N2, N3) { N2 < N3 }
> then Swap(N1, N2); { N1 < N2 < N3 }
Здесь в первой и третьей строках функция вызывается как процедура, поскольку возвращаемый ею булев результат не используется. Во второй строке она вызывается как функция, поскольку результат использован оператором IF.
Возможность вызывать функцию как процедуру называют расширенным синтаксисом (Extended syntax), – он должен быть разрешен в настройках компилятора, иначе вызов функции как процедуры компилятор сочтет ошибкой.