Инициализация переменных
Во время объявления переменных можно сообщить им значение путем помещения знака равенства и константы после имени переменной. Этот процесс называется инициализацией и в общем случае имеет вид:
тип имя_переменной — константа;
Ниже приведено несколько примеров
float balance = 123.23;
Глобальные и статические глобальные переменные инициализируются только при запуске программы. Локальные переменные инициализируются каждый раз при входе в блок, где они были объявлены. Статические локальные переменные инициализируются только один раз, а не каждый раз при входе в блок. Глобальные и статические локальные переменные инициализируются нулем, если не указано инициализационное значение. Неинициализирующиеся нестатические локальные и регистровые переменные будут иметь неопределенное значение.
Что такое определение, объявление и инициализация переменной
Объясните пожалуйста доступно, что такое определение, объявление и инициализация переменной. Как их отличать синтаксически. Что без чего можно делать, а что без чего нельзя. Прочитал уже несколько статей, теперь в голове только каша
Отслеживать
122k 24 24 золотых знака 124 124 серебряных знака 297 297 бронзовых знаков
задан 13 июн 2020 в 12:45
201 1 1 золотой знак 3 3 серебряных знака 12 12 бронзовых знаков
Чтобы каши в голове не было, лучше читать учебники.
13 июн 2020 в 12:47
@SergeyGornostaev посоветуй, пожалйста книгу, где можно об этом почитать
13 июн 2020 в 12:59
Приведённые раньше ответы неверные. Уже неоднократно поднималась эта тема на стеках. Вот пример правильного ответа stackoverflow.com/a/1410632. Также можно почитать тут en.cppreference.com/w/cpp/language/declarations, en.cppreference.com/w/cpp/language/definition. Ну и в Стандарте, разумеется eel.is/c++draft.
13 июн 2020 в 13:06
@Slad, если вам нужны формально точные определения, тогда берите стандарт языка.
13 июн 2020 в 13:22
7 июл 2020 в 13:16
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Нижеизложенное сильно упрощено. Здесь не преследуется цель рассказать подробно все нюансы — для этого лучше почитать Стандарт языка.
Объявление (declaration) переменной информирует компилятор о том, что где-то, возможно, в другой единице трансляции (очень грубо, в другом cpp-файле) выделено sizeof байт под хранение переменной такого-то типа с таким-то именем. Деклараций можно писать сколько угодно в разных блоках кода, по одной на блок.
Определение (definition) переменной информирует тот же компилятор о том, что память под переменную нужно взять прямо в этом месте, где написано данное определение. Именно в этой единице трансляции. Определение на всю программу может быть одно и только одно.
Этими процессами управляют квалификаторы static , extern , thread_local и некоторые другие.
Чаще всего, происходят одновременно объявление и определение, например
int a; // вне функций - заставит компилятор создать глобальную переменную. < int a; //в блоке кода - переменная будет существовать до конца блока, а память будет выделена на стеке >
Примером чисто объявления идентификатора будет объявление его со спецификатором static внутри структуры:
struct A < static int a; // объявление A::a >;
Никакая память на данный момент не выделена, но компилятор теперь знает, что у него такое есть. Для использования этого поля необходимо прежде определить его вне структуры:
int A::a; // определение A::a int b = A::a; // теперь можно
Использование ключевого слова extern , которое как раз говорит компилятору, что переменная объявлена где-то в другой единице трансляции
//alpha.cpp int a; //beta.cpp extern int a; // указали, что будем пользоваться `int a` из `alpha.cpp`
Само связывание имен и памяти произойдет на этапе компоновки программы.
Инициализация в смысле C++ — это когда определение и объявление объединяют с присваиванием начального значения;
Будет инициализацией в смысле практики программирования (самая первая запись в переменную), но не будет инициализацией в смысле C++ — это идущие подряд определение и присваивание.
Чтение из неинициализированной переменной — форменное UB. Так писать нельзя, это неправильно.
Инициализация, присваивание и объявление переменной в Си, ошибки
![]()
Правильная инициализация переменной в С имеет важное значение. Потому что если ее сделать некорректно, тогда программа на С будет работать с ошибками или вообще не будет работать. Поэтому сегодня в статье поговорим о переменных в С.
Напомним, переменная — это имя «куска памяти», который будет временно сохранять какую-то информацию. Работа переменных тесно связана с оперативной памятью устройства. Когда мы объявляем переменную в коде, то, фактически, мы говорим компилятору в устройстве: «выдели немного оперативной памяти вот для такого-то значения». Если в момент объявления переменной сделать какую-то ошибку, тогда может возникнуть проблема с оперативной памятью. Допустим, выделится недостаточное количество памяти или, наоборот, переменная у потребит слишком много памяти и др.
Инициализация переменной в С
Почему важна правильная инициализация переменной в С? Любая информация, которая попадает внутрь компьютер а, преобразуется в последовательность битов. Бит — это минимальное значение в памяти, которое может быть двух значений: «0» или «1». Если рассмотреть какой-то «кусок памяти» в компьютере, тогда можно увидет ь, что он похож на нечто такое: «010110110011001110100110».
Когда мы объявляем переменную, мы просим выделить ей какое-то количество памяти. Однако мы не указываем необходимое количество памяти в битах, а указываем тип переменной. Компилятор самостоятельно определяет сколько и каким образом нужно выделить памят и для вашей переменной, основываясь на ее типе.
Инициализация переменной в С — это объявление ее типа и одновременное присвоение ей значения. Таким образом, для разработчика важно определить к какому типу данных относится его переменная, а обо всем остальном заботятся компилятор и процессор.
Основные типы переменных в С
- размер выделенной памяти зависит от типа переменной;
- представление переменной в памят и также зависит от типа переменной.
- «char» с размером 1 байт;
- «short» с размером 2 байта;
- «int» с размером 4 байта;
- «long» с размером 4 байта;
- «long long» с размером 8 байт.
- «float» с размером в 4 байта;
- «long float» с размером в 8 байт;
- «double» с размером в 8 байт;
- «long double» с размером в 8 байт.
Как происходит объявление, присвоение и инициализация переменной в С
- тип переменной;
- имя переменной.
- «Копирующая инициализация». Происходит при помощи знака «равно» и выглядит вот так: «int myVar = 7».
- «Прямая инициализация». Происходит при помощи «круглых скобок» и выглядит вот так: «int myVar(7);».
Заключение
Сегодня мы познакомились с особенностями переменных в языке программирования С. В частности, вы могли увидеть как проходит объявление, присвоение и инициализация переменной в С.
При работе с переменными в С, нужно обязательно запомнить, что определение их типа имеет ключевое значение.
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
Присваивание и инициализация в Java

Основное предназначение компьютерных программ — обработка данных. Чтобы обработать данные нужно их как-то хранить. Предлагаю разобраться с тем, как происходит хранение данных.

Переменные
- Поля (fields) : переменные, объявленные в классе;
- Локальные переменные (local variables) : переменные в методе или в блоке кода;
- Параметры (parameters) : переменные в объявлении метода (в сигнатуре).
- Тип переменной показывает, какие данные представляет данная переменная (т.е. какие данные может хранить). Как мы знаем, тип переменной может быть примитивным (primitives primitives) или объектным, не примитивными (Non-primitive). При объектных переменных их тип описывается определённым классом.
- Название переменной должно быть с маленькой буквы, в camel case. Подробнее про именование можно прочитать в «Variables:Naming».
Объявление переменной (Declaration)
Итак, мы вспомнили, что такое переменная. Для того, чтобы с переменной начать работать нужно её объявить. Для начала, разберёмся с локальной переменной. Вместо IDE для удобства воспользуемся онлайн решением от tutorialspoint: Online IDE. Выполним в их online IDE вот такую простенькую программку:
public class HelloWorld < public static void main(String []args)< int number; System.out.println(number); >>
Итак, как видно, мы объявили локальную переменную с именем number и типом int . Нажимаем кнопку «Execute» и получаем ошибку:
HelloWorld.java:5: error: variable number might not have been initialized System.out.println(number);
- Обращение к локальным переменным должно быть выполнено только после того, как они будут инициализированы;
- Локальные переменные не имеют значений по умолчанию;
- Проверка значений локальных переменных выполняется в момент компиляции.
Инициализация локальной переменной
Инициализация переменных одна из самых мудрёных тем в Java, т.к. очень тесно связана с работой с памятью, с реализацией JVM, спецификацией JVM и другими не менее страшными и хитрыми вещами. Но можно попробовать разобраться хоть в какой-то мере. Пойдём от простого к сложному. Чтобы инициализировать переменную воспользуемся оператором присваивания и изменим строчку в нашем прошлом коде:
int number = 2;
В таком варианте ошибок не будет и на экран выведется значение. Что же происходит в этом случае? Давайте попробуем порассуждать. Если мы хотим присвоить переменной какое-то значение, значит мы хотим, чтобы эта переменная хранила значение. Получается, что значение где-то должно храниться, но где? На диске? Но это очень медленно и может на нас накладывать ограничения. Получается, единственное, где мы можем быстро и эффективно хранить данные «здесь и сейчас» это память. Значит, нам нужно выделить в памяти какое-то место. Так и есть. При инициализации переменной под неё будет выделено место в памяти, отведённой java процессу, в рамках которого будет выполняться наша программа. Память, выделяемая java процессу, разделена на несколько областей или зон. В какой из них будет выделено место зависит от того, какого типа была объявлена переменная. Память разделяется на следующие разделы: Heap, Stack и Non-Heap. Начнём со стэковой памяти. Stack переводится как стопка (например, стопка книг). Представляет собой LIFO структуру данных (Last In, First Out). То есть как стопка книг. Когда мы добавляем в неё книги – мы кладём их сверху, а когда забираем – берём верхнюю (т.е. ту, которая добавлена самой последней). Итак, мы запускаем нашу программу. Как мы знаем, Java программу выполняет JVM, то есть виртуальная Java машина. JVM должна знать то, откуда должно начаться выполнение программы. Для этого мы объявляем main метод, который называется «точкой входа». Для выполнения в JVM создаётся основной поток (Thread). При создании потока ему выделяется свой стэк в памяти. Этот стэк состоит из фрэймов. При выполнении каждого нового метода в потоке под него будет выделен новый фрэйм и добавлен на вершину стэка (как новая книжка в стопке книг). Этот фрэйм будет содержит ссылки на объекты и примитивные типы. Да да, наш int будет храниться в стэке, т.к. int это примитивный тип. Прежде чем выделить фрэйм JVM должна понимать, что туда сохранять. Именно по этой причине мы получим ошибку «variable might not have been initialized», ведь если она не инициализирована, то JVM не сможет нам подготовить стэк. Поэтому при компиляции программы умный компилятор поможет нам не допустить ошибку и не сломать всё. (!) Для наглядности советую супер-пупер статью: «Java Stack and Heap: Java Memory Allocation Tutorial». В ней ссылаются на не менее крутое видео:
После завершения выполнения метода из стэка потока будут удаляться фрэймы, выделенные под эти методы, а вместе с ними и очищаться память, выделенная под этот фрэйм со всеми данными.
Инициализация локальных объектных переменных
Давайте опять изменим наш код на чуть более хитрый:
public class HelloWorld < private int number = 2; public static void main(String []args)< HelloWorld object = new HelloWorld(); System.out.println(object.number); >>
Что же тут будет происходить? Давайте ещё раз рассуждать. JVM узнает о том, откуда ей выполнять программу, т.е. она видит main метод. Она создаёт поток, под него выделяет память (потоку ведь надо где-то хранить данные, которые нужны для выполнения). В этом потоке выделяется фрэйм под метод main. Далее мы создаём объект HelloWorld. Этот объект уже создаётся не в стэке, а в хипе. Потому что object у нас не примитивный тип, а объектный. А в стэке будет храниться только ссылка на объект в хипе (мы ведь как-то должны обращаться к этому объекту). Далее в стэке метода main будут выделены фрэймы для выполнения метода println. После выполнения метода main будут уничтожены все фрэймы. При уничтожении фрэйма будут уничтожены все данные. Объект object не будет уничтожен сразу. Сначала на него будет уничтожена ссылка и таким образом на объект object больше никто ссылаться не будет и доступа больше к этому объекту в памяти будет не получить. Умная JVM имеет свой механизм для такого – сборщик мусора (garbage collector или сокращённо GC). Он то и удаляет из памяти такие объекты, на которые больше никто не ссылается. Данный процесс опять же был описан в ссылке, что была приведена выше. Там даже видео есть с объяснением.
Инициализация полей
Инициализация полей, указанных в классе происходит особым образом в зависимости от того, является ли поле статическим или нет. Если у поля стоит ключевое слово static, то данное поле относится к самому классу, а не слово static не указано, то данное поле относится к экземпляру класса. Давайте рассмотрим это на примере:
public class HelloWorld < private int number; private static int count; public static void main(String []args)< HelloWorld object = new HelloWorld(); System.out.println(object.number); >>
В данном примере, инициализация полей происходит в разное время. Поле number будет инициализировано после того, как будет создан объект object класса HelloWorld. А вот поле count будет инициализировано тогда, когда класс будет загружен виртуальной Java машиной. Загрузка классов – это отдельная тема, поэтому не будем сюда примешивать её. Просто стоит знать, что статические переменные инициализируются тогда, когда о классе становится известно при выполнении. Тут важнее другое и Вы уже это заметили. Мы нигде не указали значения, а оно работает. И действительно. Переменные, которые являются полями, если для них не указано значение, то они инициализируются значением по умолчанию. Для числовых значением это 0 или 0.0 для чисел с плавающей точкой. Для boolean это false. А для всех переменных объектных типов значение будет null (об этом мы ещё поговорим). Казалось бы, а почему так? А потому, что объекты создаются в Heap (в куче). Работа с данной областью выполняется в Runtime. И мы в runtime можем инициализировать эти переменные, в отличии от стэка, память под который должна быть подготовлена ещё до выполнения. Так устроена работа с памятью в Java. Но есть тут и ещё одна особенность. В этом маленьком кусочке затрагиваются разные уголки памяти. Как мы помним, в Stack памяти под метод main выделяется фрэйм. В этом фрэйме хранится ссылка (reference) на объект в Heap памяти. Но где тогда хранится count? Как мы помним, эта переменная инициализируется сразу, до создания объекта в хипе. Вот тут действительно хитрый вопрос. До Java 8 существовала область памяти, называемая PERMGEN. Начиная с Java 8 эта область претерпела изменения и называется METASPACE. По сути, статические переменные являются частью описания класса, т.е. его метаданными. Поэтому, логично, что хранится в хранилище метаданных, METASPACE. MetaSpace относится к той самой Non-Heap области памяти, является её частью. Важно ещё учитывать то, что учитывается порядок, в котором объявлены переменные. Например, в этом коде ошибка:
public class HelloWorld < private static int b = a; private static int a = 1; public static void main(String []args)< System.out.println(b); >>
Что такое null
Как было сказано выше, переменные объектных типов, если они являются полями класса, инициализируются значениями по умолчанию и таким значением по умолчанию является null. Но что же такое null в Java? Первое что важно помнить – примитивные типы не могут быть null. А всё потому, что null – это особенная ссылка (reference), которая не ссылается никуда, ни на какой объект. Поэтому, только объектная переменная может быть равна null. Второе, что важно понимать, что null – это ссылка, reference. Я reference тоже имеют свой вес. На эту тему можно почитать вопрос на stackoverflow: «Does null variable require space in memory».
Блоки инициализации
Рассматривая инициализацию переменных грех не рассмотреть блоки инициализации. Выглядит это следующим образом:
public class HelloWorld < static < System.out.println("static block"); > < System.out.println("block"); >public HelloWorld () < System.out.println("Constructor"); >public static void main(String []args) < HelloWorld obj = new HelloWorld(); >>
Порядок вывода будет: static block, block, Constructor. Как мы видим, блоки инициализации выполняются раньше, чем конструктор. И иногда это может быть удобным средством для инициализации.