Мой вопрос:указатель и динамической памяти распределение
int* x = new int;
cout << x<<"\n";
int* p;
cout << p <<"\n";
p = x;
delete p;
cout << p <<"\n";
Я написал это чисто сам понимать указатель и понять (также теряться в) динамический new
и delete
.
Мой XCode может составить программу и возвращать следующие результаты:
0x100104250
0x0
0x100104250
Я знаю, что я могу назвать только удалить динамически выделенную память. Однако я назвал delete в p
в вышеуказанной программе и скомпилирует.
Может ли кто-нибудь объяснить это мне? Почему я могу удалить p
?
Кроме того, я обнаружил, если программа переходит в следующее:
int* x = new int;
int* p;
cout << p <<"\n";
delete p;
cout << p <<"\n";
Тогда мой Xcode снова собирает и возвращает меня:.
0x0
0x0
Program ended with exit code: 0
и теперь, я получил полностью потерял :( Может ли кто-нибудь объяснить мне это? Почему я мог удалить p
, так как он не имеет ничего общего с x
?
Поскольку Xcode успешно компилируется, я предполагаю, что указанные выше две программы верны для компьютера. Тем не менее, я думаю, что это снова утверждение «только удаление вызова в динамической выделенной памяти». Или, возможно, я не совсем понял, что такое указатель и что такое динамически распределенная память. Я нашел это post, когда искал в Интернете. Но я не думаю, что это похоже на мое дело.
Пожалуйста, помогите мне.
Я хотел бы задать еще один вопрос. Код here о бинарном дереве поиска. В строке 28-32 речь идет об удалении узла одним ребенком. Здесь я помещаю эту часть кода, если веб-ссылка не работает.
else if (root-> left == NULL) { struct Node * temp = root; root = root-> right; delete temp; }
Это коды, которые приводят меня, задают вышеуказанный вопрос относительно указателя. После ответа, данного этим сообщением. Правильно ли понимать код следующим образом?
Я не могу вначале связать родительский узел root с правым дочерним элементом root. , а затем удалить корневой узел, поскольку поддерево под корневым узлом также будет удалено. Поэтому я должен создать указатель темпа, указывая на слот памяти, на который указывает корень. Затем я связываю родительский узел с корнем с дочерним элементом root. , и теперь я могу безопасно удалить слот памяти, обозначенный «root» (т. Е. Темп, поскольку оба они указывают на одну и ту же память). Таким образом, я освобождаю память, а также сохраняю связь между родителем и дочерними элементами. Кроме того, темп все еще присутствует и по-прежнему указывает на «этот» слот памяти. Должен ли я установить его в NULL после удаления?
Спасибо всем заблаговременно.
Yaofeng
Вы "повезло", что 'p' является' 0' в вашем втором примере кода. Поскольку он не инициализирован, он может иметь любую ценность. Так как это '0' (aka' NULL'), то можно вызвать 'delete' (это полезно, чтобы избежать наличия миллиона проверок для' NULL', особенно при работе с условиями ошибки, при которых не удалось выполнить выделение, и вы хотите очистите остальные распределения - если все указатели сначала инициализируются на «NULL», тогда вы можете просто «удалить» все, не беспокоясь, какой из них не удалось выделить). –
Просто совет, вы всегда должны инициализировать переменные указателя, такие как int * p = 0; или int * p = NULL; Это потому, что в сборке отладки это будет сделано для вас. Но в релиз-сборке это не будет сделано. Это может сэкономить вам много времени на отладку. – user743414
@ user743414 Если вы не поддерживаете устаревший код, вы должны использовать C++ 11 и, следовательно, 'int * p = nullptr;'. (Эта часть) C++ 11 уже много лет поддерживается всеми основными компиляторами. – Angew