Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекцій по С.doc
Скачиваний:
7
Добавлен:
16.11.2019
Размер:
393.73 Кб
Скачать

4.4 Обчислення значення функцій

4.4. Обчислення значення функції — вихід із функції; особливості повернення та використання іменованого значення, іменованої константи

Звичайно функція повертає копію створеного (правостороннього) значення. Найпростіший випадок повернення функцією значення ілюструється прикладом

int min (int x, int y)

{

return x < y ? x : y;

}

У випадку повернення іменованих (лівосторонніх) значень можливі проблеми. Нехай маємо визначення структури дерева

struct Tree

{

int node;

Tree *left;

Tree *right;

};

Як можна уявити собі створення його вузла. Наприклад, так: локальна змінна

Tree theTree;

резервує пам’ять для полів структури, а їх заповнення відбувається у функції

Tree createTree ( int node, Tree * left, Tree * right)

{

Tree aTree;

aTree.node = node;

aTree.left = left;

newTree.right = right;

return aTree;

}

ЇЇ виклик очевидний, наприклад, такий

theTree = createTree (1, 0, 0);

Інший спосіб полягає у визначенні указника

Tree *theTreePtr;

йому необхідно відвести пам’ять під вершину і викликати функцію

theTreePtr = new Tree;

theTreePtr = createTree (1, 0, 0);

Хотілося б уникнути копіювання і одразу розмістити указник на збудований вузол. Цього можна було б досягти, додавши до функції ще один параметр

void createTree (Tree *aTree,

int node, Tree *left, Tree *right)

або змінивши тип результату на лівостороннє значення. Спочатку розглянемо дві типові помилки, які виникають при створенні іменованого значення. Вони полягають у спробі повернути адресу локального об’єкту, який не існуватиме після виходу з функції

Tree* createTree ( int node, Tree *left, Tree *right)

{

// Помилка: повернення адреси локального об’єкту

Tree aTree;

aTree.node = node;

aTree.left = left;

newTree.right = right;

return &aTree;

}

або ще не зрозуміліше

Tree& createTree ( int node, Tree *left, Tree *right)

{

// Помилка: повернення адреси локального об’єкту

Tree aTree;

aTree.node = node;

aTree.left = left;

newTree.right = right;

return aTree;

}

Інша справа, якщо в підпрограмі використати указники

Tree* createTreePtr (int node, Tree *left, Tree *right)

{

Tree *aTree;

aTree = new Tree;

aTree -> node = node;

aTree -> left = left;

aTree -> right = right;

return aTree;

}

тоді відпадає необхідність попереднього створення вузла з подальшим копіюванням

Tree *theTree;

theTree = createTreePtr (1, 0, 0);

Ось трохи складніший приклад

int& getValue (int *vi, int ix, int sx)

{

if (ix>sx) return 0;

return vi [ ix ];

}

Якщо тепер вжити виклик функції в присвоєнні справа ,то відбудеться обчислення правостороннього значення за лівостороннім значенням виразу і результат копіюється і передається в місце, визначене лівою стороною присвоєння

a = getValue( v, i, n);

Але ж функція, що повертає лівостороннє значення сама може стати зліва

getValue( v, i, n) = a;

і тоді значення a буде записане до масиву або ж такий виклик

getValue(v,1,5)++; //збільшує v[1] на 1

Якщо зміна значення лівостороннього виразу небажана перетворюємо його на сталий