>procedure Swap (var x, y: integer);
Принцип объединения в заголовке тот же, что при объявлении однотипных переменных в секции VAR.
Теперь напишем процедуру Swap и программу «P_22_1» для её проверки.
>{ P_22_1 – процедура обмена и программа её проверки }
>{ процедура обмена }
>procedure SWAP(var x,y : integer);
>var t: integer;
>begin
> t:= x; x:= y; y:= t;
>end;
>var A, B : integer;
>begin {--- главная программа ---}
> A:= 10; B:= 20;
> Writeln(’A= ’, A, ’ B= ’, B);
> SWAP(A, B);
> Writeln(’A= ’, A, ’ B= ’, B);
> Readln;
>end.
Работает ли эта программа? Обязательно проверьте!
Замена символов в строке
Вернемся к программе P_20_1, где возможности процедуры Scan небогаты: допускается менять только символы «A» на символы «B». А если надо менять символы по своему усмотрению? Пожалуйста! Добавим в заголовок процедуры пару формальных параметров, например, так:
>procedure Scan(var arg: string; Ch1, Ch2: char);
>var k: integer;
>begin
> for k:=1 to Length(arg) do
> if arg[k]= Ch1 then arg[k]:= Ch2;
>end;
Здесь параметры Ch1 и Ch2 указывают, что и на что надо поменять. Поскольку параметры однотипны, они разделяются запятой. Порядок объявления формальных параметров в заголовке не важен. Но важно, чтобы при вызове процедуры порядок фактических параметров был таким же. Вот пример правильного вызова (символ «1» меняется на символ «2»).
>Scan(S, ’1’, ’2’);
А вот ошибочные:
>Scan(S, ’1’); { указаны не все параметры }
>Scan(’1’, S, ’2’); { нарушен порядок следования параметров }
>Scan(S, ’1’, ’2’, ’3’); { указан лишний параметр }
>Scan(S, 1, 2); { неверный тип параметров }
За соответствием фактических параметров формальным жестко следит компилятор. Исключение составляют встроенные в язык процедуры ввода-вывода, такие как Readln и Writeln, где допускается гибкая передача параметров разных типов.
Переработайте программу «P_20_1» с тем, чтобы испытать новую версию процедуры замены символов, а затем исследуйте её в пошаговом режиме.
О передаче строк
Передача строковых данных таит свои тонкости. Рассмотрим процедуру Calc для подсчета заданного символа в некоторой строке.
>procedure Calc(arg: string; Ch: char; var Res: integer);
>var k: integer;
>begin
> Res:=0;
> for k:=1 to Length(arg) do
> if arg[k]= Ch then Res:= Res+1;
>end;
Процедура принимает три разнотипных параметра: строку arg, символ Ch и ссылку на переменную Res – в ней возвращается результат. Здесь все правильно. Но недаром говорят: «меньше знаешь, – крепче спишь», – мой сон тревожит параметр arg строкового типа.
Поскольку строка может содержать до 255 символов, параметру arg отводится немалая память – 256 байтов! При передаче по значению все эти байты копируются в параметр arg, и на это тратится время. Если же параметр arg будет ссылкой на строку, то копирования не потребуется, и программа заработает быстрее. Вдобавок мы и память сэкономим, ведь ссылка на строку занимает в памяти всего 4 байта! Раз так, объявим процедуру иначе.
>procedure Calc(var arg: string; Ch: char; var Res: integer);
Этот вариант лучше, но не сработает, если в вызове процедуры указать строковую константу, например:
> Calc(’PASCAL’, ’L’, Result);
Здесь компилятор воспротивится не на шутку, требуя в первом параметре переменную. И будет прав, поскольку ключевое слово VAR в заголовке процедуры объявляет ссылку на переменную, а не на константу. Что делать? Вернуться к первому способу? Нет, есть лучшее средство: вместо ключевого слова VAR укажите в заголовке слово CONST, вот так:
>procedure Calc(const arg: string; Ch: char; var Res: integer);
Такая ссылка будет годна как для переменной, так и для константы.
> Calc(’PASCAL’, ’L’, Result); { вызов с константой }
> Calc(S, ’L’, Result); { вызов с переменной }
Слово CONST перед формальным параметром, так же, как и VAR, определяет ссылку на данные, но без возможности их изменения. Обратите внимание на двойное назначение слов CONST и VAR: их применяют и для открытия соответствующих секций, и для объявления ссылочных параметров.
Итоги
• Количество фактических параметров, их тип и порядок следования в вызове должны совпадать со списком формальных параметров процедуры.