# Глава 2.1. Переменные и функции Вы познакомитесь с несколькими важными типами данных, переменными и простыми функциями. А чтобы сразу же приступить к практике, узнаете правила именования и форматирования кода. ## Правила именования Правил именования в C++ всего несколько. Они распространяются на переменные, функции, классы и другие сущности в программе. Имя _должно начинаться_ с буквы латинского алфавита или символа подчёркивания `_`: `i`, `SearchEngine`, `connect_to_db`, `_abs_val`. Символ подчёркивания в начале имени использовать [не рекомендуется:](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#nl8-use-a-consistent-naming-style) такие имена могут оказаться зарезервированными. Имя _может содержать_ только буквы, цифры и символы подчёркивания: `API_v3`, `isValid`, `catch2`. Имя _не должно совпадать_ с [ключевыми словами](https://en.cppreference.com/w/cpp/keyword) языка: `int`, `if`, `union` и другими. C++ — регистрозависимый язык. Поэтому `count`, `Count` и `COUNT` — это разные имена. Какие имена переменных составлены правильно? Перечислите номера строк через пробел. {.task_text} ``` 1 $total_volume 2 codek.meta 3 loop 4 MDFormatter 5 %TOKEN% 6 hex_val ``` ```consoleoutput {.task_source #cpp_chapter_0021_task_0010} ``` Имя `$total_volume` содержит недопустимый символ `$`. Имя `codek.meta` содержит недопустимую в названии точку. Имя `%TOKEN%` содержит недопустимый символ `%`. {.task_hint} ```cpp {.task_answer} 3 4 6 ``` ## Правила форматирования В C++ отсутствуют общепринятые правила форматирования. Например, нет разницы между пробелами и табуляцией, а наличие отступов опционально. Фигурные скобки можно ставить на любой строке. Перед вами два разных подхода к форматированию: ```cpp {.example_for_playground} int main() { int x = 5 + (2 - 1); } ``` ```cpp {.example_for_playground} int main() { int x=5+(2-1); } ``` Более того, вся программа может быть записана в одну строку, оставаясь при этом корректной. Хоть и не читабельной. ## Точка входа в программу Функция с именем `main` — это точка входа в программу (entry point). Ее наличие обязательно: после запуска программы управление передаётся именно ей. Так выглядит минимальная программа на C++, которая ничего не делает: ```cpp {.example_for_playground} int main() { } ``` Функция `main()` возвращает [целое число](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#rf-main) типа `int` вызвавшему программу окружению. Это статус завершения: - 0 в случае успеха, - другое значение в случае ошибки. В нашем примере тело функции пустое: `{ }`. Но как же тогда формируется статус завершения? Функция `main()` — особая: при отсутствии явно возвращаемого значения она возвращает 0. Для наглядности мы можем вернуть его явно: ```cpp {.example_for_playground} int main() { return 0; } ``` Чтобы обеспечить выполнение кода, удостоверьтесь, что он вызывается из функции `main()`. ## Функции При объявлении функции сначала указывается тип возвращаемого значения, потом имя функции, после него параметры. А затем тело функции, обрамлённое фигурными скобками: ![Функции в C++](https://raw.githubusercontent.com/senjun-team/senjun-courses/refs/heads/main/illustrations/cpp/function.jpg) {.illustration} Напомним, что **параметр** — это имя в определении функции. А **аргумент** — это фактическое значение, переданное функции при вызове. Рассмотрим реализацию функции `is_error()` и её вызов: ```cpp {.example_for_playground} import std; bool is_error(int http_code) { return http_code >= 300; } int main() { bool res = is_error(404); std::println("404 is error code? {}", res); return 0; } ``` ``` 404 is error code? true ``` Для возврата из функции значения мы использовали [оператор](https://en.wikipedia.org/wiki/Operator_(computer_programming)) `return`. А для вывода `res` в консоль мы сделали две вещи: - Импортировали стандартную библиотеку `std`. В ней содержится функция [println()](https://en.cppreference.com/w/cpp/io/println), отвечающая за форматированный вывод. - Вызвали `println()`. Она находится в пространстве имён (namespace) `std`, и мы указали его при вызове: `std::println()`. Вы обратили внимание, что некоторые строки в программе заканчиваются точкой с запятой? Это **инструкции** (statements) — фрагменты кода, выполняемые последовательно. {#block-statements} Напишите функцию `to_fahrenheit()`, которая: {.task_text} - Принимает вещественное число типа `double` — температуру в градусах по Цельсию. - Возвращает градусы по шкале Фаренгейта (`double`). Формула: `°F = °C × 9.0/5.0 + 32.0`. Чтобы её реализовать, воспользуйтесь операторами для сложения `+`, умножения `*` и деления `/`. {.task_text} ```cpp {.task_source #cpp_chapter_0021_task_0020} ``` Возвращаемое функцией значение, если параметр называется `celsius`: `celsius * 9.0 / 5.0 + 32.0`. {.task_hint} ```cpp {.task_answer} double to_fahrenheit(double celsius) { return celsius * 9.0 / 5.0 + 32.0; } ``` ## Переменные Чтобы создать переменную, укажите её тип и имя. А затем через оператор `=` проинициализируйте значением: ```cpp int request_count = 0; ``` После типа можно перечислять несколько переменных, разделённых запятой: ```cpp int left = -100, right = 100; ``` Однако делать так [не рекомендуется:](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#res-name-one) такой код сложно читать. Лучше заводите по одной переменной на одну строку: ```cpp int left = -100; int right = 100; ``` В некоторых языках действует правило: если переменной не задано значение явно, то она инициализируется значением по умолчанию. C++ к таким языкам не относится: ```cpp int request_count; // Здесь может быть что угодно! ``` Поэтому при создании переменной обязательно задавайте ей значение. {#block-initialization} Чтобы изменить значение переменной, применяется уже знакомый вам **оператор присваивания** (assignment operator): ```cpp double default_len = 6.7; double len = default_len; len = len + 2; // 8.7 ``` Чему равны значения `a` и `b`? Введите их через пробел. {.task_text} ```cpp {.example_for_playground .example_for_playground_004} int a = -1 int b = 4; int c = a; a = b; b = c; ``` ```consoleoutput {.task_source #cpp_chapter_0021_task_0030} ``` В этом коде значения переменных `a` и `b` меняются местами с использованием переменной `c`. {.task_hint} ```cpp {.task_answer} 4 -1 ``` ## Константы Делать константами все переменные, которые не требуется изменять — это [отличная практика.](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#rconst-immutable) Она предотвращает случайную перезапись переменной. Константы помечаются квалификатором типа [const](https://en.cppreference.com/w/cpp/language/cv). Попытка перезаписи константы приведёт к ошибке компиляции. Квалификатор `const` может стоять как слева от типа, так и справа: ```cpp const int equator_len_km = 40075; int const winter_avg_temp = -5; ``` ## Знакомство с фундаментальными типами {#block-fundamental-types} [Фундаментальные типы](https://en.cppreference.com/w/cpp/language/types) (fundamental types) — это типы, встроенные в язык. Их имена являются ключевыми словами (keywords). Рассмотрим некоторые из них: - `int` — знаковое целое: `93`, `-3`, `0`, `9'100`. - `double` — число с плавающей точкой [двойной точности:](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) `-45.5`, `1e6`, `0.0`, `NAN` (not a number), `INFINITY`. - `bool` — логическое значение: `true`, `false`. - `char` — ASCII-символ: `'a'`, `'9'`, `'\t'`, `50`. - `void` — отсутствие значения. ### Типы int и double Большие числовые значения удобно разбивать по разрядам символом штриха `'`: ```cpp int avg_dist_to_moon_km = 384'400; ``` В [литералах](https://en.wikipedia.org/wiki/Literal_(computer_programming)) типа `double` целая часть отделяется от дробной точкой. ```cpp double weight = 1008.9; ``` Тип `double` поддерживает экспоненциальную запись числа. Она удобна для компактного представления длинных значений. ```cpp double a = 3e6; // 3x10^6 = 3'000'000.0 double b = -7e-2; // -7x10^-2 = -0.07 ``` Напишите экспоненциальное представление числа 0.00002. {.task_text} Если вы раньше не работали с экспоненциальной записью, самое время [разобраться в ней.](https://urvanov.ru/2021/12/08/%D0%BD%D0%B0%D1%83%D1%87%D0%BD%D0%B0%D1%8F-%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C-%D1%87%D0%B8%D1%81%D0%BB%D0%B0/) {.task_text} ```consoleoutput {.task_source #cpp_chapter_0021_task_0040} ``` Представим число 0.00002 в виде мантиссы и порядка. Мантисса: 2. Порядок: -5. {.task_hint} ```cpp {.task_answer} 2e-5 ``` ### Тип bool Логический тип `bool` может принимать два значения: `true` и `false`. ```cpp bool is_eq = false; bool has_open_connections = true; ``` ### Тип char Переменную символьного типа `char` можно инициализировать символом в одинарных кавычках: ```cpp char letter = 'S'; ``` А можно кодом символа из [ASCII-таблицы:](https://www.asciitable.com/) ```cpp char letter = 83; ``` Тип `char` представляет собой целое число, которое _можно_ трактовать как ASCII-код. Поэтому в обоих примерах переменная `letter` содержит одно и то же значение — число 83, в ASCII-таблице соответствующее заглавной букве S латинского алфавита. ### Тип void Используйте тип `void` в качестве типа возвращаемого значения функции, если она ничего не возвращает: ```cpp {.example_for_playground} void show_warning() { std::println("Something went wrong"); } ``` Кстати, вызывать `return` в конце такой функции не обязательно. Но его можно использовать для раннего выхода (early exit): ```cpp if (!is_connection_opened) { return; } ``` ## Знакомство с библиотечными типами Итак, мы обсудили несколько встроенных в язык типов. А теперь взглянем на два типа из стандартной библиотеки C++. Они пригодятся вам уже в следующей главе: - `std::size_t` — беззнаковое целое. - `std::string` — класс, реализующий строку. Класс — это пользовательский тип данных, призванный объединять данные (поля класса) и методы по работе с ними. ### Тип std::size_t Тип [std::size_t](https://en.cppreference.com/w/cpp/types/size_t) может хранить: - Индекс элемента в контейнере. [Контейнер](https://en.cppreference.com/w/cpp/container) — это коллекция элементов. Например, переменная типа `std::size_t` может хранить индекс символа строки. - Длину контейнера. - Размер объекта в байтах. - Счетчик цикла. Под капотом `std::size_t` — псевдоним (alias) для одного из фундаментальных беззнаковых целых типов. ```cpp import std; int main() { const std::size_t i = 9; std::println("{}", i); } ``` ``` 9 ``` ### Класс std::string Тип [std::string](https://en.cppreference.com/w/cpp/string/basic_string) реализует строку, не привязанную к кодировке. Она представляет собой последовательность символов типа `char`. Если `std::size_t` — всего лишь псевдоним фундаментального типа, то `std::string` — полноценный класс, содержащий методы для работы со строкой. ```cpp import std; int main() { std::string s = "The standard string class"; // Получение символа по его индексу: const char c = s[1]; // Длина строки: const std::size_t n = s.size(); // Запись символа по индексу: s[n-1] = 'S'; std::println("{}", s); std::println("{} {}", c, n); } ``` ``` The standard string clasS h 25 ``` Из примера видно, что строковый литерал заключается в двойные кавычки. А для обращения к символу строки по индексу используется оператор `[]`. Индексация начинается с нуля. Чтобы получить размер строки, мы вызвали метод `size()`. Для вызова метода между объектом класса и именем метода ставится точка: `s.find("st")`. Точка — это тоже оператор, и он нужен для доступа к членам класса (то есть его полям и методам). У класса `std::string` есть [множество](https://en.cppreference.com/w/cpp/string/basic_string) полезных методов. Вот некоторые из них с примерами для строки `s="example"`: - `size()` возвращает длину строки: `s.size() // 7`. - `empty()` возвращает `true`, если строка пустая: `s.empty() // false`. - `insert()` вставляет заданное количество символов по указанному индексу: `s.insert(1, 2, '8') // e88xample`. - `contains()` проверяет, присутствует ли в строке подстрока или символ: `s.contains("am") // true`, `s.contains('y') // false`. Этот метод появился в C++23. ---------- ## Резюме - Функция `main()` — это точка входа в программу. - Если функция ничего не возвращает, то тип её возвращаемого значения `void`. - При создании переменных всегда инициализируйте их значением. - Неизменяемые переменные помечаются квалификатором типа `const`. - Несколько фундаментальных типов: `bool`, `int`, `double`, `char`, `void`. - Пара библиотечных типов: `std::size_t`, `std::string`.
Отправка...
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!