JavaRush /Курсы /C++ SELF /Углубляемся в переменные

Углубляемся в переменные

C++ SELF
6 уровень , 1 лекция
Открыта

1. Вспоминаем переменные

Когда вы пишете программу, она постоянно что-то считает: сумму, остаток, количество попыток, текущий счёт, выбранное имя пользователя. Если не хранить это где-то, программа будет как золотая рыбка: три секунды — и всё, контекст потерян. Переменная как раз и нужна, чтобы у программы появилась «память» хотя бы на время выполнения.

Прежде чем углубиться в этот вопрос, давайте вспомним, что вы уже знаете о переменных.

Переменную удобно представлять как маленький контейнер с наклейкой. Наклейка — это имя переменной, контейнер имеет определённый тип (какой «формы» данные можно хранить), а внутри лежит текущее значение. И вот эта тройка — тип + имя + значение — и есть рабочая модель переменной.

Сразу маленькая таблица, чтобы закрепить образ:

Что это Как выглядит в коде Что означает
Тип
int, std::string
«какие значения можно хранить»
Имя
score, age, name
«как к этому обращаться в коде»
Значение
10, "Alex"
«что там лежит прямо сейчас»

Мы пока не углубляемся в разные виды типов (это будет следующая лекция уровня). Но важно запомнить: тип — это не украшение. Он задаёт правила игры: что можно делать с переменной и какие значения в неё помещаются.

2. Объявление и инициализация

С переменными у новичков часто путаница из-за того, что в одной и той же строчке мы делаем сразу два действия. Когда вы пишете int x = 10;, вы одновременно «объявляете» переменную (сообщаете компилятору её тип и имя) и «инициализируете» (даёте стартовое значение). Это как завести банковский счёт и сразу положить туда первые деньги — не обязательно, но очень разумно.

В рамках курса у нас будет простое правило безопасности: переменная должна получать начальное значение при объявлении. Это экономит время и спасает от странных багов, когда вы случайно используете значение «из ниоткуда».

Мини‑пример: переменная появляется и сразу получает число.

#include <iostream>

int main() {
    int score = 10;                 // создали переменную score со значением 10
    std::cout << score << '\n';      // 10
}

Обратите внимание: слово int — часть объявления. Пока вы не написали тип, переменная ещё не «создана». Имя тоже важно: компилятор должен знать, как к ней обращаться дальше.

Ещё пример: переменная инициализируется выражением. Это всё ещё инициализация — просто справа не «готовое число», а выражение.

#include <iostream>

int main() {
    int a = 3;
    int b = 4;

    int sum = a + b;                // sum создаётся и сразу получает 7
    std::cout << sum << '\n';        // 7
}

Здесь очень полезно проговаривать себе так: «создаю sum, вычисляю a + b, записываю результат в sum».

3. Присваивание: изменить значение существующей переменной

После того как переменная создана, вы можете обновлять то, что лежит внутри. Это уже другое действие — присваивание. И вот тут появляется ключевая мысль лекции: символ = в C++ означает не “равно”, а “записать новое значение”.

Проще всего запомнить так:

  • инициализация — это «создать переменную»;
  • присваивание — это «обновить уже существующую».

Пример: сначала создаём переменную, потом изменяем.

#include <iostream>

int main() {
    int score = 10;                 // создать
    score = 20;                     // изменить

    std::cout << score << '\n';     // 20
}

А теперь более «живой» пример: меняем значение с использованием старого.

#include <iostream>

int main() {
    int score = 10;

    score = score + 5;              // справа вычисляем 10 + 5, результат 15 записываем в score
    std::cout << score << '\n';     // 15
}

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

То есть это НЕ «уравнение» и не «равенство». Это скорее команда: «возьми текущее значение score, прибавь 5, и сохрани обратно в score».

4. Выражения и операторы = и ==

Правая часть — выражение

Когда вы видите строку вида x = ...;, справа почти всегда стоит выражение. Выражение — это кусок кода, который можно вычислить в одно значение. Там может быть просто число, может быть переменная, может быть формула, а может быть даже результат чтения из std::cin (но обычно cin используют отдельной строкой, чтобы было читабельно).

Посмотрим на несколько вариантов и потренируем взгляд.

#include <iostream>

int main() {
    int x = 5;
    int y = 2;

    int a = x;                      // выражение справа — просто x
    int b = x + y;                  // выражение — сумма
    int c = (x + y) * 10;           // выражение — более сложная формула

    std::cout << a << ' ' << b << ' ' << c << '\n';  // 5 7 70
}

Главная привычка, которую мы вырабатываем: в каждой строке присваивания задавайте себе вопрос: «Что вычисляется справа?» и «Куда это записывается слева?».

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

= — это не сравнение

Путаница между = и “равно” — настолько классическая, что её можно считать «обрядом посвящения». Почти каждый новичок хотя бы раз пишет в условии if (x = 10), а потом удивляется, что программа ведёт себя… скажем так… творчески.

Важно:

  • =присваивание (изменяет переменную),
  • ==сравнение (даёт true или false).

Сравнение вы уже проходили раньше, но сегодня мы добавим акцент: ошибка = вместо == — это ошибка смысла, а не синтаксиса. Иногда компилятор даже не ругнётся так, как вам хотелось бы.

Мини‑пример (покажем как «нельзя», но без углубления):

#include <iostream>

int main() {
    int x = 3;

    // if (x = 10) {                 // плохо: вы меняете x на 10
    //     std::cout << "x is 10\n";
    // }

    if (x == 10) {                   // хорошо: вы сравниваете x с 10
        std::cout << "x is 10\n";
    } else {
        std::cout << "x is not 10\n"; // x is not 10
    }
}

Мы не будем сейчас подробно разбирать, почему if (x = 10) может компилироваться. Нам важнее практическое правило: если вы в голове произнесли “проверим, равно ли” — в коде почти всегда должен быть ==.

5. Область видимости: где переменная «видна»

Когда программа становится больше, появляется очень практичный вопрос: «А где эта переменная вообще доступна?» В C++ ответ связан с фигурными скобками { ... }. Блок кода задаёт область видимости: имя переменной видно от места объявления до конца текущего блока.

Это похоже на бейджик на конференции: внутри зала все знают, кто вы, а за дверью охрана такая: «Извините, вы кто вообще?». (Компилятор в роли охраны — это отдельный сериал.)

Вот простой пример:

#include <iostream>

int main() {
    int x = 1;

    {
        int y = 2;
        std::cout << (x + y) << '\n';    // 3
    }

    std::cout << x << '\n';             // 1
    std::cout << y << '\n';             // ошибка: y здесь не существует
}

Здесь x объявлена во внешнем блоке main, поэтому она видна и снаружи, и внутри внутреннего блока. А y объявлена во внутреннем блоке, и снаружи её уже нет.

Почему это нужно? Потому что scope помогает держать порядок в голове: переменная «живет» там, где она действительно нужна, и не мешает остальному коду.

Очень часто scope появляется естественно через if и циклы. Например, переменная, объявленная внутри if, не обязана существовать после него.

#include <iostream>

int main() {
    int temperature = 30;

    if (temperature > 25) {
        int extraWater = 2;
        std::cout << extraWater << '\n'; // 2
    }

    std::cout << extraWater << '\n';  // ошибка: переменная умерла вместе с блоком
}

И да, формулировка «умерла» тут внезапно очень точная: после закрывающей } имя перестаёт быть доступным, как будто его никогда и не было.

6. Мини‑приложение: «копилка» и обновление баланса

Чтобы переменные не остались абстрактной философией, соберём маленький консольный сценарий, который вы сможете расширять дальше по курсу. Пусть это будет «копилка» (или баланс), куда мы добавляем и откуда вычитаем. Сегодня нас интересует именно разница между созданием значения и изменением.

Начнём с минимального: есть стартовый баланс и пополнение.

#include <iostream>

int main() {
    int balance = 0;                     // стартовое значение

    int deposit = 0;
    std::cin >> deposit;                 // вводим пополнение

    balance = balance + deposit;          // обновляем баланс
    std::cout << balance << '\n';         // зависит от ввода
}

Здесь сразу видно два слоя:

Первый слой — «создать переменные»: balance, deposit. Мы их объявили и инициализировали нулями, чтобы они точно имели понятное значение.

Второй слой — «изменить состояние программы»: мы считали deposit и обновили balance. Обновление делается через присваивание, и правая часть — это выражение balance + deposit.

Добавим ещё одно действие: расход. Это всё те же переменные, всё та же механика, просто мы делаем присваивание несколько раз.

#include <iostream>

int main() {
    int balance = 0;

    int deposit = 0;
    std::cin >> deposit;

    balance = balance + deposit;

    int spend = 0;
    std::cin >> spend;

    balance = balance - spend;

    std::cout << balance << '\n';         // итоговый баланс
}

Если вы внимательно посмотрите, то увидите «шаблон»:

1) создать переменную,
2) получить значение,
3) обновить состояние другой переменной.

Это один из самых типичных паттернов в программировании. И сегодня наша задача — научиться видеть его глазами, а не только руками печатать.

Схема присваивания: порядок действий

Иногда помогает не код, а маленькая картинка. Присваивание можно мысленно разложить на шаги: вычислить правую часть, затем записать в левую часть. Это как заказ в кафе: сначала приготовили блюдо, потом положили на тарелку. Нельзя «положить на тарелку» то, что ещё не приготовлено.

Вот упрощённая блок‑схема:

flowchart TD
    A["Строка: x = выражение;"] --> B["Вычислить выражение справа"]
    B --> C["Получить результат (одно значение)"]
    C --> D["Записать результат в x"]
    D --> E["x теперь хранит новое текущее значение"]

Если вы ловите себя на мысли «почему оно так посчитало», очень часто причина в том, что вы неправильно представляете этот порядок. Особенно когда справа тоже встречается x (как в x = x + 5;): сначала вычисление, потом запись.

7. Типичные ошибки

Ошибка №1: использовать переменную до объявления.
Это выглядит невинно: вы пишете std::cout << total << '\n';, а потом ниже добавляете int total = 0;. Для человека это «почти рядом», а для компилятора — строгий порядок: пока переменная не объявлена, её имени не существует. Лечится просто: объявляйте переменную до первого использования, и лучше максимально близко к месту, где она реально нужна.

Ошибка №2: считать, что = — это математическое равенство.
В математике x = x + 1 звучит как бред (и преподаватель матанализа уже тянется к мелу). В программировании это нормальная команда обновления: «возьми старое значение x, прибавь 1, сохрани обратно». Если постоянно помнить “справа вычислили → слева записали”, эта путаница постепенно исчезает.

Ошибка №3: путать = и == в условиях.
Это тот случай, когда программа может начать «работать», но делать не то. Вы хотели сравнить, а вместо этого меняете значение переменной прямо внутри условия. Даже если компилятор выдаст предупреждение, новичок часто его игнорирует, потому что «ну оно же запускается». Дисциплина простая: если вы читаете это как «равно ли», пишите ==.

Ошибка №4: объявлять переменную слишком рано и делать огромную область видимости.
Новички иногда объявляют десяток переменных в начале main, «потому что так спокойнее». В итоге половина из них не используется до середины программы, вы забываете, что где хранится, и начинаются магические числа и “а почему оно поменялось?”. Гораздо проще объявлять переменные прямо перед тем, как они впервые понадобились — так scope получается маленьким, а код читается легче.

Ошибка №5: объявлять переменную внутри блока и ждать, что она будет доступна снаружи.
Очень распространённая ситуация: внутри if вы посчитали discount, а потом ниже пытаетесь применить его к цене. Но discount объявлен внутри { ... }, значит, снаружи он не существует. Решение — объявить переменную снаружи и обновлять внутри (если по смыслу она должна жить дольше), либо перенести использование внутрь блока, если оно действительно относится только к этому сценарию.

1
Задача
C++ SELF, 6 уровень, 1 лекция
Недоступна
Двойная сумма
Двойная сумма
1
Задача
C++ SELF, 6 уровень, 1 лекция
Недоступна
Смена мест
Смена мест
1
Задача
C++ SELF, 6 уровень, 1 лекция
Недоступна
Копилка дня
Копилка дня
1
Задача
C++ SELF, 6 уровень, 1 лекция
Недоступна
Карточная скидка
Карточная скидка
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ