Форум: "Начинающим";
Текущий архив: 2008.04.06;
Скачать: [xml.tar.bz2];
Внизпроблема с локальной переменной типа Pchar Найти похожие ветки
← →
alshtam (2008-03-07 08:20) [0]Здравствуйте, помогите разобаться пожалуста.
Есть две процедуры, одна вызывает другую:
procedure DatamapSave(var dm:TDataMap; s:string; cript:boolean;var version:Pchar);
var
ss:Tfilestream;
begin
ss := TFileStream.Create(dm.FileName, fmCreate);
ss.Seek(0,soBeginning);
saveStrStream(ss,version);
dm.SaveToStream(ss); //сдесь возникает ошибка
if cript then
EncryptStream(ss, ss.Size, "0");
ss.Free;
end;
procedure saveStrStream(stri:Tstream; ss:Pchar);
var
j:integer;
s:Pchar;
begin
{$o-}
getmem(s,250);
j:=strlen(ss);
s:=Pchar(inttostr(j));
stri.WriteBuffer(s^,3);
stri.WriteBuffer(ss^,j+1);
FreeMemory(s); //если закоментить эту строку ошибки нет
end;
если закоментировать освобождение локальной переменной ошибки не возникает, но эт о вероятно приведет к утечкам памяти
Как освобожденная переменная могла привести к ошибке???
← →
Palladin © (2008-03-07 08:22) [1]
> s:=Pchar(inttostr(j));
это что такое? ты представляешь себе что это делает или просто так от балды написал?
← →
alshtam (2008-03-07 08:26) [2]а как пправильно?
j:integer;
если написать s:=Pchar(j); то в s ниче не попадает
← →
alshtam (2008-03-07 08:30) [3]к стати если ету строку закоментировать ошибка тоже не возникает, но каким образом она может повлиять на дальнйшую работу программы??
← →
Palladin © (2008-03-07 08:35) [4]зачем ты это написал? с какой целью?
← →
alshtam (2008-03-07 08:37) [5]с целью перевода переменной типа integer в string а затем в Pchar чтоб сохранить в файл.
← →
Palladin © (2008-03-07 08:45) [6]
> к стати если ету строку закоментировать ошибка тоже не возникает,
с чего вдруг она возникнет, и зачем тебе вообще использовать Pchar? это какая то религия? а saveStrStream вообще бред какой то...Procedure saveStrStream(stri:Tstream; Const s:String);
Var
n:Integer;
begin
n:=Length(s);
stri.WriteBuffer(n,SizeOf(n));
stri.WriteBuffer(s[1],n);
end;
ну и буду уж совсем до конца добрымFunction loadStrStream(stri:TStream):String;
Var
n:Integer;
Begin
stri.ReadBuffer(n,SizeOf(n));
SetLength(Result,n);
stri.ReadBuffer(Result[1],n);
End;
← →
alshtam (2008-03-07 08:50) [7]:) спасибо большое, но все же не понятна природа ошбки? глюк какойто!
← →
Palladin © (2008-03-07 08:56) [8]глюки в первую очередь искать у себя в голове нужно
объясняю на пальцахvar
j:integer;
s:Pchar;
begin
{$o-} // зачем оптимизацию отключил? мешала?
getmem(s,250); // взяли память, теперь s у нас равна например $1000
j:=strlen(ss);
s:=Pchar(inttostr(j)); // функция inttostr вернула переменную типа string, которая сразу же была приведена к типу pchar и переменная s равна теперь $2000, потому что именно там была создана строка
stri.WriteBuffer(s^,3); // зачем то ты записал 3 байта от s, тоесть 000
stri.WriteBuffer(ss^,j+1);
FreeMemory(s); //и тут ты зачем то освободил указатель на string, этого делать нельзя, за строками следят, и освобождаются они автоматически
end;
в результате ты кстати потерял где то в памяти 250 байт, они ж не освободились...
← →
alshtam (2008-03-07 09:26) [9]оптимизацию отключил для трасировки(на время)
> getmem(s,250); // взяли память, теперь s у нас равна например
> $1000
апочему 1000? разве по 4 байта на символ? ядумал 1байт
> // функция inttostr вернула переменную типа string, которая
> сразу же была приведена к типу pchar и переменная s равна
> теперь $2000, потому что именно там была создана строка
не непонял почему удвоилось все?
> //и тут ты зачем то освободил указатель на string, этого
> делать нельзя, за строками следят, и освобождаются они автоматически
не стой s она же типа Pchar и я под нее памят выделил потом Pchar и убил
> в результате ты кстати потерял где то в памяти 250 байт,
> они ж не освободились...
тоже не понял когда.
если разъесниш буду оч благодарен
← →
Palladin © (2008-03-07 09:41) [10]
> апочему 1000? разве по 4 байта на символ? ядумал 1байт
это я для примера привел значение указателя, это вымышленное значение и это значение указателя, грубо говоря адрес в твоем адресном пространстве, а не строки на которую типа он указывает
что происходит при вызове getmem. менеджер памяти (далее МП) выделяет кусочек памяти и возвращает его адрес. ты вызвал getmem(s,1000) например. МП нашел свободное пространство пометил это пространство как занято и присвоил указателю s адрес этого пространства. что происходит дальше. а дальше ты вызваешь функцию inttostr, которая тоже выделяет память (ей же нужно куда то заносить результат), и заполняет ее символьным представлением переданного числа. далее эта функция возвращает указатель на эту выделенную ею память и сохраняет этот указатель в переменной s, то есть предыдущее значение которое ты получил getmem потерялось (!). дальше. про действия inttostr я слишком утрировано рассказал что бы ты понял что переменная типа string это тоже указатель куда то в память. но на самом деле все гораздо сложнее. взятие и освобождение памяти под строку выполняется автоматически. кусок памяти выделенный под string выглядит так:
[счетчик ссылок:4b][длинна строки:4b][данные:много байт]
потому просто так freemem для указателя на [данные] вызывать нельзя. а ты пытаешься.
понял?
ps. постарайся понять разницу между указателем и данными на которые он указывает.
← →
alshtam (2008-03-07 09:46) [11]а теперь понял, спасибо за разьеснения!
← →
Игорь Шевченко © (2008-03-07 10:24) [12]" У некоторых людей отсутствует часть мозга, которая отвечает за понимание указателей"
(с) Джоэл Спольски
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.04.06;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.005 c