глюки указателей

Lodi
Дата: 10.12.2007 13:44:09
Есть файл:
123456789...

автор
var
p: PChar;
FStrm: TFileStream;
begin
GetMem(p,4);
FStrm:=TFileStream.Create('C:\TextFile.TXT',fmOpenRead);
FStrm.Read(p^,4);
ShowMessage(p);
end;


Вываливается 1234Button2
Откуда берётся Button2 - ошибка Delphi?



ИЛИ ещё хуже


автор
Type
PStr = ^TStr;
TStr = string[4];

var
pp: PStr;
begin
New(pp);
FStrm:=TFileStream.Create('C:\TextFile.TXT',fmOpenRead);
FStrm.Read(pp^,4);
ShowMessage(pp^);
end;


Вылезает 234'квадрат' вместо 1234.


если присваивать так:
pp^:='1234';
то нормально.
Johnmen
Дата: 10.12.2007 13:50:47
автор
Вываливается 1234Button2
Откуда берётся Button2 - ошибка Delphi?

Как откуда? 4 байта ты выделил, это 1234, а Button2 это из чужой области.
Lodi
Дата: 10.12.2007 14:05:13
Непонятно, почему забирает из чужой области, когда читаю 4 байта,
Описание процедуры GetMem

Syntax


[Delphi] procedure GetMem(var P: Pointer; Size: Integer);


Description
P is a variable of any pointer type. Size is an expression specifying the size in bytes of the dynamic variable to allocate. Access the newly allocated memory by dereferencing the pointer; that is, use P^.
If there isn't enough memory available to allocate the dynamic variable, an EOutOfMemory exception is raised.
Note:
It is considered preferable to use the New and Dispose procedures rather than GetMem and FreeMem .


Насколько я понял отсюда, она выделяет Size байт памяти. Я выделил всего 4???
Bulygin Roman
Дата: 10.12.2007 14:07:49
Строка должна заканчиваться нулём. После чтения ты никаких нулей вконец строки не дописываешь и при определённых (ну очень благоприятных) обстоятельствах, он тебе вообще всю память до конца 4-го гигабайта может вывести. ;)

Короче,
1. резервируй памяти на 1 байт больше
2. Дописывай в последний байт #0
Warstone
Дата: 10.12.2007 14:13:20
Вообще, то что ты делаешь - это C-Style. P-Style этого кода:
var
  s:String;
  FStrm:TFileStream;
begin
  SetLength(s, 4); //Это если именно 4 байта, а так - сколько надо
  FStrm:=TFileStream.Create('C:\TextFile.TXT',fmOpenRead);
  FStrm.Read(@s[1],4);
  ShowMessage(s);
end;
Bulygin Roman
Дата: 10.12.2007 14:16:09
Warstone
Вообще, то что ты делаешь - это C-Style. P-Style этого кода:

Одно из преимуществ, кстати, что никаких нулей в конец дописывать не надо, всё там уже есть.
Anatoly Podgoretsky
Дата: 10.12.2007 16:05:37
автор
Вываливается 1234Button2
Откуда берётся Button2 - ошибка Delphi?

Это мусор из буфера. Хочешь брать 4 байта используй другую функцию.
Зачем тебе указатель в данной программе, тем более, что ты не умеешь с ними работать и не понимаешь устройство строк.
Используй тип string и не будет у тебя проблем.
Warstone
Дата: 10.12.2007 16:15:30
Bulygin Roman
Одно из преимуществ, кстати, что никаких нулей в конец дописывать не надо, всё там уже есть.
Ну да... Сначала через SetLength ставим в 0-й байт 4(ну не все так просто, но...), а потом просто копируем 4 байта в 1-й байт (со смещением ессно). Только вот ри выводе все знают, что выводить надо столько, сколько в 0-м написанно. И Это ИМХО - преимущество P-строк перед C-строками. (Дискуссию по поводу сравнения стрингов, и прочих элементов одежды, устраивать не надо!)
Dimitry Sibiryakov
Дата: 10.12.2007 16:22:18

Warstone

Сначала через SetLength ставим в 0-й байт 4(ну не все так просто,
но...), а потом просто копируем 4 байта в 1-й байт

Это для тех, кто не смог найти SetString.

Posted via ActualForum NNTP Server 1.4

Bulygin Roman
Дата: 10.12.2007 16:45:14
Warstone
Ну да... Сначала через SetLength ставим в 0-й байт 4(ну не все так просто, но...), а потом просто копируем 4 байта в 1-й байт (со смещением ессно). Только вот ри выводе все знают, что выводить надо столько, сколько в 0-м написанно. И Это ИМХО - преимущество P-строк перед C-строками. (Дискуссию по поводу сравнения стрингов, и прочих элементов одежды, устраивать не надо!)


Ну, на самом деле эти паскалевские строки поинтереснее устроены. Например сработает и такой фокус:
var
  s:String;
  p: PChar;
  FStrm:TFileStream;
begin
  SetLength(s, 4); //Это если именно 4 байта, а так - сколько надо
  FStrm:=TFileStream.Create('C:\TextFile.TXT',fmOpenRead);
  FStrm.Read(@s[1],4);
  p := PChar(s);
  ShowMessage(p);
end;
SetLength(s, 4) выделяет памяти несколько побольше, чем 4 байта. Если считать, что строка -- это собственно 4 байта, которые несут для нас смысловую нагрузку, то к ним добавочно выделяется наверное 4 байта (а может и все 8 байт -- честно говоря, не знаю) перед строкой на длину строки и счётчик ссылок, потом сразу идут собственно наши четыре смысловых байта на содержимое и наконец 1 байт, содержащий нолик, если кому-то придёт в голову мысль привести строку к PChar и оный PChar куда-то в API отправить. А тут кстати есть ловушка. После SelLength(s, Size) все указатели, полученные с помощью PChar(s) могу стать недействительными. А могут и не стать..