Передача параметров по значению и по ссылке. Рассмотрим следующий фрагмент программы: var a,b: integer; procedure P(x:integer; var y: integer); var z: integer; begin z:=2; x:=x+z; y:=y+z end;... {ПРОИЗВОЛЬНЫЙ ФРАГМЕНТ} a:=1; b:=1; P(a,b); writeln(a, _,b);... {ПРОИЗВОЛЬНЫЙ ФРАГМЕНТ} P(a,b):завести переменную x типа integer; x:=знач(а)=1 завести переменную z типа integer (без значения) z:=2; тело P x:=x+z; {x=3} (y b) b:=b+z; {b=3} уничтожить z уничтожить x
1)Выполнение процедуры начинается с того, что для каждого ее параметра-значения заводится (т.е. начинает существовать) вспомогательная переменная с именем и типом этого формального параметра и этой переменной присваивается значение соответствующего фактического параметра. 2)После этого заводятся (т.е. начинают существовать) все вспомогательные объекты, описанные в процедуре. 3)Далее выполняется тело процедуры, в котором все ссылки на формальные параметры-переменные заменены ссылками на соответствующие фактические параметры. 4)После завершения выполнения тела процедуры уничтожаются (т.е. перестают существовать) все вспомогательные объекты, описанные в процедуре, а затем будут уничтожены и переменные, соответствующие параметрам-значениям 5)На этом выполнение оператора процедуры полностью завершается Действия при выполнении оператора процедуры
Следствия из семантики оператора процедуры 1) Результат – только параметр-переменная. 2) Сложные типы – как параметры-переменные. Рассмотрим процедуру сложения двух векторов c=a+b: type вект=array[1..200] of real; var x,y,z:вект; procedure СЛОЖ1(a,b: вект; var c:вект); var i:integer; begin for i:=1 to 200 do c[i]:=a[i]+b[i] end; СЛОЖ1: z x y ab a i + b i => z i СЛОЖ2: zx y x i + y i => z i Слож 1(x,y,z);Слож 2(x,y,z);
3) Параметры-значения – нужны. Фактическим параметром-переменной может быть не только переменная, но и выражение при выборе вида параметров процедур нужно придерживаться следующих правил: - если параметру что-то присваивается в процедуре, то он обязательно должен быть описан как параметр-переменная; - если параметру ничего не присваивается в процедуре, то надо смотреть на тип параметра: если он сложного типа (например, массив), то лучше его описать как параметр-переменная; если же он простого типа, то его следует описывать как параметр-значение. 4) Соответствие типов. формальный параметр (типа Т1) фактический параметр (типа Т2) способ передачи параметра соотношение типов параметр-значение выражение по значению Т1 : =Т2 параметр-переменная переменная по ссылке Т1 Т2
Функции Пример функции Определим функцию гиперболический косинус: Описание функции выглядит следующим образом: function ch(x: real): real; var p: real; begin p:=exp(x); ch:=(p+1/p)/2 end; ::= 1) Иногда в левой части такого оператора присваивания указывают не только имя функции, но и аргументы: ch(x):=(p+1/p)/2. Это ошибка, т.к. здесь указывать надо только имя функции. Аргументы же функции уже указаны в заголовке функции, повторять их не надо. 2) Имя функции не является переменной, поэтому его, в частности, нельзя использовать в правой части оператора присваивания. Иногда, экономя на переменной р, пишут: ch:=exp(x); ch:=(ch+1/ch)/2; но это ошибка: имени функции можно что-то присваивать, но употреблять его в качестве переменной нельзя.
Синтаксис описания функции и указателя функции ::= ; ::= function : | function ( ) : указатель функции имя функции () фактический параметр, 1) Что может быть значением функции? Во-первых, значением функции может быть только одна величина. Во-вторых, при любых аргументах значениями функции должны быть величины одного и того же типа. В-третьих, значения функции могут быть только простого типа или ссылочного типа (мы его будем рассматривать позже), но не сложного типа. В частности, в Паскале значением функции не может быть массив, поэтому в Паскале нет векторных и матричных функций
2) Что же может быть аргументом функции? Аргументами (параметрами) могут быть данные любых типов, в том числе и массивы. Например, описание функции, вычисляющей максимальный элемент массива, может выглядеть так:... const n=20; type вект=array[1..n] of real; function max(var x: вект): real; var m: real; i: integer; begin m:=x[1]; for i:=2 to N do if x[i]>m then m:=x[i]; max:=m end; 3) Функции без параметров. function nextchar: char; const blank=' '; var c : char; begin repeat read(c) until c=blank; nextchar:=c end;
Различия между функциями и процедурами 1. Описание процедуры начинается со слова procedure, а описание функции - со слова function. 2. В заголовке функции указывается тип значения функции, а у процедур этого нет, т.к. процедура вообще не имеет значения. 3. В теле функции обязательно должен быть оператор присваивания, в левой части которого стоит имя функции, а в процедуре же такого оператора быть не должно.
Побочные эффекты функций Побочный эффект - это произведенное функцией изменение в текущем состоянии программы, и такие изменения могут быть двух типов: - ввод или вывод, осуществленный функцией (здесь меняется входной или выходной файл программы); Изменение функцией значения глобальной переменной, т.е. переменной, описанной вне функции, причем такое изменение функция может сделать двояко: либо меняя значение своего параметра-переменной, либо напрямую меняя переменную из программы. Рассмотрим сначала случай отрицательного побочного эффекта: var a,b: integer; function f(x: integer): integer; begin f:=sqr(x); a:=0 end; a:=2; b:=f(a)-f(а)
Однако в некоторых случаях побочные эффекты могут быть и полезны. Рассмотрим один из таких случаев. Пусть имеются описания: const n=20; type строка=array[1..n] of char; var S1,S2: строка; i1,i2: integer; Требуется сделать следующее: если в строку S1 входит символ '+', а в строку S2 - буква 'a', тогда требуется поменять местами первые вхождения этих символов (т.е. первое вхождение '+' в S1 заменить на 'a', а первое вхождение 'a' в S2 заменить на '+'). true, если с S, i <--номер первого вхождения BX(S,c,i) = false, иначе; i не меняется Эта функция не только определяет, входит ли символ с в строку S, но еще и меняет свой 3-й параметр, что и является побочным эффектом. Имея такую функцию, уже легко решить нашу задачу: if BX(S1,'+',i1)and BX(S2,'a',i2) then begin S1[i1]:='a'; S2[i2]:='+' end
function BX(var S:строка; c:char; var i:integer):boolean; var k:integer; b: boolean; begin b:=false; k:=1; repeat if S[k]=c then begin b:=true; i:=k end else k:=k+1 until b or (k>n); BX:=b end;