Что значит неинициализированная переменная в c
Неинициализированные переменные — распространенный источник ошибок в программах на С и C++. Избегайте их, выработав привычку очищать память перед ее использованием; инициализируйте переменные при их определении.
Обсуждение
В традициях низкоуровневой эффективности C++ (как и С), от компилятора зачастую не требуется инициализация переменных, пока вы не сделаете это явно (например, локальные переменные, члены, опущенные в списке инициализации конструктора). Такие переменные надо инициализировать явно.
Имеется несколько причин, по которым переменная может остаться неинициализированной. Но ни одна из них не является достаточно серьезной для того, чтобы оправдать опасность неопределенного поведения.
Если вы используете процедурный язык (такой как Pascal, С, Fortran или Cobol), вы можете определить переменные отдельно от кода, их использующего, и присвоить им значения позже, когда эти переменные будут использоваться. Этот подход устарел и не рекомендуется для использования (см. рекомендацию 18).
Распространенное заблуждение по поводу неинициализированных переменных заключается в том, что они приводят к краху программы, так что несколько неинициализированных переменных быстро обнаруживаются простым тестированием. На самом деле программы с неинициализированными переменными могут безукоризненно работать годами, если биты в памяти соответствуют требованиям программы. Позже вызов с другим контекстом, перекомпиляция или какие-то изменения в другой части программы могут привести к последствиям разной степени тяжести — от необъяснимого поведения до периодического аварийного завершения программы.
Примеры
Пример 1. Использование инициализирующего значения по умолчанию или оператора ?: для снижения степени смешивания потока данных и потока управления.
// Не рекомендуется: не инициализирует переменную int speedupFactor; if( condition ) speedupFactor = 2; else speedupFactor = -1; // Лучше: инициализирует переменную int speedupFactor = -1; if( condition ) speedupFactor = 2; // Лучше: инициализирует переменную int speedupFactor = condition ? 2 : -1;
Варианты, отмеченные как лучшие, не имеют промежутка между определением и инициализацией.
Пример 2. Замена сложных вычислений вызовом функции. Иногда вычисление значения происходит таким образом, что лучше инкапсулировать его в функции (см. рекомендацию 11).
// Не рекомендуется: не инициализирует переменную int speedupFactor; if( condition ) < // . код . speedupFactor = someValue; >else < // . код . speedupFactor = someOtherValue; // лучше: инициализирует переменную int speedupFactor = ComputeSpeedupFactor();
Пример 3. Инициализация массивов. Для больших составных типов, таких как массивы, корректная инициализация не всегда означает реальное обращение к данным. Пусть, например, вы используете API, который заставляет вас использовать фиксированные массивы char размера МАХ_РАТН (см. рекомендации 77 и 78). Если вы уверены, что массивы всегда будут рассматриваться как строки в стиле С с завершающим нулевым символом, то такого немедленного присваивания будет достаточно:
// Допустимо: Создание пустой строки char path[MAX_PATH]; path[0] = '\0';
Более безопасная инициализация заполняет все элементы массива нулевыми значениями:
// Лучше: заполняем нулями весь массив char path[MAX_PATH] = < '\0' >;
Рекомендованы оба варианта, но в общем случае вы должны предпочитать безопасность излишней эффективности.
Исключения
Входные буферы и данные, описанные как volatile, которые записываются непосредственно аппаратным обеспечением или другими процессами, не требуют инициализации программой.
Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru
Использована неинициализированная локальная переменная?
В чем вопрос?
Да использована не инициализированная переменная r.
Вы когда объявляете переменную внутри функции (автоматическую) без инициализатора, то ее реальное значение не определено, т.е. оно может быть любым. Любой мусор, который валяется в памяти по месту расположения переменной станет значением переменной.
А потом вы делает r += a; Т.е. вы складываете a с мусором. Что вы хотите получить в итоге?
Просто проинициализируйте r нулем, так же как это сделано для b.
Ответ написан более трёх лет назад
Ответы на вопрос 0
Ваш ответ на вопрос
Вопрос закрыт для ответов и комментариев
Потому что уже есть похожий вопрос.

- Android
- +2 ещё
Почему FindLibrary выдает 0x0?
- 1 подписчик
- вчера
- 60 просмотров
Что хранит в себе неинициализированная переменная в C#?
Собственно вопрос и состоит в этом: Что хранить в себе неинициализированная переменная в C#? Насколько я знаю, в С++ такие переменные хранят всякий "мусор", в Java null, а для C# не нашел информации, кроме как "выдаст ошибку"
Отслеживать
11.7k 9 9 золотых знаков 28 28 серебряных знаков 40 40 бронзовых знаков
задан 26 июл 2020 в 17:17
authoraytee authoraytee
27 5 5 бронзовых знаков
Стоит, наверное, дать более точное определение "инициализации". В С++, например, все переменные инициализированы, но это инициализированное значение может быть неопределённым в некоторых ситуациях
26 июл 2020 в 17:33
@dIm0n, я имею ввиду, например, когда пишем просто int a или string stroka, что они в себе хранят? Вообще, в другом месте мне ответили, что "в C# нет переменных, есть структуры, они в себе не хранят ничего, а программа вызывает исключение", верно?
26 июл 2020 в 17:36
Подождите ответа от знающих C# (это не я :)). Я просто уточнил, что с точки зрения С++ нет неинициализированных переменных, как сказано у вас в вопросе
26 июл 2020 в 17:38
Узнать легко, вот например для int : Console.WriteLine(default(int).ToString());
26 июл 2020 в 17:45
"Всякий мусор" - это обычно то, что хранила другая переменная, которая "жила" до того в этом месте. В C++ таким образом можно подсмотреть или даже поменять "чужие" данные или даже код, что очень небезопасно, поэтому в современных языках подходят строже к таким вещам и среда выполнения инициализирует значения переменных в любом случае.
Проклятие неинициализированных переменных
Позволять программистам использовать неинициализированные переменные — большая ошибка со стороны разработчиков языка. Например, это может привести к значению undefined в JavaScript, которое чревато сопутствующими ошибками.
Такую оплошность легко совершить и тяжело отследить. Особенно при выполнении программы на разных платформах. И необходимости в этой особенности нет — переменная всегда должна иметь определенное значение.
Проблема
Локальные переменные, переменные-поля и т. д. представляют собой неинициализированные переменные, то есть в них будет записано ровно то, что было записано в отведенной под них памяти при объявлении. В C++ существуют различные правила для работы с неинициализированными переменными, инициализированными переменными и нуль-инициализированными переменными. Очень путанный механизм.
Учитывая частоту, с которой в коде появляются неинициализированные переменные, можно подумать, что отследить подобные ситуации в коде легко. Совсем нет. Да, конечно же, большая часть автоматически инициализируется нулем, если не указано иное. Однако так происходит не всегда. Например, в результате выполнения этого кода:
#include int main() < bool a; if( a ) < std::cout else < std::cout int b; std::cout
В результате выполнения этого кода у автора статьи всегда печатается False и 0 . Ошибок, связанных с утечкой памяти, можно избежать, используя valgrind .
Но основная проблема заключается в том, что программы даже в таком случае продолжают работать, что снижает вероятность обнаружения ошибки. Обычно ее можно отследить, только лишь запустив тестирование на другой платформе.
Почему ноль?
Почему программа автоматически инициализирует переменную нулем? На самом деле, это делает не программа, а операционная система, которая просто не позволит приложению проникнуть в неинициализированную область памяти, такова природа этого защитного механизма. Если программа A отработала свое, и результаты ее работы остались где-то в памяти, то программа B не должна обнаружить их во время своей работы, а потому ядро самостоятельно очищает память. В частности, Linux прописывает в освободившуюся память нули.
Естественно, нет никакого правила, чем заполнять память. Вероятно, OpenBSD делает это как-то иначе. Иначе чистит память и ArchLinux, запущенный в VirtualBox. Этим может заниматься не только операционная система — то же может проделать и другая программа, например. И если вдруг в область памяти, которую использует приложение, попадут какие-нибудь значения, изменить их сможет уже только сама эта программа.
Любопытно, что это стало одной из причин появления Heartbleed бага.
Решение
Язык просто не должен позволять использовать неинициализированные переменные. Необязательно нужно указывать конкретное значение — значение просто обязательно должно быть. Например, значением по умолчанию может стать все тот же ноль. Вне зависимости от того, как и в какой области видимости я создал данную переменную.
В то же время, могут быть сделаны определенные исключения в пользу оптимизации. Например, при работе с памятью на низком уровне. Впрочем, оптимизатор обычно обнаруживает неиспользуемые переменные и может их принудительно не инициализировать. Если нам нужен блок неинициализированной памяти, у нас должна быть возможно выделить ее самостоятельно. В этом случае программист четко отдает себе отчет в производимых им действиях, а потому не должен попасть в ловушку.
И чтобы полностью отследить все моменты с инициализацией памяти, язык также должен иметь специальное значение noinit , которое будет показывать, что данная переменная не нуждается в инициализации.
Автор статьи уверен, что уже в ближайшем стандарте C++ должны быть реализованы эти изменения. Превращение неинициализированных ранее переменных в инициализированные не повлияет на корректность выполнения ни одной программы. Такое нововведение будет полностью backwards compatible, и серьезно улучшит популярный язык.
Перевод статьи «The uninitialized variable anathema: non-deterministic C++»