Статья Автор: Лебедев Дмитрий

Конспект 12. Функции

Оглавление

Часть 1 Часть 2 Часть 3 Часть 4
Задачи      
       

C++_Функции. Часть 1

Функция — это выделенный блок программы, который принимает параметры, выполняет с ними какие-то действия, после чего возвращает результат. При этом функция может и не принимать параметров, а также может ничего не возвращать.

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

Так может выглядеть функция, которая возвращает максимум из двух переменных:

int max2(int a, int b) {
    if (a > b) {
        return a;
    } else {
        return b;
    }
}

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

int max3(int a, int b, int c) {
    return max2(a, max2(b, c));
}

Напишем функцию для проверки числа на простоту. Эта функция будет возвращать true для простого числа и false для составного:

bool isPrime(int x) {
    for (int i = 2; i * i <= x ; ++i) {
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}

Эту функцию можно переделать в функцию, которая находит все делители заданного числа и возвращает их в виде вектора (подумайте, как это можно сделать эффективнее, перебирая делители, квадрат которых не превосходит x):

vector<int> divisors(int x) {
    vector<int> ans;
    for (int i = 1; i <= x; ++i) {
        if (x % i == 0) {
            ans.push_back(i);
        }
    }
    return ans;
}

C++_Функции. Часть 2

Если мы изменяем значения переменных внутри функции, то переменные, которые передавались в эту функцию, меняться не будут, потому что внутри функции создаются копии переданных переменных и все изменения происходят только с копиями. Но бывают ситуации, когда необходимо поменять переданные переменные, например для реализации функции обмена значений двух переменных swap. В таком случае необходимо передавать переменные в функцию по ссылке, тогда внутри функции будут производиться действия с переданными переменными, а не с их копиями. Заметим, что функция swap ничего не должна возвращать, поэтому для типа возвращаемого значения такой функции следует использовать слово void. Например, функция swap может быть написана следующим образом:

void swap(int& x, int& y) {
    int temp = x;
    x = y;
    y = temp;
}

Рассмотрим ещё одну функцию, в которую следует передавать переменные по ссылке. Это функция, которая получает числитель и знаменатель дроби и преобразует их таким образом, что дробь становится несократимой. Например, дробь 46 следует преобразовать в несократимую дробь 23.

void reduction(int& x, int& y) {
    for (int i = x; i >= 2; --i) {
        if (x % i == 0 && y % i == 0) {
            x /= i;
            y /= i;
        }
    }
}

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


C++_Функции. Часть 3

Передача вектора по ссылке

Бывают ситуации, когда удобно передавать параметр по ссылке даже в той ситуации, когда не требуется менять переданную переменную. Например, если требуется передать в функцию вектор. Дело в том, что вектор может быть очень большим и создание его копии может потребовать слишком много времени и памяти.

Напишем функцию, которая находит максимум в векторе и получает вектор по ссылке для того, чтобы не создавалась его копия, а действия производились с исходным вектором:

int maxvector(vector<int>& v) {
    int ans = v[0];
    for (auto now : v) {
        if (now > ans) {
            ans = now;
        }
    }
    return ans;
}

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

void reversevector(vector<int>& v) {
    for (int i = 0; i < v.size() / 2; ++i) {
        swap(v[i], v[v.size() - 1 - i]);
    }
}

C++_Функции. Часть 4

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

Чтобы создать глобальную переменную, её следует объявить до всех функций, включая функцию main. Тогда эта переменная будет доступна из любой функции программы.

Например, пусть нам нужно подсчитать количество операций взятия остатка, которые совершила функция проверки числа на простоту. Заведём глобальную переменную cnt и будем увеличивать её каждый раз, когда функция проверки числа на простоту выполняет операцию взятия остатка:

int cnt = 0;
 
bool isPrime(int x) {
    for (int i = 2; i * i <= x; ++i) {
        ++cnt;
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}
 
int main() {
    isPrime(3);
    cout << cnt << endl;
    isPrime(10);
    cout << cnt << endl;
    return 0;
}

Использовать глобальные переменные следует аккуратно. Например, если внутри функции создать локальную переменную с таким же именем, как у глобальной, то далее в этой функции все действия будут совершаться с локальной переменной, а доступ к глобальной переменной потеряется. То же самое произойдёт, если в параметрах функции будет переменная с именем, которое совпадает с именем глобальной переменной.


Задачи для тренировки

1) Треугольник

 
2) Ёлочка  
3) На завод!  
4) Числа Фибоначчи  
5) Простые числа  
6) Пары по росту  
7) Среднее арифметическое  
8) Сокращение последовательности  

Печать