Почему данные все еще существуют после того, как я удалю пространство массива?

Сегодня обнаружил небольшую проблему при создании динамических массивов.

Я использую функцию resize() для изменения размера массива. В функции resize() я создал временный массив «newData», а затем присвоил ему новый размер, который хотел. Присвоив ему значение исходного массива «Данные», я установил

Data=newData;

На данный момент задача функции resize() выполнена. Перед выходом из функции у меня был каприз и я удалил пространство "newData" по

delete [] newData;

После этого, когда я вывожу значение данных [2], я все еще могу вывести значение.

Теперь я немного смущен. «Данные» и «новые данные» должны быть указателями, верно? Когда я использую оператор «Data=newData;», то, на что указывает «Data», должно стать адресным пространством, на которое указывает «newData». Если я удалю адресное пространство «newData», не должно ли также исчезнуть пространство, соответствующее «Данным»? Почему я могу продолжать выводить значения?

Ниже приведен полный код

#include<iostream>
using namespace std;
int Length = 0;
int* Data;
void resize(int,int *);

int main()
{
  Data = new int[5];//This is the space I allocated for the initial array
  for (int i = 0; i < 5; i++)
     Data[i] = i;
  Length = 5;//There are five data in the initial array
  int newLength = 10;//I started distributing new sizes to the initial array
  resize(newLength,Data);
  cout << Data[2];//The output is still 2
}

void resize(int newLength,int *Data)
{
  int* newData = new int[newLength];//A temporary array
  for (int i = 0; i <Length; i++)//Move the value of the original array to the temporary array
  {
     newData[i] = Data[i];
  }
  Data = newData;
  delete[] newData;//Delete the space where the temporary array is located
}

Ваша программа имеет неопределенное поведение, вот и все.

πάντα ῥεῖ 19.11.2022 10:34

@ πάνταῥεῖ То есть это действительно неправильный метод записи, и данные нестабильны, верно?

spciyofwolf123 19.11.2022 10:40

Это не только нестабильно. @ spciyofwolf123 прочитай мой ответ. С таким же успехом вы можете вызвать сбой программы или очень плохое поведение. То, что вы запрограммировали, является явной ошибкой. Кроме того, сигнатура вашей функции не имеет смысла; Data в resize — это копия указателя, который вы передаете, а не ссылка на этот указатель, так что Data = newData; на самом деле ничего не делает.

Marcus Müller 19.11.2022 10:42

Природа неопределенного поведения заключается в том, что оно не определено. Не делай этого, и точка.

πάντα ῥεῖ 19.11.2022 10:43

Ага, что сказал @πάνταῥεῖ: Компьютеры прекрасны тем, что на них можно запускать любую программу. Плохо то, что почти все программы совершенно бесполезны, и ваша работа как программиста состоит в том, чтобы заставить эту всемогущую машину делать именно то, что вы хотите, и ничего больше.

Marcus Müller 19.11.2022 10:45

@MarcusMüller Я изменил его, как вы сказали, и данные действительно стали подходящими. Спасибо

spciyofwolf123 19.11.2022 10:45

@spciyofwolf123 что. Ничто в этой программе не должно давать подходящие данные?!

Marcus Müller 19.11.2022 10:47

Пссс... std::vector

463035818_is_not_a_number 19.11.2022 10:51

@ 463035818_is_not_a_number пссс… расширил мой ответ, упомянув об этом.

Marcus Müller 19.11.2022 10:57

@MarcusMüller Я обнаружил, что после добавления & к форме функции и добавления «удалить [] данные;» перед последним предложением функции изменения размера выходное значение данных [2] в основной функции больше не является строкой чисел.

spciyofwolf123 19.11.2022 10:57

@ spciyofwolf123 это не подходящие данные. Опять же, вы не должны ничего предполагать об этих данных. Ни как выглядит, ни как не выглядит. То, что там были исходные данные, не было ошибкой.

Marcus Müller 19.11.2022 10:58

@ spciyofwolf123 вывод кода с неопределенным поведением бессмысленен. Он может измениться, даже если вы не будете изменять код. Это может измениться, когда луна находится в другой фазе.

463035818_is_not_a_number 19.11.2022 10:58

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

Marcus Müller 19.11.2022 10:59

Дело в том, что код без неопределенного поведения имеет четко определенное поведение, стандарт языка гарантирует вам, что программа делает при ее выполнении. Вы не получите этого для кода с неопределенным поведением, это больше похоже на игру в кости, вы можете получить то, что ожидаете, может даже выглядеть так, как если бы он был надежным и воспроизводимым, но это не случайно

463035818_is_not_a_number 19.11.2022 11:00
en.cppreference.com/w/cpp/language/ub
Jesper Juhl 19.11.2022 12:22
[JS за 1 час] - 9. Асинхронный
[JS за 1 час] - 9. Асинхронный
JavaScript является однопоточным, то есть он может обрабатывать только одну задачу за раз. Для обработки длительных задач, таких как сетевые запросы,...
Топ-10 компаний-разработчиков PHP
Топ-10 компаний-разработчиков PHP
Если вы ищете надежных разработчиков PHP рядом с вами, вот список лучших компаний по разработке PHP.
Скраппинг поиска Apple App Store с помощью Python
Скраппинг поиска Apple App Store с помощью Python
📌Примечание: В этой статье я покажу вам, как скрапировать поиск Apple App Store и получить точно такой же результат, как на Apple iMac, потому что...
Редкие достижения на Github ✨
Редкие достижения на Github ✨
Редкая коллекция доступна в профиле на GitHub ✨
Подъем в javascript
Подъем в javascript
Hoisting - это поведение в JavaScript, при котором переменные и объявления функций автоматически "перемещаются" в верхнюю часть соответствующих...
Улучшение генерации файлов Angular
Улучшение генерации файлов Angular
Angular - это фреймворк. Вы можете создать практически любое приложение без использования сторонних библиотек.
1
15
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы (пытаетесь¹) получить доступ к удаленному пространству; это то, что называется поведением undefined в C++: может случиться что угодно. Там могут быть исходные значения, могут быть какие-то другие данные, над которыми вы работали, может быть значение 0xdeadcafe повсюду, ваша программа может рухнуть или вызвать пожар, удалить все файлы или предоставить доступ злоумышленнику.

Это не определено, и вы обнаружили одну из вещей, которые могут произойти.


¹ Судя по вашему вопросу, это было вашим намерением. К счастью, вы испортили свой прототип функции resize и передали указатель Data по значению, а не по ссылке, так что ваш Data = newData; ничего не делает за пределами вашей функции. Это вместе с глобальными переменными поверх ваших файлов: может быть, пересмотреть, что такое функция и что означают область действия и передача по ссылке!


В общем, вы новичок в C++: круто! Это хороший путь. Может быть, делайте меньше с new и delete. Прошло некоторое время с тех пор, как я использовал эти два, они становятся редкостью в современном C++! С++ вполне может (по большей части) быть написан без них, полностью, с использованием других методов, где выделение и освобождение памяти связаны с временем жизни объектов. И это менее подвержено ошибкам и, честно говоря, проще для понимания. Например, в вашем случае использования вместо вашей обработки Data, newData, new и delete вы могли бы сказать std::vector<int> Data(Length);, вставить значения точно так, как вы это сделали, а затем просто вызвать Data.resize(newLength);. Нет необходимости вручную знать, где удалить память!

Я не уверен, почему вы это делаете, но вы объявляете свои переменные глобально. Это плохая идея от начала до конца, так что просто не делайте этого: объявляйте переменные в нужной вам области видимости, которая будет вашей main функцией. Может быть, кто-то, у кого была копия какой-нибудь книги по C в самом начале 1970-х годов, перепутал устаревший C с C++, которому вас следует учить? Я не знаю. Глобальные переменные, как правило, плохая идея.

Спасибо за совет(´・ᴗ・`). Я изучаю структуры данных. Учитель дал задание составить список переменной длины. Учитывая, что вектор уже является инкапсулированной структурой данных, я решил использовать «новый» для его создания.

spciyofwolf123 19.11.2022 11:04

Ах, здорово! Да, std::vector внутренне использует new внутренне (или что-то эквивалентное). Однако чего он не делает, так это не копирует какие-либо элементы, когда вы сжимаете вектор, и, что самое элегантное, в структуре данных, он сохраняет свои собственные знания о длине своего содержимого (и длине выделенной памяти). , потому что это может быть больше, чем текущая длина содержимого). Итак, если вам поручили создать структуру данных на C++, попробуйте поместить указатель на данные и текущую длину в class (или struct, то же самое) и дайте ей метод .resize.

Marcus Müller 19.11.2022 11:15

(подсказка: C++ и другие языки программирования имеют struct (C и C++) /class (C++, Java, Python, …) / object (Javascript,…) /… именно для того, чтобы избежать ложного перемещения вокруг неструктурированных глобальных значений. Вот что это заключается в разработке структуры данных: точно определите, что является ее частью, а что нет. Использование глобальных переменных здесь действительно является проблемой, если задача заключалась в разработке структуры данных!)

Marcus Müller 19.11.2022 11:17

Другие вопросы по теме