Функция в C++ — фрагмент программного кода, к которому можно обратиться из другого места программы.
У функции, чаще всего, имеется имя, тело и параметры.
С именем функции неразрывно связан адрес первой инструкции в теле функции, которой передаётся управление при обращении к функции. После выполнения функции управление возвращается обратно в точку программы, откуда данная функция была вызвана.
Функция может принимать параметры и должна возвращать некоторое значение, возможно пустое.
Пример объявления функции:
Тип_функции Имя_функции (Список_параметров) {
Тело функции
}
Тип функции — это тип возвращаемого функцией значения.
Список параметров функции — это объявление переменных для передачи через них значений в тело функции.
В объектно-ориентированном программировании функции, объявления которых являются неотъемлемой частью определения класса, называются методами. Также в языках с ООП возможно объявление абстрактной (виртуальной) функции без объявления тела функции.
Для того, чтобы использовать ранее определённую функцию, необходимо в требуемом месте программного кода указать имя функции и перечислить передаваемые в функцию параметры. Параметры, которые передаются функции, могут передаваться как по значению, так и по ссылке: для переменной, переданной по значению создаётся локальная копия и любые изменения, которые происходят в теле функции с переданной переменной, на самом деле, происходят с локальной копией и никак не сказываются на самой переменной, в то время как изменения, которые происходят в теле функции с переменной, переданной по ссылке, происходят с самой переданной переменной.
int umnominus(int x, int y, int z){
int l = x * y - z;
return l;
}
void setup() {
Serial.begin(9600);
Serial.print(umnominus(4, 1, 100));
}
void loop() {
}
Лист. 1. Создана функция umnominus().
int area(int a, int b){
return a * b;
}
void setup() {
Serial.begin(9600);
Serial.print(area(3, 5));
}
void loop() {
}
Лист. 2. Создана функция area() для вычисления площади прямоугольника.
float area(int a, int b){
return a * b / 2;
}
void setup() {
Serial.begin(9600);
Serial.print(area(3, 5));
}
void loop() {
}
Лист. 3. Создана функция area() для вычисления площади треугольника.
Функция area() в примере листинг 3 вычисляет площадь треугольника с погрешностью. Причём, эту погрешность вычислений мы можем заметить только если произведение параметров a и b нечётное.
float area(int a, float b){
return a * b / 2;
}
void setup() {
Serial.begin(9600);
Serial.print(area(3, 5));
}
void loop() {
}
Лист. 4. Создана функция area() для вычисления площади треугольника.
float area(int a, int b){
return a * b / 2.0;
}
void setup() {
Serial.begin(9600);
Serial.print(area(3, 5));
}
void loop() {
}
Лист. 5. Создана функция area() для вычисления площади треугольника.
Функция определяет собственную (локальную) область видимости, куда входят входные параметры, а также те переменные, которые объявляются непосредственно в теле самой функции.
Существует возможность вызвать функцию внутри самой функции: такой вызов функции называется рекурсивным, а сам процесс последовательных вложенных друг в друга вызовов функций называют рекурсией.
Вычисление факториала
апрвапр
Рис. 1.
jhfjh
unsigned long factorial(int a){
unsigned long f = 1;
for(int n = 1; n <= a; n++)
f *= n;
return f;
}
void setup() {
Serial.begin(9600);
Serial.println(factorial(12));
}
void loop() {
}
Лист. 6.
unsigned long factorial(int a){
if(a==1) return 1;
return a * factorial(a-1);
}
void setup() {
Serial.begin(9600);
Serial.println(factorial(12));
}
void loop() {
}
Лист. 7.
Conway's Game of Life
Воспользуемся примером из библиотеки MaxAndMatrix для создания игры Жизнь на светодиодной матрице 8х8.
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b01110001,
0b11011011,
0b10001110,
0b10001100,
0b10001000,
0b11111111,
0b10000001,
0b11111111
};
void setup() {
led88.begin(0);
led88.force(0);
led88.loadMatrix(matrix);
}
void loop() {
}
Лист. 8. Пример из библиотеки MaxAndMatrix
Рис. 1. Принципиальная электрическая схема LED дисплея 8x8 с микросхемой MAX7219 управляемого микроконтроллером ATtiny88.
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b00011000,
0b00100100,
0b01000010,
0b10000001,
0b10000001,
0b01000010,
0b00100100,
0b00011000
};
byte conways[64];
void setup() {
led88.begin(0);
led88.force(4);
for(int i=0; i<64; i++){
conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
}
}
void loop() {
}
Лист. 9. Преобразование массива в массив.
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b00011000,
0b00100100,
0b01000010,
0b10000001,
0b10000001,
0b01000010,
0b00100100,
0b00011000
};
byte conways[64];
void setup() {
led88.begin(0);
led88.force(4);
for(int i=0; i<64; i++){
conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
}
}
void loop() {
toled();
delay(200);
}
void toled(){
byte matrix[8] {0,0,0,0,0,0,0,0};
for(int i=0; i<64; i++)
matrix[i/8] |= conways[i] << (i % 8);
led88.loadMatrix(matrix);
}
Лист. 10. Преобразование массива в массив и вывод на матрицу.
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b00011000,
0b00100100,
0b01000010,
0b10000001,
0b10000001,
0b01000010,
0b00100100,
0b00011000
};
byte conways[64];
void setup() {
Serial.begin(9600);
led88.begin(0);
led88.force(4);
for(int i=0; i<64; i++){
conways[i] = (matrix[i/8] & 1<<(i%8)) == 0 ? 0 : 1;
}
for(int i=0; i<64; i++){
Serial.print(romie(i));
}
}
void loop() {
toled();
delay(200);
}
int romie(int n){
int m = 0;
for(int i=-8; i<=8; i+=8)
for(int j=-1; j<=1; j++)
if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
m += conways[i + j + n];
return m;
}
void toled(){
byte matrix[8] {0,0,0,0,0,0,0,0};
for(int i=0; i<64; i++)
matrix[i/8] |= conways[i] << (i % 8);
led88.loadMatrix(matrix);
}
Лист. 11. Создана функция romie()
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
byte matrix[8] = {0b00011000,
0b00100100,
0b01000010,
0b10000001,
0b10000001,
0b01000010,
0b00100100,
0b00011000
};
byte conways[64];
void setup() {
led88.begin(0);
led88.force(4);
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
conways[i*8+j] = (matrix[i] & 1<<j) == 0 ? 0 : 1;
}
}
}
void loop() {
toled();
live();
delay(200);
}
void live(){
byte next[64];
for(int n=0; n<64; n++){
next[n] = 0;
int m = romie(n);
if(m == 3)
next[n] = 1;
else if(m == 2)
next[n] = conways[n];
}
for(int i=0; i<64; i++)
conways[i] = next[i];
}
int romie(int n){
int m = 0;
for(int i=-8; i<=8; i+=8)
for(int j=-1; j<=1; j++)
if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
m += conways[i + j + n];
return m;
}
void toled(){
byte matrix[8] {0,0,0,0,0,0,0,0};
for(int i=0; i<64; i++)
matrix[i/8] |= conways[i] << (i % 8);
led88.loadMatrix(matrix);
}
Лист. 12. Игра «Жизнь» (англ. Game of Life) — клеточный автомат Джона Конвея (John Horton Conway 26 December 1937 – 11 April 2020).
#include "MaxAndMatrix.h"
int dataPin = 12; // DIN
int clockPin = 11; // CLK
int csPin = 10; // LOAD (CS)
MaxAndMatrix led88 = MaxAndMatrix(dataPin, clockPin, csPin);
// Салют
//byte matrix[8] = {0b00011000,
// 0b00100100,
// 0b01000010,
// 0b10000001,
// 0b10000001,
// 0b01000010,
// 0b00100100,
// 0b00011000
// };
// Маленькие часики
//byte matrix[8] = {0b00000000,
// 0b00000000,
// 0b00001000,
// 0b00101000,
// 0b00010100,
// 0b00010000,
// 0b00000000,
// 0b00000000
// };
// Лягушка
//byte matrix[8] = {0b00000000,
// 0b00000000,
// 0b00000000,
// 0b00011100,
// 0b00111000,
// 0b00000000,
// 0b00000000,
// 0b00000000
// };
// Змея
//byte matrix[8] = {0b11000000,
// 0b10100000,
// 0b00000000,
// 0b00101000,
// 0b00000000,
// 0b00001010,
// 0b00000001,
// 0b00000011
// };
// Указатель
//byte matrix[8] = {0b00000000,
// 0b00000000,
// 0b00110000,
// 0b00110000,
// 0b00001100,
// 0b00001100,
// 0b00000000,
// 0b00000000
// };
// Муравей
//byte matrix[8] = {0b00001000,
// 0b00101000,
// 0b01000010,
// 0b10111100,
// 0b01000010,
// 0b00101000,
// 0b00001000,
// 0b00000000
// };
// Скорпион
//byte matrix[8] = {0b00010000,
// 0b00010100,
// 0b01000000,
// 0b00111110,
// 0b01000000,
// 0b00010100,
// 0b00010000,
// 0b00000000
// };
// Часы
//byte matrix[8] = {0b10110110,
// 0b11010100,
// 0b00010010,
// 0b11000110,
// 0b10010000,
// 0b01010110,
// 0b11011010,
// 0b00000000
// };
// Медуза
//byte matrix[8] = {0b01100000,
// 0b10010000,
// 0b10101000,
// 0b01001110,
// 0b00000000,
// 0b00011000,
// 0b00010000,
// 0b00000000
// };
// Осьминог
byte matrix[8] = {0b00000000,
0b00000000,
0b00011000,
0b00100100,
0b00111100,
0b10100101,
0b11000011,
0b00000000
};
byte conways[64];
void setup() {
led88.begin(0);
led88.force(4);
for(int i=0; i<8; i++){
for(int j=0; j<8; j++){
conways[i*8+j] = (matrix[i] & 1<<j) == 0 ? 0 : 1;
}
}
toled();
delay(3000);
}
void loop() {
toled();
live();
delay(200);
}
void live(){
byte next[64];
for(int n=0; n<64; n++){
next[n] = 0;
int m = romie(n);
if(m == 3)
next[n] = 1;
else if(m == 2)
next[n] = conways[n];
}
for(int i=0; i<64; i++)
conways[i] = next[i];
}
int romie(int n){
int m = 0;
for(int i=-8; i<=8; i+=8)
for(int j=-1; j<=1; j++)
if((n+i+j >= 0 and n+i+j < 64 and (n+i)/8 == (n+i+j)/8) and n+i+j != n)
m += conways[i + j + n];
return m;
}
void toled(){
byte matrix[8] {0,0,0,0,0,0,0,0};
for(int i=0; i<64; i++)
matrix[i/8] |= conways[i] << (i % 8);
led88.loadMatrix(matrix);
}
Лист. 13. Игра «Жизнь» (англ. Game of Life) — клеточный автомат Джона Конвея с примерами
Не обязательные параметры
Язык C++ допускает использование не обязательных параметров функций по умолчанию. В среде Arduino если вы вызываете функцию с параметрами по умолчанию до её объявления в тексте программы, возникает ошибка.
Например,
void setup() {
Serial.begin(115200);
}
void loop() {
fn(7);
}
void fn(int x = 4) {
Serial.println(x * 2);
}
Лист. 14.
error: 'fn' was not declared in this scope
fn(7);
^~
exit status 1
'fn' was not declared in this scope
Лист. 15.
Прототипы функций
В этой ситуации поможет практика объявления функций до их использования или объявление виртуальных функций.
void fn(int x=4);
void setup() {
Serial.begin(115200);
}
void loop() {
fn(7);
}
void fn(int x) {
Serial.println(x * 2);
}
Лист. 16.
Перегрузка функций
Перегрузка функций в C++ — это возможность определять функции с одним и тем же именем, но разным набором параметров.
int a = 10;
int b = 5;
float c = 10.0;
void summator(int x, int y) {
Serial.println(x + y);
}
void summator(int x, float y) {
Serial.println(x * y);
}
void setup() {
Serial.begin(9600);
summator(a, b);
summator(b, c);
}
void loop() {
}
Лист. 17.