Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Архив форумов ЦИТФорума
Море(!) вопросов - Море(!) ответов
 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Как правильно задавать вопросы

Помогите с С++

 
Перейти:  
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование
Предыдущая тема :: Следующая тема  
Автор Сообщение
_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
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
_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
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
DmitryShm



Зарегистрирован: 17.11.2003
Сообщения: 211
Откуда: Казань

СообщениеДобавлено: Вт Ноя 18 2003 14:07    Заголовок сообщения: Re: вовсе нет Ответить с цитатой

А Вам никогда не приходило в голову использовать то обилие БЕСПЛАТНОГО кода (шаблонов классов) с умными указателями.
Должен напомнить, что такого рада программирование (имеется в виду тот кусок кода, который Вы опубликовали) не одобряется вовсе, т.к. не только не соответствует принятым правилам хорошего стиля, но и не правильно может быть понят компиляторами.
Советую Вам пересмотреть ВЕСЬ свой проект на предмет прозрачности и выразительности. Тогда у Вас будет хороший код, мне кажется.
_________________
love IT
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Отправить e-mail
Борис
Гость





СообщениеДобавлено: Вт Ноя 18 2003 14:55    Заголовок сообщения: Re: вовсе нет Ответить с цитатой

Уважаемый г-н _ZooY_, сказанное Вами

>>>... что ptr указывает на ту память, на которую указывал buf до того, как он стал указывать на новую выделеную память

в точности соответствет моему предыдущему сообщению:

>>> >>>в указателе ptr Вы запоминаете один
>>> >>>адрес (который находился в указателе
>>> >>>t.buf), затем в указатель t.buf
>>> >>>заносите другой адрес (оператором new)

И ошибка возникает из-за того, что Вы пытаетесь освободить память, которую выделяет не Ваша программа. Как раз этого делать нельзя. Можно освобождать только то, что Вы выделяете сами.

Кстати, если не секрет, поясните, что должен делать блок кода, приведённый Вами? Такое ощущение, что Вы хотите прочитать и проанализировать память вне пространства программы. Пощупать данные соседей? Smile
Вернуться к началу
_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    Заголовок сообщения: Продолжу... Ответить с цитатой

С тэгами беда...
В предыдущем сообщении следует читатьSadt.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 (-) Ответить с цитатой

-
Вернуться к началу
Показать сообщения:   
Этот форум закрыт, вы не можете писать новые сообщения и редактировать старые.   Эта тема закрыта, вы не можете писать ответы и редактировать сообщения.    Список форумов Архив форумов ЦИТФорума -> Программирование Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB © 2001, 2002 phpBB Group
Русская поддержка phpBB

 

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 6608306, ICQ 232284597
Пресс-релизы — pr@citforum.ru
Послать комментарий
Информация для авторов
This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2006 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...