Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 10:52 Заголовок сообщения: Помогите с С++ |
|
|
Есть такой код: char * ptr; ptr = t.buf; //t - класс, с полем buf типа char * t.buf = new char [count]; for(i = 0; i < t.count; i++) t.buf[i] = ptr[i]; delete [] ptr;
Так вот на последней строчке вываливается какая-то нелепая ошибка: "Debug Error! Program: имя_моей_программы.exe DAMAGE: after Normal block (#60) at 0x00301AB0." и кнопки Прервать, Повторить и Пропустить.
В чем тут может быть дело? |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 10:54 Заголовок сообщения: Да, кстати... |
|
|
...если эту строчку (delete [] ptr;) убрать, то все нормально работает, но надо же как-то освобождать память то |
|
Вернуться к началу |
|
|
DmitryShm
Зарегистрирован: 17.11.2003 Сообщения: 211 Откуда: Казань
|
Добавлено: Пн Ноя 17 2003 14:56 Заголовок сообщения: Re: Помогите с С++ |
|
|
Во-первых, для чего Вам понадобился этот код. Вы, видимо, неправильно понимаете, что пишете.
char * ptr; // объявление указателя ptr = t.buf; // присваивание ему адреса поля // t.buf //t - класс, с полем buf типа char * t.buf = new char [count];// выделение памяти // под t.buf и ptr for(i = 0; i < t.count; i++) //цикл t.buf[i] = ptr[i];// присваивание самому // себе ? (помните, что //(ptr == t.buf) - это // true) delete [] ptr;//error, естественно, кому //же понравится неверный //указатель t.buf, который // будет теперь указывать на //невыделеный блок памяти. _________________ love IT |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 16:23 Заголовок сообщения: нет я прекрасно понимаю что делаю |
|
|
нет я прекрасно понимаю что делаю, мне нехватент ранее выделенной памяти, я создаю указатель на ранее выделенную память (ptr), выделяю новую память и привязываю ее к старому указателю, затем копирую содержимое старой памяти в новую более большую (копирую поэлементно) и освобождаю старую память |
|
Вернуться к началу |
|
|
grayrat
Зарегистрирован: 30.06.2003 Сообщения: 189
|
Добавлено: Пн Ноя 17 2003 16:24 Заголовок сообщения: Re: Помогите с С++ |
|
|
Нефига! после t.buf = new char [count] t.buf уже не равно ptr. Вопрос в другом: куда указывал t.buf, а значит после ptr=t.buf и ptr, в самом начале примера, и каким образом под него была выделена память (если конечно выделена)
Если всё нормально то проверь все операции с памятью. Я однажды на один байт просчитался, не учёл место под ноль-символ в конце строки с именем файла, выделил 12 байт вместо 13, и долго не мог понять почему уменя при некоторых наборах входных данных или при перемене местами некоторых строк в программе происходит вылет в функции free очень далеко от того места где была допущена ошибка.
ещё рекомендация: вместо цикла лучше использовать memcpy( t.buf, ptr, count ). |
|
Вернуться к началу |
|
|
grayrat
Зарегистрирован: 30.06.2003 Сообщения: 189
|
Добавлено: Пн Ноя 17 2003 16:39 Заголовок сообщения: используй realloc |
|
|
struct T { char *buf; int count; };
T t; t.count = 100; // конечно не так грубо надо, но для примера сойдёт t.buf = (char *)malloc( t.count );
что-то делаем, ... и тут 100 байт не хватило ... // вводим ВРЕМЕННЫЙ уазатель: char *ptr = t.buf; t.buf = realloc( t.buf, newcount ); if( !t.buf ) { t.buf = ptr; // восстанавливаем значение return myerror( "not enough memory !); } t.count = newcount; // и работаем дальше, а ptr вообще не трогаем
Если сразу за старым куском памяти есть достаточно свободного места, то оно будет добавлено к уже имеющемуся и копирование данных не потребуется. Если нет, то память будет выделена в другом месте а данные будут скопированы автоматически. Если newcount < count то выделенный кусок будет просто усечён. Как видите, не только упрощается код, но и ускоряется работа.
Разумеется, очищать буфер нужно будет так: free( t.buf ); |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 16:50 Заголовок сообщения: к сожалению нельзя... |
|
|
дело не только в том чтобы было просто, так я бы мог вообще кучц памяти слазу выделить и все дела, дало в том чтобы выделялось именно столько памяти сколько необходимо (это насчет ситуации когда newcount < count), а насчет realloc - заманчиво, но тоже не выход (свалим это на условие задачи, тем более что так оно и есть) |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 16:52 Заголовок сообщения: Re: Помогите с С++ |
|
|
>>Вопрос в другом: куда указывал t.buf,
ранее в программе под t.buf выделялась память там все нормально |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Пн Ноя 17 2003 17:30 Заголовок сообщения: Г-да, разрешите вас поправить |
|
|
>>> delete [] ptr;//error, естественно, кому >>> //же понравится неверный >>> //указатель t.buf, который >>> // будет теперь указывать на >>> //невыделеный блок памяти.
Эта строка действительно невена, но не по приведённой причине. Согласно коду и ptr, и t.buf указывают на один блок, и это выделенный блок. Ошибка в том, в операторе освобождения памяти стоит не тот указатель, которому выделялась память. Сравните операторы new и delete: первый требует указания необходимого размера памяти, а второй нет. Это потому, что ОС запоминает указатель, которому приписана память. Поэтому нельзя освобождать память, приписанную указателю ptr, так как ему ничего не приписано. Правильный код будет таким:
char * ptr; ptr = new char [count]; t.buf = ptr; for(i = 0; i < t.count; i++) t.buf[i] = ptr[i]; delete [] ptr;
или что-то в этом духе. Главное: который указатель участвует в операторе new, тот же и должен быть в операторе delete. |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 17:34 Заголовок сообщения: да, но тогда... |
|
|
...получается что под ptr мы память выделяем, но она зависает без указателя после того как ptr присвоим значение t.buf |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Пн Ноя 17 2003 17:54 Заголовок сообщения: Re: да, но тогда... |
|
|
Мысль верная, но не совсем соответствует приведённому коду. Согласно Вашему коду память выделяется указателю t.buf, а не указателю ptr. Соответственно нельзя освобождать память для ptr, так как ему ничего не выделено. |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Пн Ноя 17 2003 18:00 Заголовок сообщения: а делать то тогда что? |
|
|
так как тогда убить то эту память по указателю ptr, я уж пробовал и размер указфвать (delete [2] ptr;) все равно не работает |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Пн Ноя 17 2003 18:17 Заголовок сообщения: Re: а делать то тогда что? |
|
|
Удалять указатель ptr не нужно, так как для него нет команды new. ptr просто указывает на интересующую область, а не на какую-то специально выделенную. Вероятно, верным будет следующее:
char * ptr; // эта строка неясная: ptr = t.buf; // куда указывал ptr, и куда теперь он указывает? t.buf = new char [count]; for(i = 0; i < t.count; i++) t.buf[i] = ptr[i]; delete [] t.buf; |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Пн Ноя 17 2003 21:17 Заголовок сообщения: Re: Помогите с С++ |
|
|
Я ещё раз посмотрел переписку и обнаружил, что неверно выразился. Мои высказывания к данному случаю не относятся. На самом деле ошибка находится только в строке
ptr = t.buf;
так как по окончании делается попытка освободить блок, который выделялся не для указателя ptr (сам указатель ptr в этом случае смотрит не на только что выделенный блок, а на то, куда смотрел t.buf):
delete [] ptr;
Надо либо поменять местами операторы ptr = t.buf; t.buf = new char [count];, либо освобождать указатель t.buf. |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 18 2003 10:18 Заголовок сообщения: кстати ничего подобного |
|
|
Я узнал поконкретнее, при такой ситуации: char * buf = new char [5]; char * ptr; ptr = buf;
в ptr записывается адрес начала куска памяти на который ссылается buf (тоеть и ptr и buf начинают ссылаться на один и тот же кусок памяти), а также сопостовляются все данные, которые были известны о buf, в том числе и размер выделеной памяти. Поэтому строка delete [] ptr вполне корректна |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 18 2003 10:19 Заголовок сообщения: см. выше (-) |
|
|
- |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Ноя 18 2003 11:24 Заголовок сообщения: Re: см. выше (-) |
|
|
Я уже сказал, что неверно выразился и к данному случаю мои поправки не относятся. В отношении запоминаемого адреса начала выделенного блока действительно не имеет значения, в котором указателе этот адрес находится. В Вашем случае ошибка возникает из-за того, что в указателе ptr Вы запоминаете один адрес (который находился в указателе t.buf), затем в указатель t.buf заносите другой адрес (оператором new) и считаете, что ptr тоже указывает на этот новый адрес. Но он указывает на прежний адрес, который нельзя освободить, так как он не был выделен оператором new. |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 18 2003 12:26 Заголовок сообщения: вовсе нет |
|
|
я считаю что ptr указывает на ту память, на которую указывал buf до того как он стал указывать на новую выделеную память |
|
Вернуться к началу |
|
|
DmitryShm
Зарегистрирован: 17.11.2003 Сообщения: 211 Откуда: Казань
|
Добавлено: Вт Ноя 18 2003 13:33 Заголовок сообщения: Re: нет я прекрасно понимаю что делаю |
|
|
Этими присваиваниями память "поэлементно" копируется, действительно. Но зачем же тогда ее потом освобождать. Все операции остались бессмысленными: Вы все освободили. Попытайтесь еще раз построчно прочитать свой код и Вы убедитесь в этом. С другой стороны, разве нельзя использовать memcpy(..)? _________________ love IT |
|
Вернуться к началу |
|
|
DmitryShm
Зарегистрирован: 17.11.2003 Сообщения: 211 Откуда: Казань
|
Добавлено: Вт Ноя 18 2003 14:07 Заголовок сообщения: Re: вовсе нет |
|
|
А Вам никогда не приходило в голову использовать то обилие БЕСПЛАТНОГО кода (шаблонов классов) с умными указателями. Должен напомнить, что такого рада программирование (имеется в виду тот кусок кода, который Вы опубликовали) не одобряется вовсе, т.к. не только не соответствует принятым правилам хорошего стиля, но и не правильно может быть понят компиляторами. Советую Вам пересмотреть ВЕСЬ свой проект на предмет прозрачности и выразительности. Тогда у Вас будет хороший код, мне кажется. _________________ love IT |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Ноя 18 2003 14:55 Заголовок сообщения: Re: вовсе нет |
|
|
Уважаемый г-н _ZooY_, сказанное Вами
>>>... что ptr указывает на ту память, на которую указывал buf до того, как он стал указывать на новую выделеную память
в точности соответствет моему предыдущему сообщению:
>>> >>>в указателе ptr Вы запоминаете один >>> >>>адрес (который находился в указателе >>> >>>t.buf), затем в указатель t.buf >>> >>>заносите другой адрес (оператором new)
И ошибка возникает из-за того, что Вы пытаетесь освободить память, которую выделяет не Ваша программа. Как раз этого делать нельзя. Можно освобождать только то, что Вы выделяете сами.
Кстати, если не секрет, поясните, что должен делать блок кода, приведённый Вами? Такое ощущение, что Вы хотите прочитать и проанализировать память вне пространства программы. Пощупать данные соседей? |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 18 2003 17:28 Заголовок сообщения: а что нетак в моем куске кода? (-) |
|
|
- |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 18 2003 17:29 Заголовок сообщения: Re: вовсе нет |
|
|
что значит немоя программа? в моей программе ранее было естественно есть строка t.buf = new char [число] |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Ср Ноя 19 2003 08:40 Заголовок сообщения: Re: вовсе нет |
|
|
Уважаемый г-н _ZooY_,
Вы всё время пропускаете обстоятельство, что указатель ptr в момент освобождения памяти указывает не на правильный блок. Вот Ваш код:
>>>> char * ptr; >>>> ptr = t.buf; // в указателе ptr запоминаем некоторый адрес (назовём его adr(1)) >>>> t.buf = new char [count]; // выделяем блок памяти, его адрес запомнаем в указателе t.buf (назовём его adr(2)) >>>> for(i = 0; i < t.count; i++) // что-то делаем >>>> t.buf[i] = ptr[i]; // что-то делаем >>>> delete [] ptr; // освобождаем блок по адресу в указателе ptr, то есть adr(1).
Таким образом Ваш код выделяет блок по адресу adr(2), а Вы пытаетесь освободить блок по адресу adr(1), но Ваш код этот не выделял (это я и имел ввиду, говоря, что освобождаемую память выделяет не Ваша программа). Поэтому и возникает ошибка. |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Ср Ноя 19 2003 10:25 Заголовок сообщения: Re: вовсе нет |
|
|
Хороше, чтобы снять все непонятки напишу полностью char * t.buf; t.buf = new char [count1]; // выделяем блок памяти с адресом adr(1) char * ptr; ptr = t.buf; // в указателе ptr запоминаем адрес adr(1) t.buf = new char [count2]; // выделяем блок памяти, его адрес запомнаем в указателе t.buf (назовём его adr(2)) for(i = 0; i < t.count; i++) t.buf[i] = ptr[i]; delete [] ptr; // освобождаем блок по адресу в указателе ptr, то есть adr(1).
я уже неоднократно говорил, что память под t.buf ранее выделяется, иначе весь приведенный код просто не имееет смысл (ну не совсем же я дурак в конце концов)
Таким образом ptr указывает на вполне реальный блок памяти и непонятно почему его удаление вызывает ошибку |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Ср Ноя 19 2003 15:16 Заголовок сообщения: Это добавление существенно меняет дело (+) |
|
|
в этом блоке кода ошибок нет. Проверь его работу под другим компилятором. В частности g++ и MS VC++ 6.0 ошибок не дают.
PS Я проверил такой код: ----------------------- #include "stdio.h" int count1 = 10; int count2 = 10; int i; int main (void) { struct { char * buf; int count; } t; t.count = 10; t.buf = new char [count1]; char * ptr; ptr = t.buf; t.buf = new char [count2]; for(i = 0; i < t.count; i++) t.buf[i] = ptr[i]; delete [] ptr; delete [] t.buf; } |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Ср Ноя 19 2003 16:44 Заголовок сообщения: Ответ на: "Это добавление существенно мен..- Борис- 19-11-2003 15:16" у меня как раз MS VC++ 6.0 |
|
|
- |
|
Вернуться к началу |
|
|
winc Гость
|
Добавлено: Ср Ноя 19 2003 17:12 Заголовок сообщения: Re: Помогите с С++ |
|
|
Моё мнение - ты напутал с индексами массивов в цикле. Убедись, что t.count соответствует числу элементов в t.buf и не превышает count. |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Чт Ноя 20 2003 10:32 Заголовок сообщения: Остаётся предложить переустановку MSVC (-) |
|
|
- |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Чт Ноя 20 2003 11:25 Заголовок сообщения: не поможет, эффекут повторяется на нескольких машинах (-) |
|
|
- |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Чт Ноя 20 2003 11:26 Заголовок сообщения: Re: Помогите с С++ |
|
|
с индесками все в порядке, по крайней мере если смотреть по отладке то присвоение проходит прависльно |
|
Вернуться к началу |
|
|
winc Гость
|
Добавлено: Чт Ноя 20 2003 12:16 Заголовок сообщения: Буду настойчив :) |
|
|
То есть в отладке цикл проходит ДО КОНЦА? С указателями ты работаешь корректно, дак что не вижу, где ещё может быть проблема кроме как в цикле. Всё же поставь брикпоинт ПРЯМО ПЕРЕД циклом и проверь то что я писал в предыдущем посте. (Напомню (t.count==sizeof(*ptr)&&(t.count |
|
Вернуться к началу |
|
|
winc Гость
|
Добавлено: Чт Ноя 20 2003 12:26 Заголовок сообщения: Продолжу... |
|
|
С тэгами беда... В предыдущем сообщении следует читатьt.count==sizeof(*ptr)&&(t.count меньшеравно count) А ещё лучше, не поленись, убери цикл и запусти свой код. Если ошибка в нём, то она исчезнет. Это внесёт ясность. PS Заметь, код предложенный Борисом, отличается от твоего ТОЛЬКО явной инициализацией count1, count2 и t.count И он работает! |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Чт Ноя 20 2003 12:38 Заголовок сообщения: убрал цикл - ничто не изменилось (-) |
|
|
- |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Чт Ноя 20 2003 15:59 Заголовок сообщения: Попробуйте трассировкой проследить, что именно содержит указатель ptr при попытке освободить память (-) |
|
|
- |
|
Вернуться к началу |
|
|
_ZooY_ Гость
|
Добавлено: Вт Ноя 25 2003 10:37 Заголовок сообщения: адрес, который раньше был в buf (-) |
|
|
- |
|
Вернуться к началу |
|
|
|