Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216

Освобождение участка памяти

08.11.2015, 19:46. Показов 1143. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый вечер. Подскажите, пожалуйста, где здесь ошибка. В разделе "После освобождения памяти" программа ничего не выдает.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;
#include<locale>
 
int main()
 
{
    setlocale(LC_ALL, "Russian");
    int *i;
    i = new int(1) ;
    cout << "\n*i=" << *i << "\t i=" << i ;
    i = new int(5);
    cout << "\t*i=" << *i << "\t\t i=" << i ;
    i = new int(2**i) ;
    cout << "\n*i=" << *i <<"\t i=" << i ;
    i = new int (2**i) ;
    cout << "\t*i=" << *i << "\t\t i=" << i ;
    delete i;
    cout << "\n После освобождения памяти:";
    cout << "\n*i=" << *i << "\t i=" << i ;
    delete i; // Некорректное применение операции
    cout << "\t*i=" << *i << "\t i=" << i ;
 
    cin.get();
    return 0;
    
 
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.11.2015, 19:46
Ответы с готовыми решениями:

Двойное освобождение одного и того же участка памяти
Всем привет! Помогите разобраться. Я написала в своем коде такую штуку: digits = X.digits; Получалось, что у меня два...

Резервирование памяти/освобождение памяти для трехмерного массива
Необходимо создать трехмерный массив (A), в котором элементы вдоль направления Z выли бы выровнены по 16 байт. Есть две проблемы: ...

Освобождение памяти
Есть класс, в котором я выделяю память с помощью new. В деструкторе класса я с помощью delete освобождаю память, но у меня вылетает ошибка...

20
 Аватар для _Valera_
495 / 377 / 136
Регистрация: 27.01.2015
Сообщений: 1,588
08.11.2015, 19:49
Цитата Сообщение от tst Посмотреть сообщение
delete i; // Некорректное применение операции
память уже была удалена в строчке 18

Добавлено через 1 минуту
Цитата Сообщение от tst Посмотреть сообщение
i = new int(1) ;
* * cout << "\n*i=" << *i << "\t i=" << i ;
* * i = new int(5);
* * cout << "\t*i=" << *i << "\t\t i=" << i ;
* * i = new int(2**i) ;
* * cout << "\n*i=" << *i <<"\t i=" << i ;
* * i = new int (2**i) ;
так не хорошо, потеряна память.
Алгоритм такой для каждого new свой delete
1
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 19:59  [ТС]
Если удаляю 21 и 22 строку тоже не проходит - пишет, что есть ошибка в 20-ой строке. Почему так происходит?
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 20:09
tst, ты перезатер все предыдущие адреса. Соответственно освободить память для первых трех new теперь невозможно.

C++
1
2
3
4
5
6
7
8
    int * i = new int(1) ;
    cout << "\n*i=" << *i << "\t i=" << i ;
    int * j = new int(5);
    cout << "\t*j=" << *j << "\t\t j=" << j ;
    int * z = new int(2**j) ;
    cout << "\n*z=" << *z <<"\t z=" << z ;
    int * x = new int (2**z) ;
    cout << "\t*x=" << *x << "\t\t x=" << x;
Ну и по delete для i, j, z и x в конце.
1
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 20:25  [ТС]
Итоговый код программы получился следующий. Но ошибка все равно осталась в delete - в строке 22.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
#include<locale>
 
int main()
 
{
    setlocale(LC_ALL, "Russian");
    int *i = new int(1);
    cout << "\n*i=" << *i << "\t i=" << i;
 
    int *j = new int(5);
    cout << "\t*j=" << *j << "\t\t j=" << j;
    int * z = new int(2 * *j);
 
    cout << "\n*z=" << *z << "\t z=" << z;
    int *x = new int(2 * *z);
    cout << "\t*x=" << *x << "\t\t x=" << x;
 
    delete i;
    cout << "\n После освобождения памяти:";
    cout << "\n*i=" << *i << "\t i=" << i;
 
    delete j;
    cout << "\n*j=" << *j << "\t j=" << j;
 
    delete z;
    cout << "\n*z=" << *z << "\t z=" << z;
 
    delete x;
    cout << "\n*x=" << *x << "\t x=" << x;
 
    cin.get();
    return 0;
 
}
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 20:28
Цитата Сообщение от tst Посмотреть сообщение
Но ошибка все равно осталась в delete
Какого рода эта "ошибка"?
Единственная ошибка сейчас тут - это обращение к значению переменной по указателю, после освобождения памяти.
0
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 20:30  [ТС]
Выглядит следующим образом (на скрине)
Миниатюры
Освобождение участка памяти  
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 20:36
tst, похоже на невнимательность. Ты уверен, что собираешь и запускаешь именно тот код, который ты показал?

Добавлено через 21 секунду
Ну и чтение из освобожденной памяти конечно надо убрать.

Добавлено через 53 секунды
C++
1
2
3
4
5
6
7
8
9
10
11
12
    delete i;
    cout << "\n После освобождения памяти:";
    cout << "\n*i=" << *i << "\t i=" << i; // НЕЛЬЗЯ тут разыменовывать i
 
    delete j;
    cout << "\n*j=" << *j << "\t j=" << j; // НЕЛЬЗЯ тут разыменовывать j
 
    delete z;
    cout << "\n*z=" << *z << "\t z=" << z; // НЕЛЬЗЯ тут разыменовывать z
 
    delete x;
    cout << "\n*x=" << *x << "\t x=" << x; // НЕЛЬЗЯ тут разыменовывать x
0
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 20:40  [ТС]
Да, однозначно тот код, ну разве что за исключением первой строки, содержащей лишь комментарий.

Странно, но ошибка по-прежнему осталась.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
#include<locale>
 
int main()
 
{
    setlocale(LC_ALL, "Russian");
    int *i = new int(1);
    cout << "\n*i=" << *i << "\t i=" << i;
 
    int *j = new int(5);
    cout << "\t*j=" << *j << "\t\t j=" << j;
    int * z = new int(2 * *j);
 
    cout << "\n*z=" << *z << "\t z=" << z;
    int *x = new int(2 * *z);
    cout << "\t*x=" << *x << "\t\t x=" << x;
 
    delete i;
    cout << "\n После освобождения памяти:";
    cout << "\n*i=" << *i << "\t *i=" << *i;
 
    delete j;
    cout << "\n*j=" << *j << "\t *j=" << *j;
 
    delete z;
    cout << "\n*z=" << *z << "\t *z=" << *z;
 
    delete x;
    cout << "\n*x=" << *x << "\t *x=" << *x;
 
    cin.get();
    return 0;
 
}
0
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 20:49
tst, скомпилируй новый вариант с учетом замечаний.

Вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <locale>
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "Russian");
    int * i = new int(1);
    cout << "\n*i=" << *i << "\t i=" << i;
 
    int * j = new int(5);
    cout << "\t*j=" << *j << "\t\t j=" << j;
    int * z = new int(2 * *j);
 
    cout << "\n*z=" << *z << "\t z=" << z;
    int * x = new int(2 * *z);
    cout << "\t*x=" << *x << "\t\t x=" << x;
 
    delete i;
    cout << "\n После освобождения памяти:";
    //cout << "\n*i=" << *i << "\t *i=" << *i;
 
    delete j;
    //cout << "\n*j=" << *j << "\t *j=" << *j;
 
    delete z;
    //cout << "\n*z=" << *z << "\t *z=" << *z;
 
    delete x;
    //cout << "\n*x=" << *x << "\t *x=" << *x;
 
    cin.get();
    return 0;
}
Добавлено через 2 минуты
Цитата Сообщение от tst Посмотреть сообщение
Странно, но ошибка по-прежнему осталась.
Собственно я же сказал, что разыменовывать невалидный пойнтер нельзя. А ты вместо того, чтобы его убрать, добавил еще одно для каждого случая )
1
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 21:06  [ТС]
Видимо, я действительно недопонимаю чего-то. Вот так будет правильно? Ошибка наконец исчезла

Код следующий
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <locale>
using namespace std;
 
int main()
{
    setlocale(LC_ALL, "Russian");
    int * i = new int(1);
    cout << "\n*i=" << *i << "\t i=" << i;
 
    int * j = new int(5);
    cout << "\t*j=" << *j << "\t\t j=" << j;
    int * z = new int(2 * *j);
 
    cout << "\n*z=" << *z << "\t z=" << z;
    int * x = new int(2 * *z);
    cout << "\t*x=" << *x << "\t\t x=" << x;
 
    delete i;
    cout << "\n После освобождения памяти:";
    //cout << "\ni=" << i << "\t i=" << i;
 
    delete j;
    //cout << "\nj=" << j << "\t j=" << j;
 
    delete z;
    //cout << "\nz=" << z << "\t z=" << z;
 
    delete x;
    //cout << "\nx=" << x << "\t x=" << x;
 
    cin.get();
    return 0;
}

Результат работы программы:
Миниатюры
Освобождение участка памяти  
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
08.11.2015, 21:14
Цитата Сообщение от tst Посмотреть сообщение
недопонимаю чего-то
Если память выделена, то её можно использовать.
Разыменовать указатель значит получить значение по адресу, который хранится в указателе.
Если память уже удалена (недоступна), то использовать значение в ней нельзя.
Правила простые.
1
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 21:15
Цитата Сообщение от tst Посмотреть сообщение
Вот так будет правильно?
Да.

Цитата Сообщение от tst Посмотреть сообщение
Ошибка наконец исчезла
Она была из-за чтения уже освобожденной памяти (*i, *z, *j, *x). Хотя ни на одном из моих компиляторов она не проявилась так фатально, как у тебя. Но это ничего не значит, на то оно и UB.
Я понимаю чего ты хотел добиться. Ты хотел посмотреть значение переменной после освобождения.
Собственно, ничего хорошего ты там все равно мне увидишь.
После применения к указателю delete он становится невалидным (некорректным). Можно посмотреть адрес, который он содержит. Можно присвоить этому указателю новое значение. Разыменовывать невалидный адрес - нельзя.
1
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 21:26  [ТС]
Спасибо, теперь ясно почему так происходило. А если значения после delete все-таки нужно просмотреть, чем тогда лучше воспользоваться?
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
08.11.2015, 21:27
Цитата Сообщение от DrOffset Посмотреть сообщение
Разыменовывать невалидный адрес - нельзя.
Или всё таки разыменовывать можно, но нельзя использовать результат разыменования?
1
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 21:38
Цитата Сообщение от Tulosba Посмотреть сообщение
Или всё таки разыменовывать можно, но нельзя использовать результат разыменования?
Автору на текущем уровне обучения - нельзя.

Добавлено через 3 минуты
Цитата Сообщение от tst Посмотреть сообщение
А если значения после delete все-таки нужно просмотреть, чем тогда лучше воспользоваться?
Честно говоря, не могу представить зачем это может быть нужно.
1
 Аватар для tst
1 / 1 / 0
Регистрация: 23.08.2015
Сообщений: 216
08.11.2015, 21:42  [ТС]
Честно говоря, не могу представить зачем это может быть нужно.
Хотелось бы сделать, так сказать, для наглядного понимания
0
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
08.11.2015, 21:42
Цитата Сообщение от DrOffset Посмотреть сообщение
Автору на текущем уровне обучения - нельзя.
Это безусловно. Но нам-то знать не помешает. Я вот что-то подзабывал этот тонкий момент.
Цитата Сообщение от tst Посмотреть сообщение
А если значения после delete все-таки нужно просмотреть,
Заглянуть глазком в загробную жизнь? Используй отладчик, он тебе поможет посмотреть что да как.
1
19491 / 10097 / 2460
Регистрация: 30.01.2014
Сообщений: 17,805
08.11.2015, 21:49
Цитата Сообщение от tst Посмотреть сообщение
Хотелось бы сделать, так сказать, для наглядного понимания
Для наглядного понимания рекомендую реализовать собственный менеджер памяти

Цитата Сообщение от Tulosba Посмотреть сообщение
Я вот что-то подзабывал этот тонкий момент.
Разыменование возвращает ссылку. Если мы значение не используем (нет фактического чтения или записи), то все будет нормально. Скажем, операция &*ptr по стандарту легальна. (5.3.1/3)
1
:)
Эксперт С++
4773 / 3267 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
08.11.2015, 21:57
Цитата Сообщение от DrOffset Посмотреть сообщение
Скажем, операция &*ptr по стандарту легальна. (5.3.1/3)
Это я читал на SO. И тут всё же взаимообратные операции, которые друг друга гасят, превращая &*ptr по сути в ptr. А вот в выражении *ptr такого "гашения" нет.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.11.2015, 21:57
Помогаю со студенческими работами здесь

Освобождение памяти
Собственно есть простенький класс class Human { public: Human ( ); void ptintHuman(); private: static long...

Освобождение памяти в C++
Добрый день! В моей программе в функции выделяется память (new char) под символьный массив, который является элементом структуры. Это...

с++ Освобождение памяти
Здравствуйте, объявляю в классе: А ** а; Далее выделяю память в функции: а=0; a = new A*; for(uint i=0;i&lt;5;++i) { a =...

Освобождение памяти
Добрый день. Подскажите пожалуйста, почему возникает ошибка при уничтожение массива class MyClass { public: int *data; int...

Освобождение памяти в c++
Привет, помогите разобраться с освобождением памяти в c++. Я так понимаю, что если освободить память, то переменная удаляется, но почему же...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru