Урок №10. Переменные, Инициализация и Присваивание

  Юрий  | 

  |

  Обновл. 11 Сен 2021  | 

 224204

 ǀ   31 

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

Переменные

Cтейтмент a = 8; выглядит довольно простым: мы присваиваем значение 8 переменной a. Но что такое a? a — это переменная, объект с именем.

На этом уроке мы рассмотрим только целочисленные переменные. Целое число — это число, которое можно записать без дроби, например: -11, -2, 0, 5 или 34.

Для создания переменной используется стейтмент объявления (разницу между объявлением и определением переменной мы рассмотрим несколько позже). Вот пример объявления целочисленной переменной a (которая может содержать только целые числа):

При выполнении этой инструкции центральным процессором часть оперативной памяти выделяется под этот объект. Например, предположим, что переменной a присваивается ячейка памяти под номером 150. Когда программа видит переменную a в выражении или в стейтменте, то она понимает, что для того, чтобы получить значение этой переменной, нужно заглянуть в ячейку памяти под номером 150.

Одной из наиболее распространенных операций с переменными является операция присваивания, например:

Когда процессор выполняет эту инструкцию, он понимает её как «поместить значение 8 в ячейку памяти под номером 150».

Затем мы сможем вывести это значение на экран с помощью std::cout:

l-values и r-values


В языке C++ все переменные являются l-values. l-value (в переводе «л-значение», произносится как «ел-валью») — это значение, которое имеет свой собственный адрес в памяти. Поскольку все переменные имеют адреса, то они все являются l-values (например, переменные a, b, c — все они являются l-values). l от слова «left», так как только значения l-values могут находиться в левой стороне в операциях присваивания (в противном случае, мы получим ошибку). Например, стейтмент 9 = 10; вызовет ошибку компилятора, так как 9 не является l-value. Число 9 не имеет своего адреса в памяти и, таким образом, мы ничего не можем ему присвоить (9 = 9 и ничего здесь не изменить).

Противоположностью l-value является r-value (в переводе «р-значение», произносится как «ер-валью»). r-value — это значение, которое не имеет постоянного адреса в памяти. Примерами могут быть единичные числа (например, 7, которое имеет значение 7) или выражения (например, 3 + х, которое имеет значение х плюс 3).

Вот несколько примеров операций присваивания с использованием r-values:

Давайте детально рассмотрим последнюю операцию присваивания:

Здесь переменная b используется в двух различных контекстах. Слева b используется как l-value (переменная с адресом в памяти), а справа b используется как r-value и имеет отдельное значение (в данном случае, 12). При выполнении этого стейтмента, компилятор видит следующее:

И здесь уже понятно, какое значение присваивается переменной b.

Сильно беспокоиться о l-values или r-values сейчас не нужно, так как мы еще вернемся к этой теме на следующих уроках. Всё, что вам нужно сейчас запомнить — это то, что в левой стороне операции присваивания всегда должно находиться l-value (которое имеет свой собственный адрес в памяти), а в правой стороне операции присваивания — r-value (которое имеет какое-то значение).

Инициализация vs. Присваивание

В языке C++ есть две похожие концепции, которые новички часто путают: присваивание и инициализация.

После объявления переменной, ей можно присвоить значение с помощью оператора присваивания (знак равенства =):

В языке C++ вы можете объявить переменную и присвоить ей значение одновременно. Это называется инициализацией (или «определением»).

Переменная может быть инициализирована только после операции объявления.

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

Правило: Если у вас изначально имеется значение для переменной, то используйте инициализацию, вместо присваивания.

Неинициализированные переменные


В отличие от других языков программирования, языки Cи и C++ не инициализируют переменные определенными значениями (например, нулем) по умолчанию. Поэтому, при создании переменной, ей присваивается ячейка в памяти, в которой уже может находиться какой-нибудь мусор! Переменная без значения (со стороны программиста или пользователя) называется неинициализированной переменной.

Использование неинициализированных переменных может привести к ошибкам, например:

В этом случае компилятор присваивает переменной a ячейку в памяти, которая в данный момент свободна (не используется). Затем значение переменной a отправляется на вывод. Но что мы увидим на экране? Ничего, так как компилятор это не пропустит — выведется ошибка, что переменная a является неинициализированной. В более старых версиях Visual Studio компилятор вообще мог бы вывести какое-то некорректное значение (например, 7177728, т.е. мусор), которое было бы содержимым той ячейки памяти, которую он присвоил нашей переменной.

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

Хорошей практикой считается всегда инициализировать свои переменные. Это будет гарантией того, что ваша переменная всегда имеет определенное значение и вы не получите ошибку от компилятора.

Правило: Убедитесь, что все ваши переменные в программе имеют значения (либо через инициализацию, либо через операцию присваивания).

Тест

Какой результат выполнения следующих стейтментов?

Ответы


Чтобы просмотреть ответ, кликните на него мышкой.

Ответ №1

Программа выведет 3: a – 3 = 3, что и присваивается переменной a.

Ответ №2

Программа выведет 3: переменной b присваивается значение переменной a (3).

Ответ №3

Программа выведет 6: a + b = 6. Здесь не используется операция присваивания.

Ответ №4

Программа выведет 3: значением переменной a до сих пор является 3.

Ответ №5

Результатом будет ошибка, так как c — это неинициализированная переменная.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (1 564 оценок, среднее: 4,93 из 5)
Загрузка...

Комментариев: 31

  1. Миха:

    "Объект — это часть памяти, которая может хранить значение. В качестве аналогии мы можем использовать почтовый ящик, куда мы помещаем информацию и откуда её извлекаем. Все компьютеры имеют оперативную память, которую используют программы. При создании объекта, часть оперативной памяти выделяется для этого объекта. Большинство объектов, с которыми мы будем работать в языке C++, являются переменными."
    Хмм. насколько верно, что переменная — это объект? Это минимальная единица манипулирования объектом (переменная — ссылка на ячейку памяти.). Если рассматривать вашу аналогию, то объект-почтовый ящик, а переменная — письмо(Хотя и письмо — тоже объект. А вот буква в письме — переменная).

    1. Denis Gusev:

      Нет, в вашей аналогии переменная — это номер почтового ящика, по которому мы отправляем письмо (r-value).

      1. N%1=W:

        тогда лучше по аналогии int объект встречает от родных b письмо в 10 ваш адрес на почту
        вам надо узнать что за письмо b послали родные и вот
        std::cout почтальон доставляет b если адрес не написан то на почте int по инструкции должен быть адресат вот и пишут любое удобное

  2. Сергей:

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

    1. Адольф:

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

    2. Владислав:

      Читай комментарий(5 вычисляется в 5, которое затем присваивается переменной а). Это для наглядности сделано, типа что бы ты понял как присвоить значение. Но на практике такое особо не делается без вывода. Если не понятно то что я сказал то напиши cout <<a<<endl; после(a = 5;) и напиши cout <<a <<endl; после (a = 4 + 6;)

    3. **No Name**:

      Это же очевидно! Например:
      Вам нужно запомнить координаты движущегося квадрата.
      Таким образом Ваш код будет такой:

      И соответственно отрисовка квадрата. А в y и x у вас координаты.
      Переменная от слова менять.

  3. ХейЛонг:

    Левое значение, оперативка. Сразу видно чёткого программера, не заморачивающегося стилистикой речи. Но это я так, не по теме =) По крайней мере, с начала изучения твоего ресурса я не испытываю ощутимого дискомфорта в понимании материала. Надеюсь, эта тенденция сохранится впредь.

  4. Алексей:

    Все отлично, было 13 лет назад баловался на С. Универ требовал и надо было.
    Сейчас вспоминаю, изучаю.
    Пишу эти простые проги на Ubuntu, неинициализированная переменная при выводе выдаст 0.

    1. SagePtr:

      Далеко не всегда 0. Тут как повезёт. Локальные переменные не инициализируются точно. Если у вас всегда 0, возможно, проверяете на какой-нибудь простецкой программе, которую компилятор вполне мог заоптимизировать и поменять переменную на константу, видя, что с ней ничего кроме вывода на экран не происходит.

  5. Dulat:

    Храни тебя господь, Юрий!)
    Благодарю вас урок очень понравился, так доступно объясняете.

    1. Фото аватара Юрий:

      Спасибо, что читаете 🙂

  6. Nub:

    [quote]

    При выполнении этого стейтмента, компилятор видит следующее:

    [/quote]

    Откуда компилятор видит, что b == 10?
    То, что b равно 10 будет известно только в рантайме, нет?

  7. Rizo:

    Скажите пожалуйста. Задумался об изучении программирования, учусь в техюунивере по профессии программная-инженерия. В приоритете такие языки как С++ и JavaScript. скажите пожалуйста, что лучше изучить сначала. Если С++ то за какое время смогу освоить ее нормально. JS рассматриваю в качестве быстро устроиться на работу, т. к. стипендия маленькая. Нужно как ты жить? Спасибо!

    1. jaroslavez:

      Освой html+css+js и устройся в какую-нибудь конторку верстальщиком на небольшую зарплату (если Москва, то минимум 20 тысяч, на еду и одежду с рынка хватит, но если ты квартиру снимаешь, то надо исходить из стоимости аренды). Если ты беспокоишься о "порче" мозгов из-за изучения js, после которого будет, якобы, сложнее изучить C++ (лично меня этим пугали), то нет, ничего подобного.

    2. Nub:

      Чувак, если тебе нужно на что-то жить, то устройся лучше в МакДональдс. Я абсолютно серьезно.

      Чтобы зарабатывать деньги программированием нужно быть профи, с опытом, для С++ с БОЛЬШИМ опытом. Опыта набираются на бесплатных работах: контрибутя в опенсорс (это если согласяттся еще принять) или придумывают себе свой проект.

      Верстальщики (а они ообще нужны кому-нибудь в 2019?) не исключение, просто путь покороче. Но это путь в никуда.

      Так что лучше подрабатывай в Маке, а по ночам пили свой проект. Советую начать с Python — он очень универсален.

      Сейчас большой хайп вокруг machine learning, вот там реально найти работу юнцу, т.к. тема новая и седовласых просто нет. Про сайтики лучше забыть — эта поляна давно вытоптана

      1. никто:

        груСНые реалии суровой жизни

  8. шЫзик:

    а есть ли разница в написании инициализации? ну может быть время выполнение или объем кода?

    или

  9. Алексей:

    Программа выведет 3. a–3 равно 3, что и присваивается переменной a. Нужно бы пересмотреть ответы. а = 6. 6 — 3 = 3. Не подготовленный пользователь, не всегда может понять.

    1. Константин:

      …нет электричества — нет никаких битов-байтов-переменных-постоянных… Подали питание — появляЮтся напряжениЯ на кристаллах оперативной памяти, скажем, 1 мВ соответствуют так называемому двоичному "0", а 3 мВ — двоичной "1". Таким образом, каждый кристаллик может хранить потенциал либо 1 мВ, либо 3 мВ. (Если там появится какое-то другое напряжение — кристалл вышел из строя). Как я полагаю, минимальный кластер "склеен" из четырёх таких кристалликов. Для поиска его внутри микросхемы каждый кластер имеет свои координаты — например: ячейка 170. А высокоуровневый язык позволяет использовать её (менять потенциалы на кристаллах) как место постоянной дислокации некоего значения — парадоксально, но это и называется "переменной"; а для удобства обращения к ней, предоставлена возможность называть её неким вымышленным именем собственным. Фиксированное же значение не имеет такого постоянного адреса.

  10. Алексей:

    Не слишком много раз повторяется слово — "Переменная"? 🙂 — "здесь мы присваиваем значение 7 переменной a. Но что такое «a»? a — это переменная. Переменная в C++ — это просто объект с именем."

  11. Алексей:

    В начале путаница возникает. "Объект — это часть памяти…" И потом — "При определении объекта часть этой памяти выделяется для него." Как бы получается если подставить выше написанное, то выйдет следующее — При определении части памяти, часть этой памяти выделяется для него. Как — то уточнить бы всё таки понятие объекта.

  12. максим:

    я правильно делаю? вроде работает

  13. Павел:

    Можно вместо термина "стейтмент" использовать "оператор" или "инструкция"? Мне кажется, что будет понятнее.

    1. Фото аватара Юрий:

      Оператор — это оператор, стейтмент — это не один лишь оператор, это определенная совокупность кода. Термин "инструкция" может быть, но не всегда это корректно.

  14. Валерий:

    Какова область действия объявленных переменных?
    Только в теле функции где они объявлены?
    Как объявить переменную, что бы она действовала во всех используемых функциях? (Во всей программе…)

    1. NiK:

      Для того чтобы переменная была видна в любом месте программы (если программа состоит из одного файла .cpp) необходимо сделать ее глобальной. Для этого нужно объявить требуемую переменную выше фенкции main(), например, так:

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

      1. Романов Артём:

        Чтобы глобальная переменная была видна за пределами функции, можно перед типом переменной написать static (для видимости во всём файле) или extern (для видимости во всех файлах программы):

        1. Некто хороший:

          Чтобы глобальная переменная была видна за пределами функции, можно перед типом переменной написать static (для видимости во всём файле) или extern (для видимости во всех файлах программы)

          -> Абсолютно неверно. Ни одно из этих ключевых слов не делает переменную глобальной. Слово static делает переменную статичной, то есть ее значение не сбрасывается после выхода из функции. Если же использовать слово в объявлении глобальной переменной, то это ограничит область видимости одним файлом. Слово extern сообщает компилятору, что переменная объявлена в другом файле и компилятор не выделяет для нее место. Окончательную работу сделает компоновку. Если же в файле написать extern, но ни в одном файле ее не определить, то произойдет ошибка при компоновке. Проверять надо свои утверждения прежде чем что-то другим объяснять.

  15. Zufar:

    Грозит ли чем-нибудь мусор в неинициализированной переменной программе? Например если я сначала объявлю переменную и через строчек 40 кода, я ей присвою значение.

    1. Фото аватара Юрий:

      Нет, всё будет нормально, если программа не будет обращаться к неинициализированной переменной до того момента, когда вы ей присвоите значение. Т.е. объявить переменную можно и инициализировать её позже также можно, даже компилировать программу можно — вы получите предупреждение, а не ошибку, что переменная неинициализированная. Но если вы будете использовать переменную в каком-то выражении до её инициализации (например, в z = x + y, где x — не инициализирован), то это уже чревато неожиданными результатами программы (вплоть до переполнения переменной или простого сбоя).

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *