Глава 22 О передаче параметров



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

Процедура обмена

Рассмотрим процедуру с несколькими параметрами. Пусть надо обменять значения в переменных A и B, это можно сделать так:


    T:= A;     { временно запомнить A }

    A:= B;

    B:= T;     { поместить в B то, что раньше было в A }


Здесь T – переменная для временного хранения данных. Поручим эту простенькую работу процедуре, которую назовем Swap (обмен). Создавать процедуру начнем, как водится, с заголовка. Поскольку в обмене участвуют два числа, оба их надо передать через параметры. Для разделения формальных параметров используют точку с запятой. Если заголовок процедуры будет таким:


procedure Swap (x: integer; y: integer);


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


procedure Swap (var x: integer; var y: integer);


Если формальные параметры имеют одинаковый тип и способ передачи, то заголовок можно сократить так:


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: их применяют и для открытия соответствующих секций, и для объявления ссылочных параметров.

Итоги

• Количество фактических параметров, их тип и порядок следования в вызове должны совпадать со списком формальных параметров процедуры.

• Для экономии памяти и повышения быстродействия строковые данные (и другие сложные типы данных) передают по ссылке с применением ключевых слов CONST и VAR.

• Если строку передают по ссылке только внутрь процедуры, используют ключевое слово CONST, а если обратно или в оба направления – слово VAR.

• Если строка передается только внутрь процедуры и далее применяется там как локальная переменная, то ключевые слова CONST и VAR в объявлении параметра не ставят (так происходит передача параметра по значению).

А слабо?

А) Введите в компьютер программу «P_22_1» и проверьте её работу.

Б) Измените программу «P_20_1» так, чтобы заменяемый и замещаемый символы передавались в процедуру Scan через параметры.

В) Напишите программу для проверки рассмотренной выше процедуры Calc, подсчитывающей символ в строке.

Загрузка...