Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
new_Лекции_1-7.docx
Скачиваний:
127
Добавлен:
05.03.2016
Размер:
1.49 Mб
Скачать
  1. Inline-функции

При передаче управления функциям неизбежна потеря эффективности программы. Для повышения эффективности небольшие по размеру функции можно объявить как inline.

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

// Пример 5.2.9

// Пример inline-функции для получения 1-го процента числа

#include <iostream>

using namespace std;

// Заголовок inline-функции

inline double Percent (double);

// Главная функция

void main() {

setlocale( LC_ALL, "Russian"); // для вывода на экран русского текста

double number=0 , result=0;

cout << "Введите число: ";

cin >> number;

result=Percent(number);

cout << "1 процент: " << result << endl;

result =Percent(number) *50;

cout << "50 процентов: " << result << endl;

result =Percent(number)*0.5;

cout << "0.5 процента: " << result << endl;

cin.get(); cin.get();

}

// Реализация функции для получения 1-го процента числа

double Percent(double number) {

return 0.01*number;

}

  1. Рекурсия

Функция может вызывать саму себя. Это называется рекурсией. Некоторые задачи проще решаются рекурсивным способом.

Рекурсивный метод использует стековую память компьютера. Размер стека ограничен. Рекурсивная программа может завершиться ошибкой выполнения из-за нехватки стековой памяти. Рекурсия всегда может быть заменена циклом.

// Пример 5.2.10

// Посимвольный вывод строки

#include <iostream>

#include <string.h> // библиотека строковых функций С

using namespace std;

const char Str[]="Мама мыла раму."; // массив символов, строка

// объявление рекурсивной функции

void PrintStr(int);

// главная функция

void main() {

setlocale( LC_ALL, "Russian"); // для вывода на экран русского текста

PrintStr(0); // вызов рекурсивной функции

cin.get();

}

// реализация рекурсивной функции

void PrintStr(int n) {

if (n==strlen(Str)) { // strlen() - возвращает число символов в строке

cout << endl << "Рекурсивные вызовы завершены!!!" << endl;

return; //завершение рекурсивных вызовов

}

else {

cout << Str[n]; cin.get();

n++; // Str[n] - символ с номером n (нумерация с 0)

PrintStr(n); //рекурсивный вызов

}

}

// Пример 5.2.11

// Сложение N-чисел

#include <iostream>

using namespace std;

// объявление рекурсивной функции

long AddNumber(int);

// главная функция

void main(){

setlocale( LC_ALL, "Russian"); // для вывода на экран русского текста

cout << AddNumber(100000) << endl; // вызов рекурсивной функции

cin.get();

}

// реализация рекурсивной функции

long AddNumber(int n) {

if (n==0) { //завершение рекурсивных вызовов

cout << endl << "Рекурсивные вызовы завершены!!!" << endl;

return 0;

}

else {

cout << "Рекурсивный вызов при n=" << n << endl;

//cin.get();

return n+ AddNumber(n-1); //рекурсивный вызов

}

}

// Пример 5.2.12

// Нахождение N-го числа Фибоначчи рекурсией

// 1,1,2,3,5,8,13,21,34...

#include <iostream>

using namespace std;

// объявление рекурсивной функции

long fib(int n);

// главная функция

void main() {

setlocale( LC_ALL, "Russian"); // для вывода на экран русского текста

int n; long answer;

cout << "Введите номер числа Фибоначчи: ";

cin >> n;

answer=fib(n); // вызов рекурсивной функции

cout << "Значение числа Фибоначчи: " << answer << endl;

cin.get();cin.get();

}

// реализация рекурсивной функции

long fib(int n) {

cout << "Функция fib (" << n << ")...";

if (n<3) {

cout << "Возврат 1! \n";

return (1); //завершение рекурсивных вызовов

}

else {

cout << "Вызов fib (" << n-2 << ") и fib(" << n-1 << ").\n";

return ( fib(n-2)+fib(n-1) ); //рекурсивный вызов

}

}

  1. Распределение памяти при использовании функций

Распределение памяти компьютера

Когда вы запускаете программу, операционная система выделяет для нее различные области оперативной памяти, такие как область глобальных имен, область кода программы, регистры процессора, свободную память и стековую память. Глобальные переменные программы размещаются в области глобальных имен. Регистры – специальная область очень быстродействующей и дорогой по стоимости памяти, встроенная в центральный процессор. Существуют специальные регистры, называемые указателем команд (Instructions Pointer). В области кода программы находятся двоичные команды (машинные инструкции), созданные компилятором из исходного текста программы. Каждая инструкция имеет определенный адрес. В указателе команд хранится адрес следующей инструкции, которую должен выполнить процессор.

Стек – специальная область памяти, выделенная программе для хранения данных, необходимых каждой функции программы. Когда данные помещаются в стек («заталкиваются» - push) – стек растет; по мере извлечения («выталкивания» - pop) данных из стека - стек сокращается. Данные можно помещать/брать только на вершине стека. Стек похож на стопку монет (тарелок), т.е. чтобы взять самую нижнюю монету, нужно снять сначала все верхние. Размер стека ограничен. Его величину можно изменять при компоновке программы.

Вот что происходит, когда программа переходит к выполнению функции:

  1. После вызова функции увеличивается адрес в указателе команд, при этом он соответствует адресу следующей после функции инструкции. Этот адрес помещается в стек и он будет служить адресом возврата при завершении функции.

  2. В стеке выделяется место для объявленного типа возвращаемого значения. Например, если функция объявлена возвращающей int, то два байта добавляются в стек, но никакое значение туда не помещается. Если функция объявлена как void, то место для возвращаемого значения в стеке не выделяется.

  3. Адрес вызываемой функции помещается в регистр указателя команд процессора, поэтому следующая выполняемая инструкция будет инструкцией из вызванной функции.

  4. В стеке выделяется место для всех параметров функции и ее локальных переменных.

Когда функция завершает свою работу, то выполняются следующие действия:

  1. Возвращаемое значение помещается в зарезервированное в стеке место для хранения результата.

  2. Из стека выталкиваются и становятся недоступными локальные переменные и параметры функции.

  3. Возвращаемое значение, хранимое в стеке необходимо присвоить какой-либо переменной вызывающей функции, иначе оно тоже будет потеряно – вытолкнуто из стека.

  4. Адрес следующей за функцией инструкции, запомненный в стеке в момент ее вызова извлекается и помещается в указатель команд и программа продолжает свою работу.

Некоторые детали этого процесса меняются в зависимости от используемого компилятора или компьютера. Однако основные идеи процесса не зависят от оборудования. В общем случае, при вызове функции адрес возврата, параметры и локальные переменные помещаются в стек. При возврате из функции его содержимое теряется.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]