26
ФУНКЦИИ ФУНКЦИИ Функция = самостоятелно обособена и логически завършена, именувана програмна конструкция от инструкции, клаузи и коментари, при изпълнението на която се получават определени резултати. Деклариране прототип на функция Деклариране прототип на функция : type functionname(typearg arg1,…,typearg argN); type = тип на резултата, който връща функцията; functionname = име на функцията. typearg = тип на аргумент, argN = име наN-тия аргумент Прототипът е формално описание на програмната конструкция (какво ще върне, как ще се нарича, какви аргументи има) без заделяне на памет за нея.

ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

  • Upload
    others

  • View
    11

  • Download
    0

Embed Size (px)

Citation preview

Page 1: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

ФУНКЦИИФУНКЦИИ

Функция = самостоятелно обособена и логически завършена,именувана програмна конструкция от инструкции, клаузи икоментари, при изпълнението на която се получаватопределени резултати.

Деклариране прототип на функцияДеклариране прототип на функция:type functionname(typearg arg1,…,typearg argN);

type = тип на резултата, който връща функцията;functionname = име на функцията.typearg = тип на аргумент, argN = име наN-тия аргумент

Прототипът е формално описание на програмната конструкция (какво ще върне, как ще се нарича, какви

аргументи има) без заделяне на памет за нея.

Page 2: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

ФУНКЦИИФУНКЦИИ

float dev(int a, int b){float result;result=a/b;return(result);}

При

мер

Докато е наличен прототип, функцията може да се ползва и бездефиниция. Но програмният код не може да се изпълни бездефиниция й. Разбира се, прототип и дефиниция може да секомбинират в едно. По подразбиране типът на резултата е int.Функцията може и да няма аргументи, а само да върши някакваработа. Такива функции имат “аргумент” void .

Дефиниране на функцияДефиниране на функция:type functionname(typearg arg1,…,typearg аргN){Declarations of local variables;Zone-instructions;return(expression);}

Дефиницията е пълно описание на програмнатаконструкция, при обработката на което компилаторът на Сзаделя памет за съхраняване текущите стойности по време надостъпа му до него.

Page 3: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

ФУНКЦИИФУНКЦИИ -- примерипримери

Функция, която връща резултат с return#include <iostream>using namespace std;

float dev(float a, float b);

int main(){

float x, y, z;cout<<"\nx=? : ";cin>>x;cout<<"\ny=? : ";cin>>y;z = dev(x, y);cout<<"\nx/y="<<z;return 0;

}

float dev(float a,float b){

return(a/b);}

Декларация на прототип на функция

Дефиниция на функция

Идентификаторът на функцията еособен вид указател:

” указател към функция ”.Той съдържа адреса на входнататочка на изпълнимия й код.

При всяко извикване на функциятакомпилаторът на С генерира код запредаване на управлението наизчислителния процес с възврат вточката на извикване.

След завършването на функцията,управлението се предава къмследващия изпълним оператор следточката на извикване.

Фиг

. 6

Page 4: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

ФУНКЦИИФУНКЦИИ -- примерипримериФункция, която не връща резултат

#include <iostream>using namespace std;

void mult(int a, int b);int main(){

int x, y;cout<<"\nx=? : ";cin>>x;cout<<"\ny=? : ";cin>>y;mult(x,y);return 0;

}

void mult(int a, int b){cout<<"\n";cout<<"x*y="<<a*b;}

Функция без параметри

#include <iostream>using namespace std;

int dev(void);int main(){

dev();return 0;

}int dev(void){

float x, y, z;cout<<"\nx=? : ";cin>>x;cout<<"\ny=? : ";cin>>y;z=x/y;cout<<"\nx/y="<<z;return(0);

}

Формални параметри

Фактически параметри

Формалните параметри сезаменят с фактически вточката на извикване нафункцията

(процедура)

Фиг. 7 Фиг. 8

Page 5: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИПрограмата на С/С++ е съвкупност от равнопоставени самостоятелнипрограмни конструкции (функции), една от които е задължителна - main().Te си взаимодействат по между си като обменят информация в най-общсмисъл. Инструментът на това взаимодействие е извикването на функция,което е действие с най-висш приоритет от всички действия в езика С. Всякапотребителска функция може да извиква друга функция. Първата се нарича”извикваща”, а в точката на извикване втората се нарича ”извикана”. Товавзаимодействие може да се разгледа в два аспекта: предаване на данни и/илипредаване на управление на изчислителния процес.

Разпределението на ОП за изпълнима програмаРазпределението на ОП зависи от изчислителната система, от типа наоперационната система, а също от модела памет. Да припомним, че всекидял на ОП, заделен за активиран процес (изпълнение на програма) най-общо се състои от: блок 1 (вектори на прекъсвания на ОС) с начален адрес0000:0000, блок 2 – изпълним програмен код, блок 3 - област настатичните данни, блок 4 - област на динамичните данни, блок 5 -програмен стек, блок 6 – резидентни команди на ядрото на ОС и блок 7 –стек на ОС .

Page 6: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Блок 2 (изпълним програмен код) – за изпълнимият код на всичкифункции, изграждащи потребителската програма

Блок 3 (област на статични данни) – за глобалните обекти напрограмата

Блок 4 (област на динамични данни) – за реализиране надинамични структури от данни (списъци, дървета, графи, ...). Зацелта се използват средства за динамично разпределение напаметта. Чрез тях се заделя и освобождава памет в процеса наизпълнение на програмата, а не преди това (при компилирането й).

Блок 5 (програмен стек) – Съхранява данните на функциите напрограмата. Стекът е динамична структура, организирана поправилото FILO “ пръв влязъл – последен излязъл”. Композирасе като редица от елементи с пряк достъп, при което достъпът доелементите му се осъществява само от единия му край, нареченвръх. За целта се ползва указател, който съхранява текущатастойност на върха на стека в специален регистър на централнияпроцесор, наречен stack pointer (SP).

Page 7: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

0x000x000x0A0x1E0x000x000xD10x2C0x010x000x1B0xBA

adr adr-1adr-2adr-3adr-4adr-5adr-6adr-7adr-8adr-9adr-10adr-11

var1var2

varlast

****************

Началното инициализиране на SP (т.е. указване начален адрес настека) се осъществява от компилатора на С и свързващия редактор,които добавят машинен код към изпълнимия програмен код от вида:stack pointer=bottom of stack;

Пос

ока

на

зап

ъл

ван

е н

а ст

ека

Bottom of stack

Връх на стека adr-12adr-13adr-14adr-15

****adr-16

Стекът (по точно SP) се инициализира с най-старшия адрес на паметта, предназначенa занего, т.е.

stack pointer=bottom of stack=adr.

Нататък операцията включване сеосъществява само пред елемента от върха, аоперацията изключване – само за елемента отвърха. Така, първият включен елемент var1(от тип int) ще бъде с адрес adr, при което SPще получи адрес adr-4. При вмъкване наследващ елемент var2 (от тип int), неговияадрес ще стане текущия адрес на SP вмомента, т.е. adr-4, а SP ще си промениадреса на adr-8. Аналогично, при вмъкванена текущо последния елемент varlast (от типint), неговия адрес ще стане текущия адрес наSP в момента, т.е. adr-8, а SP ще си промениадреса на adr-12. Обратно, при “извличане”на елемент от стека (varlast), адресът на SPще се увеличи с 4 и ще указва на адрес adr-8. (Фиг. 9)

SP

SP

За всякафункция отпотребителскатапрограма сезаделят “зони”от програмниястек,съхраняващиданните,дефинирани внея. Тези “зони”се наричатстекови рамки.

Основа на стека

Фиг. 9

Page 8: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Обменът на данни между функциите в една С-програма :

1. Използуване на общи (външни) променливиПри дефиниране на глобални променливи достъпът до тях вблока на функциите е възможен, тъй като те са видими. Това визвестен смисъл ограничава независимостта (мобилността) им ипоследващото им използуване в други програми иливключването им като единици в други проекти, използващиразделна компилация.

2. Предаване на данни чрез входни аргументи наизвиканата функцияТова е основен подход, който се използува при предаване наданни между извиканата и извикващата функции. При негоформалните параметри, описани в прототипа на функциятаполучават посредством механизма на извикване копия настойностите на фактическите параметри, които сеизползуват при изпълнението на извиканата функция. Товапредаване (копиране) се осъществява чрез програмния стек(SP). При това имаме:

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Page 9: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Предаване на параметри (аргументи) чрез стойност - стойността нафактическия параметър се копира в т.н. стек (специална област от паметта ) ифункцията работи с това копие. Следователно всички промени във функциятаводят до промени само с копията и нямат ефект върху фактическитепараметри.Предаване на параметри чрез адрес - адресът на фактическия параметърсе копира във формалния параметър. Следователно всички промени въвфункцията водят до промени върху фактическите параметри. Предаването напараметри чрез адрес може да се моделира като се предават стойностите науказатели, които представляват адреси. По този начин в С се осигурявавъзможността за връщане на повече от една стойност в извикващата функция– ако формалния аргумент е указател, копирайки го по стойност в SP ,извиканата функция получава достъп до адреса на фактическия аргумент и бимогла да промени неговата стойност. Ако формалният параметър е указателкъм данна от агрегатен тип (масив или структура), то извиканата функцияполучава достъп до нея и може да върне съвкупност от данни в зависимост оталгоритъма й за функциониранe. При това има три начина за деклариранена параметър, предназначен за получаване указател към масив:деклариране на параметъра като масив от едноименния тип и размер нареално извиквания, деклариране на параметъра като масив без параметър идеклариране на параметъра като указател към базовия тип на реалноизвиквания масив.

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Page 10: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

float triangle_area(float sd, float hght){float area;area=(sd*hght)/2;return area;}

int main(void){float side, height;float result;cout<<"side= ";cin>>side;cout<<"height= ";cin>>height;result= triangle_area(side, height);cout<<"triangle's area= "<<result;return 0;}

Механизмът на взаимодействие междуизвикващата и извиканата функция припредаване на данни с използуване на програмниястек ще демонстрираме с изпълнимия код напримерната програма за лице на триъгълник.

Входна точка на изпълнимиякод е функцията main().

В тази точка се инициализираSP с адреса adr от сегмент 4.

Знаем, че при старт напотребителската програмасе активира процес, закойто системнатазареждаща програмазаделя дял от ОП състоящсе от 7-те блока(сегменти), разгледани по-горе. Блокове 1, 6 и 7 сазапълнени със служебнатаинформация на ОС.

В блок 2 е зареденизпълнимият код напотребителската програма,което значи, че в сегментана изпълнимия код напрограмата са раз-положени двете функцииtriangle_area(…) иmain(),

#include <iostream>using namespace std;int a, b;

7: OS-stack6: OS-Kernel

5: Dynamic Data

??????

???

4: Stack Data

2: Execution codefloat triangle_area(int side, int height){float area;area=(side*height)/2;return area;}int main(void){int side, height; float result;cout<<"side= ";cin>>side;cout<<"height= ";cin>>height;result= triangle_area( side, height );cout<<"triangle's area= "<<result;return 0;}

1:OS service

adr

?????????

???

adr-1

Фиг. 10

3: Static Data???

Page 11: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

2: Execution code#include <iostream>using namespace std;int a, b;float triangle_area(float sd, float hght){float area;area=(sd*hght)/2;return area;}int main(void){float side, height;float result;cout<<"side= ";cin>>side;cout<<"height= ";cin>>height;result= triangle_area(side, height);cout<<"triangle's area= "<<result;return 0;}

Функцията triangle_area(side, height) намиралицето на триъгълник със страна side и височинакъм нея height. Тъй като main се обръща към(извиква) triangle_area, то тази функция трябвада бъде известна преди функцията main. Зацелта във файла, съдържащ програмата сепоставя декларацията на triangle_area, а следтялото на main се написва и самата й дефиниция(или както е в примера дефиницията сеимплантира в декларацията).

float triangle_area(float sd, float hght)

Описанието на triangle_area прилича на тована функцията main. Състои се от заглавие

и тяло

{float area;area=(sd*hght)/2;return area;}

Заглавието определя, че triangle_area е имена двуаргументна функция с float аргументи.Самото име е произволен идентификатор, сидеята да бъде “говорещ”.

Запазената дума float пред името на функцията е типа й (по-точно е типа нарезултата на функцията). В кръгли сkобки и отделени със запетая са описанипараметрите със своите идентификатори. Наричат се още формални параметри.

Page 12: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

…int main(void){float side, height;float result;

****

****

****

****

****

****

****

****

****

****

****

****

7:O

S-s

tack

6:O

SK

ern

el

5:D

D ****

****

****

3:S

D

2:E

xecC

ode

1:O

Sse

rvic

e

****

****

adr

adr-

1

adr-

2

adr-

3

adr-

4

adr-

5

adr-

6

adr-

7

adr-

8

adr-

9

adr-

10

adr-

11

adr-

12

adr-

13

adr-

14

???

???

???

???

???

???

adr-

15

side height result

adr-

16

Изпълнението на програмата започва привходната точка на изпълнимия код - main().Съгласно дефиниционната част на main(),компилаторът генерира код, с който заделянеобходимата памет за локалнитепроменливи side, height, result, като гиразполага в областта на стека в реда, вкойто среща техните дефиниции. При товате получават отначало случайни стойности(означени със *).

Фиг. 11

4: Stack Data – Програмен стек

Page 13: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Следва фрагментът за управление на входа/изхода,където компилаторът генерира код, осигуряващвъвеждане на стойности на променливите side иheight. Нека за side и height са въведени числата6 и 10 съответно. В тази последователност те сезаписват в дъното на програмния стек.

0x00

0x00

0x00

0x06

0x00

0x00

0x00

0x10

****

****

****

****

7:O

S-s

tack

6:O

SK

ern

el

5:D

D ****

****

****

3:S

D

2:E

xecC

ode

1:O

Sse

rvic

e

****

****

adr

adr-

1

adr-

2

adr-

3

adr-

4

adr-

5

adr-

6

adr-

7

adr-

8

adr-

9

adr-

10

adr-

11

adr-

12

adr-

13

adr-

14

???

???

???

???

???

???

adr-

15

side height result

adr-

16

Фиг. 12

…cout<<"side= ";cin>>side;cout<<"height= ";cin>>height;

Така, на дъното на стека се оформя “блок” от памет за main с достатъчноголеми размери, който освен променливите от main съдържа и някои“вътрешни” данни. Този блок се нарича стекова рамка на main.

4: Stack Data – Програмен стек

Page 14: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Следващата инструкция извиква функциятаtriangle_area с аргументи side и height, които вслучая се наричат фактически параметри (дазабележим, че типът им е същия като насъответните им формални параметри sd и hght).Това кара компилатора най-напред да генерирапоследователност от машинни инструкции с коитода съхрани return-адреса на инструкцията следresult=triangle_area(side,height);, както и дасъхрани адреса на стековата рамка на main

0x00

0x00

0x00

0x06

0x00

0x00

0x00

0x10

****

****

****

****

7:O

S-s

tack

6:O

SK

ern

el

5:D

D ****

****

****

3:S

D

2:E

xecC

ode

1:O

Sse

rvic

e

****

****

adr

adr-

1

adr-

2

adr-

3

adr-

4

adr-

5

adr-

6

adr-

7

adr-

8

adr-

9

adr-

10

adr-

11

adr-

12

adr-

13

adr-

14

???

???

???

???

???

???

adr-

15

side height result

adr-

16

Фиг. 13

…result= triangle_area( side, height );

4: Stack Data – Програмен стек

****

****

adr-

17

adr-

18

Стекова рамка на main()

cout<<"triangle's area= "<<result;

При предаване на управлението къмизпълнимия код на triangle_area сеактивира нейното изпълнение, при коетовсички програмни обекти (променливи,константи), дефинирани в тялото наизвикващата функция main ставатнедостъпни (невидими) за извиканатафункция (в конкретния случай това сапроменливите side, height , result).

След това управлението на изчислителния процес се предава към входната точка в кода на

функцията triangle_area.

Page 15: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ0x

000x

000x

000x

060x

000x

000x

000x

10**

****

****

****

****

****

****

****

****

****

****

****

****

****

****

****

**

adr

ad

r-1

adr-

2ad

r-3

adr-

4ad

r-5

adr-

6ad

r-7

adr-

8ad

r-9

adr-

10ad

r-11

adr-

12

adr-

13ad

r-14

adr-

15ad

r-16

adr-

17ad

r-18

adr-

19ad

r-20

adr-

21ad

r-22

adr-

23

side height result

****

adr-

24**

****

****

**xx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xx

adr-

25ad

r-26

adr-

27ad

r-28

adr-

29ad

r-30

adr-

31ad

r-32

adr-

33ad

r-34

adr-

35

****

adr-

36

Стекова рамка на main() Стекова рамка на triangle_area()

4: Stack Data – Програмен стек Фиг. 14

Така, при задействане на изпълнимия код на triangle_area, в програмния стексе формира нов блок памет – стекова рамка за triangle_area . В него сезаписват формалните и локалните параметри на triangle_area , а също и някои“вътрешни” данни като return-адреса и адреса на стековата рамка на main.

hght sd area

По конкретно, в стековата рамка на triangle_area се отделят по 4 байта заформалните параметри sd и hght, които се поставят в обратен ред на реда, вкойто са записани в дефиницията. Отделят се 4В и за локалната променливаarea. Отделят се също 4B за т. нар. return-адрес (адреса на мястото в main,където ще се върне резултатът), а също се отделя памет, в която се записваадресът на предишната стекова рамка.

Return-adres

Main-stack adres

Page 16: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ0x

000x

000x

000x

060x

000x

000x

000x

10**

****

****

****

****

****

****

****

**0x

000x

000x

000x

100x

000x

000x

000x

06

adr

ad

r-1

adr-

2ad

r-3

adr-

4ad

r-5

adr-

6ad

r-7

adr-

8ad

r-9

adr-

10ad

r-11

adr-

12

adr-

13ad

r-14

adr-

15ad

r-16

adr-

17ad

r-18

adr-

19ad

r-20

adr-

21ad

r-22

adr-

23

side height result

0x00

adr-

240x

000x

000x

15

adr-

25ad

r-26

adr-

27ad

r-28

adr-

29ad

r-30

adr-

31ad

r-32

adr-

33ad

r-34

adr-

35ad

r-36

Стекова рамка на main() Стекова рамка на triangle_area()

4: Stack Data – Програмен стек Фиг. 15

hght sd area

В паметта на стековата рамка наtriangle_area се откопирватстойностите на фактически параметри– side и height на местата на технитесъответни формални “приемчиици” – sdи hght. Следва изпълнение на тялото нафункцията triangle_area, при което напроменливата area се присвояваполовината от произведението между sdи hght.

Return-adres

Main-stack adres

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

****

Свързване на формалните с фактическите параметри

float triangle_area(float sd, float hght){float area;area=(sd*hght)/2;return area;}

Page 17: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ0x

000x

000x

000x

060x

000x

000x

000x

10**

****

****

****

****

****

****

****

**0x

000x

000x

000x

100x

000x

000x

000x

06

adr

ad

r-1

adr-

2ad

r-3

adr-

4ad

r-5

adr-

6ad

r-7

adr-

8ad

r-9

adr-

10ad

r-11

adr-

12

adr-

13ad

r-14

adr-

15ad

r-16

adr-

17ad

r-18

adr-

19ad

r-20

adr-

21ad

r-22

adr-

23

side height result

0x00

adr-

240x

000x

000x

15

adr-

25ad

r-26

adr-

27ad

r-28

adr-

29ad

r-30

adr-

31ad

r-32

adr-

33ad

r-34

adr-

35ad

r-36

Стекова рамка на main() Стекова рамка на triangle_area()

4: Stack Data – Програмен стек Фиг. 15

hght sd area

Последната инструкция от тялото на triangle_area() e return area;. Тяпреустановява изпълнението на функцията и (ползвайки възвратния return-адрес), връща стойността на променливата area в мястото на прекъсванетона main, с цел продължаване изпълнението на main(). В този моментотделената за triangle_area() стекова рамка се освобождава. Указателят настека сочи края на стековата рамка на main(). Изпълнението на програматапродължава с инициализацията на променливата result. Резултатът отобръщението triangle_area(6,10) се записва в отделената за променливатаresult памет. Така променливата result се зарежда от area с изчислената йстойност. Следва извеждането на резултата на екрана (cout) и успешноприключване на програмата. При достигане до инструкцията return 0; отmain, се освобождава и стековата рамка на main.

Return-adres

Main-stack adres

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

xxxx

****

Page 18: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Функцията triangle_area реализира най-простото и “чисто” дефиниране иизползване на функции – получава входните си стойности единствено чрезформалните си параметри и връща резултата си чрез инструкцията return0;. Забелязваме, че инструкцията triangle_area (side, height); работи скопия на стойностите на side и height, запомнени в sd и hght, а не съссамите side и height. В процеса на изпълнение на тялото на triangle_area,стойностите на sd и hght се променят, но това не оказва влияние настойностите на фактическите параметри side и height.

Такова свързване на формалните с фактическите параметри сенаричасвързване по стойност или ощепредаване на параметрите по стойност.При него фактическите параметри магат да бъдат не самопроменливи, но и изрази от типове, съвместими с типовете насъответните формални параметри.

В редица случаи обаче се налага някоя функция да получи входа си чрезнякои от формалните си параметри и да върне резултат не по обичайнияначин – чрез return, а чрез същите или други параметри.

Page 19: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИНека ни е поставена задачата да се въведат стойности на реалните числа a,b, c и d, след което да се разменят стойностите на a и b и на c и d съответно.За да решим задачата, ще дефинираме функция

swap_num(double *x, double *y).Тази функция разменя стойностите на реалните числа към които сочатуказателите x и y. Така, изразът swap_num(&a, &b) ще разменя стойноститена a и b, а обръщението swap_num(&c, &d) ще разменя стойностите на c и d.

#include <iostream>using namespace std;void swap_num(double *x, double *y){double work = *x;*x = *y;*y = work;return;}int main(){ double a, b, c, d;cout << "a, b, c, d= ";cin >> a >> b >> c >> d;swap_num(&a, &b);swap_num(&c, &d);cout <<" a=" <<a <<" b="<<b;cout <<" c=" <<c<<" d="<<d<<'\n';return 0;}

Функцията swap_num има подобнаструктура като на trinagle_area. Но изаглавието, и тялото й са по-различни.Типът на swap_num е указан чреззапазената дума void. Това означава,че функцията не връща стойност чрезинструкцията return. Затова в тялото наswap_num след return няма израз.Формалните параметри x и y сауказатели към double, а в тялото нафункцията се работи със съдържаниятана указателите. Да забележим също, чеобръщенията swap_num(&a, &b);swap_num(&c, &d); не участват катооперанди в някакъв израз, а сапълноправни инструкции (функция-процедура).

Page 20: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИДефинициите на функциите main и swap_num се записват вобластта на паметта, определена за програмния код. Изпълнениетона програмата започва с изпълнение на функцията main.Фрагментът

double a, b, c, d;cout << "a, b, c, d= ";cin >> a >> b >> c >> d;

дефинира и въвежда стойности за реалните променливи a, b,c и d. Нека за стойности на a, b, c и d са въведени 2.5, 3.6,1.25 и 7.8 съответно. Инструкцията swap_num(&a, &b); сеизпълнява на два етапа :

а) Свързване на формалните с фактическите параметриВ стека се конструира нова рамка – рамката на swap_num.Oтделят се по 4 байта за формалните параметри x и y, къдетосе записват адресите на съответните им фактическипараметри, още 4B, в които се записва адресът наswap_num(&c, &d); от където трябва да се продължиизпълнението на main след връщане от swap_num(&a, &b);(т.нар. return-адрес), а също и памет, в която се записваадресът на предишната стекова рамка (в случая тази на main).

Page 21: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

Инструкцията *x = *y; променясъдържанието на x с това на y,а инструкцията *y = work;променя съдържанието на y катого свързва със стойността наwork. Инструкцията return;прекъсва работа на swap_num()и предава управлението в точкатана извикването му в главнатафункция (чрез return-адреса).Стековата рамка, отделена заswap_num се освобождава.Указателят на стека сочистековата рамка на main. Врезултат, стойностите напроменливите a и b са разменени.

void swap_num(double *x, double *y){double work = *x;*x = *y;*y = work;return;}int main(){ double a, b, c, d;cout << "a, b, c, d= ";cin >> a >> b >> c >> d;swap_num(a, b);swap_num(c, d);cout <<" a=" <<a <<" b="<<b;cout <<" c=" <<c<<" d="<<d<<'\n';return 0;}

б) Изпълнение на тялото на swap_numИзпълнява се като блок. За реалната променлива work се отделят8 байта в стековата рамка на swap_num, в които се записвасъдържанието на x, в случая 2.5.

Инструкцията swap_num(&c, &d); се изпълнява по аналогичен начин. За неясе генерира нова стекова рамка (на същите адреси), която се освобождавакогато изпълнението на swap_num(&a, &b); завърши.

Page 22: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИФункцията swap_num получава входните си стойности чрезформалните си параметри и връща резултата си чрез тях.Забелязваме, че обръщението swap_num (&a, &b) работи не скопия на стойностите на а и b, а с адресите им. В процеса наизпълнение на тялото се променят стойностите на фактическитепараметри a и b при първото обръщение към нея и на c и d – привторото.Такова свързване на формалните с фактическите параметри е:свързване на параметрите по указател или ощепредаване на параметрите по указател илисвързване по адрес.При този вид предаване на параметрите, фактическите параметризадължително са променливи или адреси на променливи.

Освен предните два начина на предаване на параметри, в езика C++ има още един – предаване на параметри по псевдоним.

Ще илюстрираме този начин чрез програма, където предаването напараметрите във функцията swap_num е по псевдоним ! Дефинициитена функциите main и swap_num се записват в областта на паметта,определена за програмния код. Изпълнението на програмата започва сизпълнение на функцията main .

Page 23: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

#include <iostream>using namespace std;void swap_num(double &x, double &y){double work = x;x = y;y = work;return;}int main(){ double a, b, c, d;cout << "a, b, c, d= ";cin >> a >> b >> c >> d;swap_num(a, b);swap_num(c, d);cout <<" a=" <<a <<" b="<<b;cout <<" c=" <<c<<" d="<<d<<'\n';return 0;}

Фрагментътcout << "a, b, c, d= ";cin >> a >> b >> c >> d;

Нека за стойности на променливите a, b, c и d отново са въведени 2.5, 3.6,1.25 и 7.8 съответно. При обработката на фрагмента се конструира стековарамка на main. Инструкцията swap_num(a, b); се изпълнява два етапа :

дефинира и въвежда стойности за реалните променливи a, b, c и d.

а) Свързване на формалнитес фактическите параметри: Встека се конструира нова рамка– рамката на swap_num. Тъйкато формалните параметри x иy са псевдоними на a и b, затях памет в стековата рамка наswap_num не се отделя.Фиктивния x се “закачва за” a ифактически го представлява .Аналогично y се “закачва за”(представлява) фактическия bот стековата рамка на main.Така всички действия с x и y вswap_num се изпълняват сфактическите a и b от mainсъответно.

Page 24: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

#include <iostream>using namespace std;void swap_num(double &x, double &y){double work = x;x = y;y = work;return;}int main(){ double a, b, c, d;cout << "a, b, c, d= ";cin >> a >> b >> c >> d;swap_num(a, b);swap_num(c, d);cout <<" a=" <<a <<" b="<<b;cout <<" c=" <<c<<" d="<<d<<'\n';return 0;}

Изпълнява се като блок. Заwork се отделят 8 байта встековата рамка на swap_num,в които се записвасъдържанието на x, в случая2.5. Инструкцията x=y;присвоява на а стойността наb, а инструкцията y=work;присвоява на b стойността наwork. Инструкцията return;прекъсва работа на swap_numи предава управлението вточката на извикването му вглавната функция (чрез return-адреса). Стековата рамка наswap_num се освобождава. Врезултат, стойностите на a и bса разменени. Променливите a иb са “освободени от“ x и y.Изпълнението на swap_num(c,d);

се реализира по същия начин .

б) Изпълнение на тялото на swap_num(a,b):

Page 25: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

1. Свързване на формалните с фактическите параметриЗа целта първият формален параметър се свързва с първияфактически, вторият формален параметър се свързва с вторияфактически и т.н. последният формален параметър се свързва споследния фактически параметър. Свързването се реализира поразлични начини в зависимост от вида на формалния параметър:а) формален параметър – стойност : В стековата рамка нафункцията за формалния параметър се отделя толкова памет,колкото типът му изисква и в нея се откопирва стойността нафактическия параметър.б) формален параметър – указател : В този случай в стековатарамка на функцията за формалния параметър се отделят 4B, в коитосе записва стойността на фактическия параметър, която е адресна променлива. Действията, описани в тялото се изпълняват съссъдържанието на формалния параметър - указател. По такъв начине възможна промяна на стойността на променливата, чийто адрес епредаден като фактически параметър.

Резюме: Обръщението към функция предизвиквагенериране на нова стекова рамка и се осъществявана следните два етапа:

Page 26: ФУНКЦИИ - tu-sliven.com · извикващата функция main стават недостъпни (невидими) за извиканата функция (в конкретния

Взаимодействие между ФУНКЦИИВзаимодействие между ФУНКЦИИ

в) формален параметър – псевдоним : Формалниятпараметър-псевдоним се свързва с адреса на фактическия. Занего в стековата рамка на функцията памет не се отделя. Тойпросто се “закачва за” (представлява) фактическия си параметър.Действията във функцията практически се извършват надфактическия параметър.

2. Изпълнение на тялото на функциятаАналогично е на изпълнението на блок. При всяко обръщениекъм функция в програмния стек за нея се заделя стекова рамка.При това, в дъното на стека е стековата рамка на main. На върхана стека е стековата рамка на функцията, която се обработва вмомента. Преди нея е стековата рамка на функцията, извикалафункцията, обработваща се в момента. Ако изпълнението на еднафункция завършва, нейната стекова рамка се отстранява отстека.