что значит после переменной в с
Указатели в C++: адрес и удаление
Всем привет! В этом уроке мы разберём то, что очень тесно связано с памятью в компьютере. С помощью этого можно улучшать работу своей программы. Как вы догадались с названия урока, это — указатели.
Адрес переменной в C++
Давайте приведем аналогию с круизным лайнером. В нем, как и в отеле, имеются номера. Вот, например, при покупке номера вам могут дать номер — 0x155 (да, мы понимаем, что не в одном лайнере или отеле не станут записывать номера в шестнадцатеричном виде, но давайте все таки немного отвлечемся). А друг может оказаться в номере 0x212 — так и с переменными, они могут получить разный путь. И только сам компьютер при создании переменной знает, где она находится.
Переменные, которые вы создаете в программе, по её завершению автоматически удаляются, чтобы не нагружать операционную память вашего компьютера.
Пример удаления переменных
В играх присутствует хорошая графика, различные спецэффекты. Например, тот же дым. Все это — переменная (может не одна!), которой в будущем придётся уничтожиться навсегда. А вот, если бы она не удалилась, то она бы своей фоновой работой понемножку нагружала бы наш компьютер.
Поэтому в C/C++ присутствует возможность обратиться к переменной, и, если требует ситуация, удалить и создать её вовсе в другом участке программы, когда это, конечно, нам будет нужно.
Что такое указатели в C++
Указатели — это с самого начала переменные, уже в которых хранится адрес других переменных.
Чтобы пользоваться указателями, вам нужно использовать два оператора:
Как создать указатели в C++
Давайте посмотрим, какую конструкцию нужно использовать, чтобы создать указатели:
Урок №10. Переменные, Инициализация и Присваивание
Обновл. 11 Сен 2021 |
Программируя на языке C++, мы создаем, обрабатываем и уничтожаем объекты. Объект — это часть памяти, которая может хранить значение. В качестве аналогии мы можем использовать почтовый ящик, куда мы помещаем информацию и откуда её извлекаем. Все компьютеры имеют оперативную память, которую используют программы. При создании объекта, часть оперативной памяти выделяется для этого объекта. Большинство объектов, с которыми мы будем работать в языке C++, являются переменными.
Переменные
Для создания переменной используется стейтмент объявления (разницу между объявлением и определением переменной мы рассмотрим несколько позже). Вот пример объявления целочисленной переменной a (которая может содержать только целые числа):
При выполнении этой инструкции центральным процессором часть оперативной памяти выделяется под этот объект. Например, предположим, что переменной a присваивается ячейка памяти под номером 150. Когда программа видит переменную a в выражении или в стейтменте, то она понимает, что для того, чтобы получить значение этой переменной, нужно заглянуть в ячейку памяти под номером 150.
Одной из наиболее распространенных операций с переменными является операция присваивания, например:
Когда процессор выполняет эту инструкцию, он понимает её как «поместить значение 8 в ячейку памяти под номером 150».
Затем мы сможем вывести это значение на экран с помощью std::cout:
l-values и r-values
Вот несколько примеров операций присваивания с использованием r-values:
Давайте детально рассмотрим последнюю операцию присваивания:
Здесь переменная b используется в двух различных контекстах. Слева b используется как l-value (переменная с адресом в памяти), а справа b используется как r-value и имеет отдельное значение (в данном случае, 12 ). При выполнении этого стейтмента, компилятор видит следующее:
Сильно беспокоиться о l-values или r-values сейчас не нужно, так как мы еще вернемся к этой теме на следующих уроках. Всё, что вам нужно сейчас запомнить — это то, что в левой стороне операции присваивания всегда должно находиться l-value (которое имеет свой собственный адрес в памяти), а в правой стороне операции присваивания — r-value (которое имеет какое-то значение).
Инициализация vs. Присваивание
В языке C++ есть две похожие концепции, которые новички часто путают: присваивание и инициализация.
После объявления переменной, ей можно присвоить значение с помощью оператора присваивания (знак равенства = ):
В языке C++ вы можете объявить переменную и присвоить ей значение одновременно. Это называется инициализацией (или «определением»).
Переменная может быть инициализирована только после операции объявления.
Хотя эти два понятия близки по своей сути и часто могут использоваться для достижения одних и тех же целей, все же в некоторых случаях следует использовать инициализацию, вместо присваивания, а в некоторых — присваивание вместо инициализации.
Правило: Если у вас изначально имеется значение для переменной, то используйте инициализацию, вместо присваивания.
Неинициализированные переменные
В отличие от других языков программирования, языки Cи и C++ не инициализируют переменные определенными значениями (например, нулем) по умолчанию. Поэтому, при создании переменной, ей присваивается ячейка в памяти, в которой уже может находиться какой-нибудь мусор! Переменная без значения (со стороны программиста или пользователя) называется неинициализированной переменной.
Использование неинициализированных переменных может привести к ошибкам, например:
Использование неинициализированных переменных является одной из самых распространенных ошибок начинающих программистов, но, к счастью, большинство современных компиляторов выдадут ошибку во время компиляции, если обнаружат неинициализированную переменную.
Хорошей практикой считается всегда инициализировать свои переменные. Это будет гарантией того, что ваша переменная всегда имеет определенное значение и вы не получите ошибку от компилятора.
Правило: Убедитесь, что все ваши переменные в программе имеют значения (либо через инициализацию, либо через операцию присваивания).
Какой результат выполнения следующих стейтментов?
Ответы
Чтобы просмотреть ответ, кликните на него мышкой.
Ответ №1
Ответ №2
Программа выведет 3 : переменной b присваивается значение переменной a ( 3 ).
Ответ №3
Ответ №4
Ответ №5
Результатом будет ошибка, так как c — это неинициализированная переменная.
Поделиться в социальных сетях:
Урок №9. Комментарии
Комментариев: 33
«Объект — это часть памяти, которая может хранить значение. В качестве аналогии мы можем использовать почтовый ящик, куда мы помещаем информацию и откуда её извлекаем. Все компьютеры имеют оперативную память, которую используют программы. При создании объекта, часть оперативной памяти выделяется для этого объекта. Большинство объектов, с которыми мы будем работать в языке C++, являются переменными.»
Хмм. насколько верно, что переменная — это объект? Это минимальная единица манипулирования объектом (переменная — ссылка на ячейку памяти.). Если рассматривать вашу аналогию, то объект-почтовый ящик, а переменная — письмо(Хотя и письмо — тоже объект. А вот буква в письме — переменная).
Это не необходимость, просто демонстрация некой возможности, переменным можно всегда присваивать новые значения, а можно и не присваивать. Так например, если для разных задач нужна 1 переменная, можно просто менять ее значение для каждой операции, а не создавать новую.
Читай комментарий(5 вычисляется в 5, которое затем присваивается переменной а). Это для наглядности сделано, типа что бы ты понял как присвоить значение. Но на практике такое особо не делается без вывода. Если не понятно то что я сказал то напиши cout **No Name** :
Это же очевидно! Например:
Вам нужно запомнить координаты движущегося квадрата.
Таким образом Ваш код будет такой:
И соответственно отрисовка квадрата. А в y и x у вас координаты.
Переменная от слова менять.
Левое значение, оперативка. Сразу видно чёткого программера, не заморачивающегося стилистикой речи. Но это я так, не по теме =) По крайней мере, с начала изучения твоего ресурса я не испытываю ощутимого дискомфорта в понимании материала. Надеюсь, эта тенденция сохранится впредь.
Все отлично, было 13 лет назад баловался на С. Универ требовал и надо было.
Сейчас вспоминаю, изучаю.
Пишу эти простые проги на Ubuntu, неинициализированная переменная при выводе выдаст 0.
Далеко не всегда 0. Тут как повезёт. Локальные переменные не инициализируются точно. Если у вас всегда 0, возможно, проверяете на какой-нибудь простецкой программе, которую компилятор вполне мог заоптимизировать и поменять переменную на константу, видя, что с ней ничего кроме вывода на экран не происходит.
Храни тебя господь, Юрий!)
Благодарю вас урок очень понравился, так доступно объясняете.
Спасибо, что читаете 🙂
При выполнении этого стейтмента, компилятор видит следующее:
Откуда компилятор видит, что b == 10?
То, что b равно 10 будет известно только в рантайме, нет?
Скажите пожалуйста. Задумался об изучении программирования, учусь в техюунивере по профессии программная-инженерия. В приоритете такие языки как С++ и JavaScript. скажите пожалуйста, что лучше изучить сначала. Если С++ то за какое время смогу освоить ее нормально. JS рассматриваю в качестве быстро устроиться на работу, т. к. стипендия маленькая. Нужно как ты жить? Спасибо!
Освой html+css+js и устройся в какую-нибудь конторку верстальщиком на небольшую зарплату (если Москва, то минимум 20 тысяч, на еду и одежду с рынка хватит, но если ты квартиру снимаешь, то надо исходить из стоимости аренды). Если ты беспокоишься о «порче» мозгов из-за изучения js, после которого будет, якобы, сложнее изучить C++ (лично меня этим пугали), то нет, ничего подобного.
Чувак, если тебе нужно на что-то жить, то устройся лучше в МакДональдс. Я абсолютно серьезно.
Чтобы зарабатывать деньги программированием нужно быть профи, с опытом, для С++ с БОЛЬШИМ опытом. Опыта набираются на бесплатных работах: контрибутя в опенсорс (это если согласяттся еще принять) или придумывают себе свой проект.
Верстальщики (а они ообще нужны кому-нибудь в 2019?) не исключение, просто путь покороче. Но это путь в никуда.
Так что лучше подрабатывай в Маке, а по ночам пили свой проект. Советую начать с Python — он очень универсален.
Сейчас большой хайп вокруг machine learning, вот там реально найти работу юнцу, т.к. тема новая и седовласых просто нет. Про сайтики лучше забыть — эта поляна давно вытоптана
груСНые реалии суровой жизни
а есть ли разница в написании инициализации? ну может быть время выполнение или объем кода?
А можно написать вначале «using namespace std», чтобы при записи кода не писать «std»?
Программа выведет 3. a–3 равно 3, что и присваивается переменной a. Нужно бы пересмотреть ответы. а = 6. 6 — 3 = 3. Не подготовленный пользователь, не всегда может понять.
…нет электричества — нет никаких битов-байтов-переменных-постоянных… Подали питание — появляЮтся напряжениЯ на кристаллах оперативной памяти, скажем, 1 мВ соответствуют так называемому двоичному «0», а 3 мВ — двоичной «1». Таким образом, каждый кристаллик может хранить потенциал либо 1 мВ, либо 3 мВ. (Если там появится какое-то другое напряжение — кристалл вышел из строя). Как я полагаю, минимальный кластер «склеен» из четырёх таких кристалликов. Для поиска его внутри микросхемы каждый кластер имеет свои координаты — например: ячейка 170. А высокоуровневый язык позволяет использовать её (менять потенциалы на кристаллах) как место постоянной дислокации некоего значения — парадоксально, но это и называется «переменной»; а для удобства обращения к ней, предоставлена возможность называть её неким вымышленным именем собственным. Фиксированное же значение не имеет такого постоянного адреса.
Не слишком много раз повторяется слово — «Переменная»? 🙂 — «здесь мы присваиваем значение 7 переменной a. Но что такое «a»? a — это переменная. Переменная в C++ — это просто объект с именем.»
В начале путаница возникает. «Объект — это часть памяти…» И потом — «При определении объекта часть этой памяти выделяется для него.» Как бы получается если подставить выше написанное, то выйдет следующее — При определении части памяти, часть этой памяти выделяется для него. Как — то уточнить бы всё таки понятие объекта.
Автор, не вводи людей в заблуждения, используя ради выпендрежа английские слова. В русском языке есть понятный перевод и свои устоявшиеся понятия по теме программирования.
«Стэйтмент» — по-русски говорят «выражение»
«л и р — вэлью» — левостороннее и правостороннее присваивание, выражение, значение или ещё что.
Зачем ты плодишь свои слова уродцы?) Ты до этого программирование хоть изучал?
Читай книги, это фундамент.
Хорошо, давай по порядку.
Вопрос №1: «Зачем я используя английские слова?».
Ответ №1: «Потому что никаких 100% устоявшихся переводов всех понятий/терминов/слов ни в каком учебнике или книге, которую ты, возможно, читал — нет. Есть много терминов, перевод которых идентичен в большинстве ресурсов, но есть термины, перевод которых отличается из одного ресурса в другой. ПОЭТОМУ, ЧТОБЫ НЕ ВВОДИТЬ В ЗАБЛУЖДЕНИЕ читателей, я даю англицизм (английский «statement» = русский «стейтмент»), вместо корявого и непонятного перевода (и никак не ради выпендрёжа).
И когда человек ищет дополнительную информацию в Гугле, то лучше он наберёт англицизм и получит релевантный ответ со списком из 10-30 РЕЛЕВАНТНЫХ сайтов, нежели введёт «левостороннее присваивание» и получит НЕРЕЛЕВАНТНЫЙ ответ из всего 5 ссылок, где упоминается этот чудо-термин».
Вопрос №2: «Почему я не использую «выражение» в качестве перевода «statement»?»
Ответ №2: «Полностью развернутый ответ — это урок №8, который ты, видимо, не удосужился хотя бы просмотреть. В нём сообщается, что стейтмент — это «полное предложение», которое сообщает компилятору выполнить определенное задание. Выражение — это математический объект, который производит результат-значение. Выражения, как правило, используются внутри стейтментов. Детальнее — см. урок №8».
Вопрос №3: «Почему у меня перевод l-value и r-value, а не «левостороннее и правостороннее присваивание, выражение, значение или ещё что»?
Ответ №3: «См. ответ №1. Да можно было бы использовать левостороннее/правостороннее значение (но никак не «левостороннее/правостороннее присваивание»), но этот вариант, по моему мнению, хуже того, что есть (см. второй абзац Ответа №1)».
Вопрос №4: «Читал ли я книги по программированию и изучал ли программирование до этого?».
Ответ №4: «Не дочитал ни одну книгу по программированию. Да, изучал ещё в колледже и изучаю (если так можно выразиться вообще) в университете».
Слова уродцы — это конечно что-то новенькое 🙂
> «л и р — вэлью» — левостороннее и правостороннее присваивание
> «вэлью»
> присваивание
Иди лучше дальше, не останавливайся
Что значит звёздочка после типа указателя?
Зачем перед malloc стоит (double*), если это пишется в sizeof(double), Для чего после double стоит *, ведь это символ разыменования, а что мы разыменуем?
Простой 1 комментарий
что значить Звёздочка после типа?
Для чего после double стоит *, ведь это символ разыменования, а что мы разыменуем?
В данном случае звездочка не является оператором а относится к типу.
Зачем перед malloc стоит (double*)
Выделяет память в байтах (возвращает указатель на void), и ничего не знает о том как вы ими будете распоряжаться.
приведение к типу (double*) сообщает компилятору, что вы хотите.
Надо сказать, что данный код можно использовать только в том случае, если сразу за malloc() идет чтение или инициализация массива. Потому что malloc() вернул область памяти, заполненную случайными данными. Для гарантии, что там не будет мусора лучше использовать calloc:
ptd = (double *) calloc(sizeof(double), 10);
Урок №28. Инициализация, присваивание и объявление переменных
Обновл. 11 Сен 2021 |
Этот урок является более детальным продолжением урока №10.
Адреса и переменные
Как вы уже знаете, переменные — это имена кусочков памяти, которые могут хранить информацию. Помним, что компьютеры имеют оперативную память, которая доступна программам для использования. Когда мы определяем переменную, часть этой памяти отводится ей.
Поскольку все данные компьютера — это лишь последовательность битов, то мы используем тип данных (или просто «тип»), чтобы сообщить компилятору, как интерпретировать содержимое памяти. Вы уже видели пример типа данных: int (целочисленный тип данных). Когда мы объявляем целочисленную переменную, то мы сообщаем компилятору, что «кусочек памяти, который находится по такому-то адресу, следует интерпретировать как целое число».
Когда вы указываете тип данных для переменной, то компилятор и процессор заботятся о деталях преобразования вашего значения в соответствующую последовательность бит определенного типа данных. Когда вы просите ваше значение обратно, то оно «восстанавливается» из этой же последовательности бит.
Кроме int, есть много других типов данных в языке C++, большинство из которых мы детально рассмотрим на соответствующих уроках.
Фундаментальные типы данных в С++
В языке C++ есть встроенная поддержка определенных типов данных. Их называют основными типами данных (или «фундаментальные/базовые/встроенные типы данных»).
Вот список основных типов данных в языке C++:
Категория | Тип | Значение | Пример |
Логический тип данных | bool | true или false | true |
Символьный тип данных | char, wchar_t, char16_t, char32_t | Один из ASCII-символов | ‘c’ |
Тип данных с плавающей запятой | float, double, long double | Десятичная дробь | 3.14159 |
Целочисленный тип данных | short, int, long, long long | Целое число | 64 |
Пустота | void | Пустота |
Объявление переменных
Вы уже знаете, как объявить целочисленную переменную:
Переменные, адреса и указатели
Переменная — это область памяти, к которой мы обращаемся за находящимися там данными, используя идентификатор (в данном случае, имя переменной). При этом у этой помеченной именем области есть еще и адрес, выраженный числом и понятный компьютерной системе. Этот адрес можно получить и записать в особую переменную. Переменную, содержащую адрес области памяти, называют указателем.
Когда мы меняем значение обычной переменной, то, можно сказать, просто удаляем из конкретной области памяти данные и записываем туда новые. Когда мы меняем значение переменной-указателя, то начинаем работать с совершенно иным участком памяти, т.к. меняем содержащийся в ней адрес.
Тема указателей тесно связана с темой динамических типов данных. Когда программа компилируется, то под объявленные переменные так или иначе (в зависимости от того, где они были объявлены) выделяются участки памяти. Потом размер этих участков не меняется, может меняться только их содержимое (значения или данные). Однако именно с помощью указателей можно захватывать и освобождать новые участки памяти уже в процессе выполнения программы. Динамические типы данных будут рассмотрены позже.
Прежде чем перейти к рассмотрению объявления и определения переменных-указателей, посмотрим, что из себя представляет адрес любой переменной и как его получить.
В результате выполнения данного программного кода на экране появляется примерно следующее (шестнадцатеричное число у вас будет другим):
Как мы видим, несмотря на то, что значения переменных поменялись, ячейки памяти остались прежними.
Зная адрес, можно получить значение, которое находится по этому адресу, поставив знак * перед адресом:
На экране будет выведено число 8.
Однако запись типа &a не всегда возможна или удобна. Поэтому существует специальный тип данных — указатели, которым и присваивается адрес на область памяти.
Указатели в языке C, как и другие переменные, являются типизированными, т.е. при объявлении указателя надо указывать его тип. Как мы узнаем позже, с указателями можно выполнять некоторые арифметические операции, и именно точное определение их типа позволяет протекать им корректно. Чтобы объявить указатель, надо перед его именем поставить знак *. Например:
Обратите внимание на то, что в данном случае * говорит о том, что объявляется переменная-указатель. Когда * используется перед указателем не при его объявлении, а в выражениях, то обозначает совсем иное — «получить значение (данные) по адресу, который присвоен указателю». Посмотрите на код ниже:
С помощью комментариев указаны текущие значения ячеек памяти. Подробно опишем, что происходит:
Под сам указатель (там, где хранится адрес) также должна быть выделена память. Объем этой памяти можно узнать с помощью функции sizeof() :
Под указатели всех типов выделяется одинаковый объем памяти, т.к. размер адреса не зависит от типа, а зависит от вычислительной системы. В таком случае, зачем при объявлении указателя следует указывать тип данных, на который он может ссылаться? Дело в том, что по типу данных определяется, сколько ячеек памяти занимает значение, на которое ссылается указатель, и через сколько ячеек начнется следующее значение.
Если указатель объявлен, но не определен, то он ссылается на произвольный участок памяти с неизвестно каким значением:
Результат (в Ubuntu):
Использование неопределенных указателей в программе при вычислениях чревато возникновением серьезных ошибок. Чтобы избежать этого, указателю можно присвоить значение, говорящее, что указатель никуда не ссылается (NULL). Использовать такой указатель в выражениях не получится, пока ему не будет присвоено конкретное значение:
Результат (в Ubuntu):
В данном случае, если попытаться извлечь значение из памяти с помощью указателя, который никуда не ссылается, то возникает «ошибка сегментирования».
На этом уроке вы должны понять, что такое адрес переменной и как его получить ( &var ), что такое переменная-указатель ( type *p_var; p_var = &var ) и как получить значение, хранимое в памяти, зная адрес ячейки ( *p_var ). Однако у вас может остаться неприятный осадок из-за непонимания, зачем все это надо? Это нормально. Понимание практической значимости указателей придет позже по мере знакомства с новым материалом.
Практически проверьте результат работы всех примеров данного урока, придумайте свои примеры работы с указателями.