Различия в C ++ между динамической переменной и неопределенной памятью - PullRequest
0 голосов
/ 04 февраля 2019

Я только сейчас изучаю концепцию динамических переменных в C ++.Первый пример, с которым я столкнулся, был следующий.

  int *p1 = new int;
  std::cin >> *p1;
  *p = *p + 5;
  std::cout << *p1;

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

  int *p1;
  std::cin >> *p1;
  *p1 = *p1 + 7;
  std::cout << *p1;

Я попробовал это, и это не сработало.Это позволило мне ввести целое число из консоли, но ничего не выводило.Это почему?Даже если p1 указывает на случайную ячейку памяти, почему я не могу изменить значение того, на что оно указывает?Почему мне нужно назначить p «новой» ячейке памяти?

Ответы [ 4 ]

0 голосов
/ 04 февраля 2019

Здесь есть несколько вещей:

  • Когда вы не инициализируете переменную, она не указывает, каким будет ее значение (зависит от вашего компилятора, настроек компилятора, вашей ОС, состоянияваша машина в самый раз и т. д.).Это буквально все, что происходит в стеке в то время.
  • Операционные системы должны гарантировать изоляцию процесса, то есть, если один процесс ведет себя плохо, он не разрушает всю систему или не влияет на другие запущенные процессы.Одна из этих вещей - защита памяти.Каждый процесс имеет память, которую разрешено использовать.Если случайный адрес выпадает за пределы этого региона, ваша программа аварийно завершает работу.
  • Если случайный адрес попадает в допустимую область, он может быть «безвредным» или вы можете повредить свой стек процессов, кучу или любые другиедругое количество вещей, приводящих к более поздним таинственным сбоям.
  • Наконец, он не должен указывать на кучу или new фрагмент памяти - он может находиться в стеке.

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

int x = 0;
int* p1 = &x;
std::cin >> *p1;
*p1 = *p1 + 7;
std::cout << *p1;
std::cout << x; // x and *p1 refer to the same value
0 голосов
/ 04 февраля 2019

Разыменование неинициализированного указателя: неопределенное поведение , что в основном означает, что все может произойти.Как правило, на самом деле происходит одно из трех: либо программа немедленно завершит работу, либо продолжит работу.Это может также работать некоторое время, но плохо себя вести позже.Но вы не можете полагаться на какой-либо конкретный результат - неопределенное поведение означает, что может произойти все, что .

0 голосов
/ 04 февраля 2019

Это позволило мне ввести целое число из консоли, но ничего не выводило.Почему это так?

Если это произошло не из-за сбоя программы (как предложил VorpalSword), то, возможно, когда вы перезаписали (какое бы слово памяти вы не переписывали), что сломало что-то в механизме stdoutэто зависело от сохранения первоначальной стоимости.Смысл неопределенного поведения в том, что оно неопределенное - то есть, что именно произойдет, будет зависеть от точных деталей того, как работает каждый потенциально затрагиваемый механизм в процессе, и более точно, как он может выйти из строя, когда от предварительных условий зависит егобыли нарушены.В общем, никто не пытается задокументировать или охарактеризовать неопределенное поведение, потому что это будет бесконечная работа, и в любом случае это бесполезно, потому что программу, вызывающую неопределенное поведение, нужно все равно исправить.

Даже если p1 указывает на случайную ячейку памяти, почему я не могу изменить значение того, на что оно указывает?

Ну, вы можете -- но при этом вы вызвали неопределенное поведение, что означает, что ничто не гарантированно сработает сразу после этого, и если что-то не получится так, как вы хотели после этого, единственный человек, который будет винить вас:)

Почему мне нужно назначить p для «новой» ячейки памяти?

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

Оператор 'new' прерываетсяВы освобождаете из памяти кучу памяти, которую никто не использует, чтобы кто-то еще ее использовал, так что вы можете быть уверены, что она доступна только для личного использования.Оператор «delete» возвращает эту память обратно в кучу, чтобы ее можно было повторно использовать для других целей после того, как с ней покончено.

0 голосов
/ 04 февраля 2019

Скорее всего, он неисправен.Вы пробовали это пошагово в отладчике?

...