⚙️ C++
Cadenas y trabajo con texto en C++17: guía detallada
Функции в C++: параметры, перегрузка и ссылки для новичков
Функции (в C++ их часто называют функциями, а не методами) — основной инструмент организации кода. Написал один раз — вызываешь когда нужно. Именно функции превращают хаотичный код в понятную программу.
Объявление и вызов функции
#include <iostream>
#include <string>
using namespace std;
// Синтаксис: тип_возврата имяФункции(тип параметр, ...) { тело }
// Без параметров и без возврата
void printSep() {
cout << "══════════════════════════════" << endl;
}
// С параметром
void greet(string name) {
cout << "Привет, " << name << "! Добро пожаловать!" << endl;
}
// Возвращает значение
int add(int a, int b) {
return a + b; // return завершает функцию и возвращает значение
}
// Несколько точек return
string classify(int n) {
if (n > 0) return "положительное";
if (n < 0) return "отрицательное";
return "ноль";
}
// Проверка простого числа
bool isPrime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
int main() {
printSep();
greet("Иван");
greet("Мария");
cout << "7 + 13 = " << add(7, 13) << endl; // 20
cout << "3 + 4 = " << add(3, 4) << endl; // 7 (сразу использовать)
cout << classify(42) << endl; // положительное
cout << classify(-5) << endl; // отрицательное
cout << classify(0) << endl; // ноль
cout << "Простые до 20: ";
for (int i=2; i<=20; i++) if (isPrime(i)) cout << i << " ";
cout << endl;
printSep();
return 0;
}
Прототипы функций (объявления)
// В C++ функцию нужно объявить ДО использования!
// Если вы вызываете функцию раньше её определения — нужен прототип.
#include <iostream>
using namespace std;
// Прототипы (объявления без тела)
double circleArea(double r);
bool isEven(int n);
void swap(int& a, int& b); // & означает ссылку
int main() {
cout << "Площадь: " << circleArea(5.0) << endl; // Работает благодаря прототипу
int x=10, y=20;
swap(x, y);
cout << "x=" << x << ", y=" << y << endl; // x=20, y=10
return 0;
}
// Определения (реализации)
double circleArea(double r) { return 3.14159 * r * r; }
bool isEven(int n) { return n % 2 == 0; }
void swap(int& a, int& b) { int tmp=a; a=b; b=tmp; }
Передача по значению vs по ссылке
Аналогия: Передача по значению — отправить КОПИЮ документа. Передача по ссылке — дать доступ к ОРИГИНАЛУ. В первом случае изменения копии не влияют на оригинал.
#include <iostream>
using namespace std;
// По значению: получаем КОПИЮ — оригинал не изменяется
void tryModify(int value) {
value = 999; // Изменяем копию
cout << "Внутри функции: " << value << endl; // 999
}
// По ссылке: получаем ССЫЛКУ — изменяем оригинал!
void modify(int& value) {
value = 999;
cout << "Внутри функции: " << value << endl; // 999
}
// Swap — классика, требует ссылок
void swap(int& a, int& b) {
int temp = a; a = b; b = temp;
}
// const ref: передаём ссылку но запрещаем изменение (для эффективности)
void printString(const string& s) {
cout << "Строка: " << s << endl;
// s = ""; // ОШИБКА: s is const reference
}
// Возврат через ссылочный параметр (для нескольких значений)
void minMax(const int arr[], int n, int& minVal, int& maxVal) {
minVal = maxVal = arr[0];
for (int i=1; i<n; i++) {
if (arr[i] < minVal) minVal = arr[i];
if (arr[i] > maxVal) maxVal = arr[i];
}
}
int main() {
int x = 42;
tryModify(x);
cout << "После tryModify: " << x << endl; // 42 — не изменился!
modify(x);
cout << "После modify: " << x << endl; // 999 — изменился!
int a=10, b=20;
swap(a, b);
cout << "a=" << a << ", b=" << b << endl; // a=20, b=10
printString("Большая строка — не копируется!");
int arr[] = {3, 1, 7, 2, 9, 4};
int minV, maxV;
minMax(arr, 6, minV, maxV);
cout << "Min=" << minV << ", Max=" << maxV << endl; // Min=1, Max=9
return 0;
}
Перегрузка функций (Overloading)
#include <iostream>
#include <cmath>
using namespace std;
// Несколько функций с одним именем — разные параметры
double area(double r) { return M_PI * r * r; } // Круг
double area(double w, double h) { return w * h; } // Прямоугольник
double area(double a, double b, double c) { // Треугольник (Герон)
double s = (a+b+c)/2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
// print для разных типов
void print(int n) { cout << "int: " << n << endl; }
void print(double d) { cout << "double: " << d << endl; }
void print(string s) { cout << "string: " << s << endl; }
void print(bool b) { cout << boolalpha << "bool: " << b << endl; }
// abs для разных типов (уже встроено, но как пример)
int myAbs(int n) { return n<0 ? -n : n; }
double myAbs(double n) { return n<0 ? -n : n; }
int main() {
cout << area(5.0) << endl; // Круг r=5
cout << area(4.0, 6.0) << endl; // Прямоугольник 4×6 = 24
cout << area(3.0, 4.0, 5.0) << endl; // Треугольник = 6
print(42); // int: 42
print(3.14); // double: 3.14
print(string("Hi")); // string: Hi
print(true); // bool: true
cout << myAbs(-7) << endl; // 7
cout << myAbs(-3.14) << endl; // 3.14
return 0;
}
Параметры по умолчанию
#include <iostream>
using namespace std;
// Параметры по умолчанию — ВСЕГДА справа!
void drawLine(int length=10, char symbol='-') {
for (int i=0; i<length; i++) cout << symbol;
cout << endl;
}
double power(double base, int exp=2) { // По умолчанию возводим в квадрат
double result = 1;
for (int i=0; i<exp; i++) result *= base;
return result;
}
void greet(string name, string greeting="Привет", string ending="!") {
cout << greeting << ", " << name << ending << endl;
}
int main() {
drawLine(); // Использует дефолты: 10 символов '-'
drawLine(20); // 20 символов '-'
drawLine(5, '*'); // 5 символов '*'
drawLine(3, '#');
cout << power(5) << endl; // 25 (5²)
cout << power(2, 10) << endl; // 1024 (2¹⁰)
cout << power(3, 3) << endl; // 27 (3³)
greet("Иван"); // Привет, Иван!
greet("Мария", "Добро пожаловать", ".");
return 0;
}
Лямбда-функции (C++11)
#include <iostream>
#include <vector>
#include <algorithm> // sort, find_if, for_each
using namespace std;
int main() {
// Лямбда: [захват](параметры) { тело }
// Простая лямбда
auto square = [](int n) { return n * n; };
cout << square(5) << endl; // 25
// Лямбда с несколькими строками
auto factorial = [](int n) {
long result = 1;
for (int i=2; i<=n; i++) result *= i;
return result;
};
cout << "5! = " << factorial(5) << endl; // 120
// Захват переменных из внешнего контекста
int threshold = 5;
auto isLarge = [threshold](int n) { return n > threshold; };
cout << isLarge(10) << endl; // 1 (true)
cout << isLarge(3) << endl; // 0 (false)
// Захват по ссылке [&]
int count = 0;
auto increment = [&]() { count++; }; // захватывает count по ссылке
increment(); increment(); increment();
cout << "count = " << count << endl; // 3
// Лямбды в алгоритмах
vector<int> nums = {5, 2, 8, 1, 9, 3, 7, 4, 6};
// Сортировка по убыванию
sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; });
cout << "Убывание: ";
for (int n : nums) cout << n << " "; // 9 8 7 6 5 4 3 2 1
cout << endl;
// Найти первое число больше 6
auto it = find_if(nums.begin(), nums.end(), [](int n) { return n > 6; });
if (it != nums.end()) cout << "Первое > 6: " << *it << endl; // 9
// Вывести все чётные
cout << "Чётные: ";
for_each(nums.begin(), nums.end(), [](int n) {
if (n%2==0) cout << n << " ";
});
cout << endl;
return 0;
}
Рекурсивные функции
#include <iostream>
using namespace std;
// Факториал
long factorial(int n) {
if (n <= 1) return 1; // Базовый случай
return n * factorial(n-1); // Рекурсивный вызов
}
// Фибоначчи
int fib(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fib(n-1) + fib(n-2);
}
// НОД (наибольший общий делитель, алгоритм Евклида)
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
int main() {
for (int i=0; i<=7; i++) cout << i << "! = " << factorial(i) << endl;
cout << "Фибоначчи: ";
for (int i=0; i<10; i++) cout << fib(i) << " ";
cout << endl;
cout << "НОД(48,18) = " << gcd(48, 18) << endl; // 6
cout << "НОД(100,75) = " << gcd(100,75) << endl; // 25
return 0;
}
Итого: что мы узнали
- ✅ Функция — блок кода с именем для многократного использования
- ✅ Прототип — объявление без тела (для использования до определения)
- ✅ Передача по значению — копия; оригинал не меняется
- ✅ Передача по ссылке (
&) — доступ к оригиналу; изменения сохраняются - ✅
const&— эффективная передача без копирования и без изменений - ✅ Перегрузка: одно имя + разные параметры — компилятор выбирает нужное
- ✅ Параметры по умолчанию — не нужно передавать все аргументы
- ✅ Лямбды — анонимные функции:
[захват](параметры) { тело }