Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.06.10;
Скачать: CL | DM;

Вниз

Кто внятно пояснит в чём проблема ?   Найти похожие ветки 

 
Kozhanov ©   (2002-05-31 14:01) [0]

type
PString = ^String;

procedure TForm1.Button1Click(Sender: TObject);
var
A : array[1..8] of Byte;
begin
FillChar(A, SizeOf(A), 0);
PString(@A[1])^ := "hello, buddy !";
PString(@A[5])^ := "good-bye, buddy !"; //здесь происходит
//крушение если заремить первую строчку ?!!!!!!!!
ShowMessage(PString(@A[1])^);
ShowMessage(PString(@A[5])^);
end;


 
Внук ©   (2002-05-31 14:16) [1]

Даже если не комментарить первую строчку, это все равно некорректно.
Начиная с пятого элемента массива пишутся слудеющие данные: длина строки "good-bye, buddy !", сама эта строка, нулевой символ-терминатор. Это больше трех - выход за пределы массива :)


 
Игорь Шевченко ©   (2002-05-31 14:17) [2]

PString(..)^ := String("hello, buddy!")

Зачем такой изврат нужен ?


 
Игорь Шевченко ©   (2002-05-31 14:20) [3]

Внук © (31.05.02 14:16)

Да ?

type
TmyCoolRecord = packed record
A : Byte;
B : PString;
C : PString;
end;

Не будет работать ?

С уважением,


 
Kozhanov ©   (2002-05-31 14:38) [4]

> Игорь Шевченко
Это не изврат !
Я просто проверяю здесь принцип представления данных
в последовательности байт. Этот принцип я буду использовать
потом...
Внук не прав, ведь @A[1] - это указатель(!) на строку
в памяти, а не сама строка. Как считаешь ?


 
Внук ©   (2002-05-31 14:43) [5]

>>Игорь Шевченко © (31.05.02 14:20)
IMHO, не будет. Давайте посмотрим:
A : array[1..8] of Byte; - статический массив
PString(@A[5])^ := "good-bye, buddy !";

@A[5] - адрес пятого элемента
PString(@A[5]) - этот адрес трактуется как указатель на AnsiString
PString(@A[5])^ - сама ANSI-строка, то есть указатель на ее первый элемент.
Поскольку явно она не описана, компилятор памятью для неене управляет. Назовем ее S
Где будет лежать S[1]? По смещению a[5]+4, то есть за пределами массива.
Не было под нее выделено памяти, и все тут :)


 
Внук ©   (2002-05-31 14:45) [6]

>>Kozhanov © (31.05.02 14:38)
Я лишь хочу сказать, что неплохо бы выделить память под строки :)


 
Kozhanov ©   (2002-05-31 14:47) [7]

> Внук
Delphi сама выделяет память под String и хранит кол-во
ссылок на String. Если кол-во ссылок становится = 0, то
String сносится из памяти.


 
MBo ©   (2002-05-31 14:48) [8]

строка AnsiString есть в самом деле указатель на первый символ, и
ptr:=s
и
ptr:=@s[1]
дадут один результат
(причем перед этим адресом лежит еще счетчик ссылок на эту строку и ее длина)


 
SPeller ©   (2002-05-31 14:48) [9]

2Игорь Шевченко © (31.05.02 14:20)

По-моему, внук прав.
PString(@A[1])^ := "hello, buddy !";
Сначала мы указатель на первый элемент массива преобразуем к указателю на строку. Затем пишем начиная с этого указателя текст " hello, buddy !", и последние шесть символов выходят за пределы массива. (Размерность то 8 байт).
А ваша запись
TmyCoolRecord = packed record
A : Byte;
B : PString;
C : PString;
end;

будет работать без проблем. В эту структуру заносится байт и два 4-х байтных указателя на строки. Это равносильно записи
TmyCoolRecord = packed record
A : Byte;
B : Longint;
C : Longint;
end;

Если в чём-то не прав, то поправьте меня.


2Kozhanov © (31.05.02 14:01)

А зачем тебе все эти извратства нужны? Сделай массив строк и пиши в них что захочешь.


 
Kozhanov ©   (2002-05-31 14:49) [10]

>MBo
Код корректный ?


 
Игорь Шевченко ©   (2002-05-31 14:50) [11]

Внук © (31.05.02 14:43)

procedure TForm1.Button4Click(Sender: TObject);
var
A : array[1..8] of Byte;
begin
FillChar(A, SizeOf(A), 0);
PString(@A[1])^ := "hello, buddy !";
PString(@A[5])^ := "good-bye, buddy !";
ShowMessage(PString(@A[1])^);
ShowMessage(PString(@A[5])^);
end;

Все прекрасно работает :-)

Kozhanov © (31.05.02 14:38)

Это - изврат :-)
Не изврат:

type
TmyCoolRecord = packed record
A : Byte;
B : PString;
C : PString;
end;



 
Игорь Шевченко ©   (2002-05-31 14:52) [12]

В дополнение:

Крах происходит потому, что "заремив" первую строчку все равно остается вызов ShowMessage(PString(@A[1])^);.
Ее тоже надо "заремить"


 
Kozhanov ©   (2002-05-31 14:53) [13]

>SPeller
"и последние шесть символов выходят за пределы массива"

Тогда почему же ShowMessage(PString(@A[1])^) и ShowMessage(PString(@A[5])^) всё правильно выводят ?


 
Внук ©   (2002-05-31 14:56) [14]

>>Kozhanov © (31.05.02 14:47)
"Delphi сама выделяет память под String..."
Угу, жедезно. Только покажите мне в Вашей программе переменную типа String


 
MBo ©   (2002-05-31 14:56) [15]

>Код корректный ?
нет, вот корректный

procedure TForm1.Button1Click(Sender: TObject);
var s:string;
ptr:pointer;
begin
setlength(s,$10000);
ptr:=pointer(s);//или PChar
label1.caption:=IntToHex(Cardinal(ptr),8);
ptr:=@s[1];
label2.caption:=IntToHex(Cardinal(ptr),8);
end;


 
Внук ©   (2002-05-31 14:58) [16]

>>Игорь Шевченко © (31.05.02 14:50)
Про то, что не будет работать, я имел в виду код автора. Вы в чем не согласны с Внук © (31.05.02 14:43) ?


 
Внук ©   (2002-05-31 15:00) [17]

MBo © (31.05.02 14:56)
>>setlength(s,$10000);
Именно об этом я и говорю :)



 
Игорь Шевченко ©   (2002-05-31 15:02) [18]

Внук © (31.05.02 14:58)

Я привел пример кода автора, работающего в моей среде Delphi.
D5/WinNT.

Он работает. Другое дело, что это кривой способ :-)

С уважением,


 
Kozhanov ©   (2002-05-31 15:02) [19]

>MBo
setlength(s,$10000); - а почему бы вообще всю память у машины не
отобрать ?
И ещё почему если код не корректный, то он РАБОТАЕТ ?


 
Внук ©   (2002-05-31 15:05) [20]

"И ещё почему если код не корректный, то он РАБОТАЕТ ?"
Ну а почему нельзя вылезти за пределы массива? Можно... До поры, до времени.


 
Kozhanov ©   (2002-05-31 15:08) [21]

>Внук
До какой поры и до какого времени ?



 
MBo ©   (2002-05-31 15:08) [22]

так тоже работает ;)
begin
s:=caption;
ptr:=pointer(s);

это же просто пояснение к AnsiString



 
Игорь Шевченко ©   (2002-05-31 15:12) [23]

Только сейчас поглядел, что в моем примере с record первое поле - лишнее.
Надо:

type
TmyCoolRecord = packed record
B : PString;
C : PString;
end;

Заело, думал, что массив с нуля начинается.

Внук © (31.05.02 15:05)
>Ну а почему нельзя вылезти за пределы массива? Можно... До поры, до времени

Откомпилируйте код с Range Check - ошибок не будет :-)
Там нет выхода за пределы массива. :-))




 
Kozhanov ©   (2002-05-31 15:13) [24]

Господа, посмотрите ещё раз вопрос !
Я же просил пояснить (кто сможет) почему код не работает
если заремить FillChar(A, SizeOf(A), 0), а вы начинаете говорить
что код вообще идиотский и всё такое. Это первое...Второе :
если код неправильный, то покажите мне ситуацию при которой он
рухнет, буду очень признателен за науку...



 
Внук ©   (2002-05-31 15:17) [25]

>>Игорь Шевченко © (31.05.02 15:02)
Извиняюсь, не заметил, что это тот же самый код :) У меня он тоже работает, но я продолжаю утвержать, что это некорректно.
А вот при закомментаренной FillChar и ShowMessage(PString(@A[1])^) (как Вы советовали) вылетает ошибка. Как же это объяснить?
По-моему, все прозрачно. Если я захочу произвольный участок памяти трактовать как AnsiString, неужели Delphi должна заботиться об автоматическом выделении памяти и сборке мусора ???


 
Игорь Шевченко ©   (2002-05-31 15:23) [26]

Внук © (31.05.02 15:17)

Все, теперь мы друг друга поняли :-)
Выражение PString(@A[1])^ заставляет компилятор трактовать выражение как String, если указатель равен нулю, то _LstrAsg прекрасно работает. В противном случае, он начинает интерпретировать тот мусор, который в стеке, как строку со всеми вытекающими.
Надо PString(@A[1]) := @строки, тогда уж.

Код у автора кривой вдвойне :-)))

С уважением,


 
Kozhanov ©   (2002-05-31 15:23) [27]

>Внук
"неужели Delphi должна заботиться об автоматическом выделении памяти и сборке мусора ???"
Твой вопрос закономерен и меня он тоже волнует.
Но самое странное что вся моя байда работает (!!!).
Если бы Делфи вываливалать и говорила что ты мол дурак, это
было бы понятно, а то...В общем не понятно, как же на самом деле
всё это работает и почему ?


 
Внук ©   (2002-05-31 15:25) [28]

>>Игорь Шевченко © (31.05.02 15:12)
Ну естественно, не будет, вылазим за пределы отведенной памяти, но не через обращение A[i], а через запись строки, это же разные вещи


 
SPeller ©   (2002-05-31 15:25) [29]

Да, похоже что никакого выхода за пределы массива тут нет. На своей 6-й сделал так:

procedure TForm1.Button1Click(Sender: TObject);
var a:array[1..8]of byte;
begin
//fillchar(a,8,0);
pstring(@a[1])^:="hello, buddy !";
label1.Caption:=pstring(@a[1])^;
//a[4]:=100;
label2.Caption:=pstring(@a[1])^;
end;

Оказывается, что в первых четырёх байтах массива хранится указатель на нормальную строку. Поэтому присвоение другого значения первым четырём байтам приведёт к ошибке при считывании label2.Caption:=pstring(@a[1])^;. Остальные байты можно изменять как угодно и на результат это никак не скажется. И FillChar тут ни причём.


 
MBo ©   (2002-05-31 15:27) [30]

посмотри в watch содержимое A
PString(@A[1])^ := "hello, buddy !";
Полагаю, если заполнено нулями, Delphi видит по этому адресу nil, считает, что это новая строка, в меру сил распределяет под нее память, записывая в А адрес. Если же там не nil, происходит обращение к этому мусорному адресу, вот и AV выскакивает


 
SPeller ©   (2002-05-31 15:28) [31]

Или попробуйте уменьшить размерность массива до трёх. тогда вообще ничего не выполнится.


 
Игорь Шевченко ©   (2002-05-31 15:29) [32]

MBo © (31.05.02 15:27)

Именно так оно и происходит. Так работает процедура _LStrAsg, которая вызывается этим оператором.

С уважением,


 
SPeller ©   (2002-05-31 15:30) [33]

А хотя выполнится..... :) Вот если до одного уменьшить, то ексепшн вылезет.


 
erik ©   (2002-05-31 15:32) [34]

Блин зачем спорить, что сложно посмотреть куда физически поподает строка!!! А она поподает в произвольную область и если эта область кемто используется тогда AV. Если неверишь, что нельзя писать куда непоподя то читай Help.


 
MBo ©   (2002-05-31 15:35) [35]

>Игорь Шевченко
Да,я пробежался отладчиком, исключение возникает после вызова NewAnsiString внутри LStrAsg


 
Kozhanov ©   (2002-05-31 15:48) [36]

Господа, я пришёл к выводу, что под строку надо явно выделять
память, но всё же интересно как ведёт себя Делфи, в смысле
почему работает...а кстати, если PString заменить на
PInteger = ^Integer и написать

PInteger(@A[1])^ := 100;
PInteger(@A[5])^ := -100;

то всё работает без проблем.


 
Внук ©   (2002-05-31 15:51) [37]

>>Игорь Шевченко © (31.05.02 15:29)
Действительно, автоматическое управление памятью под строки срабатывает (будь оно неладно), отсюда глюк.
Автору вопроса спасибо за науку :)


 
Игорь Шевченко ©   (2002-05-31 15:52) [38]

Integer работает без проблем. PShortString работает без проблем

Все равно, это неправильный способ. Правильный - описывать структуру данных (см. мои предложения)


 
Внук ©   (2002-05-31 15:54) [39]

>>Kozhanov © (31.05.02 15:48)
Да, я именно так и сделал.
Кстати, явно выделить память через SetLength опять же не получится по той же причине (если предварительно не занулить строку, но в этом случае память выделять уже не нужно - диалектика, однако ).


 
Kozhanov ©   (2002-05-31 15:56) [40]

>Внук
Видимо,хотя явно и нет переменной String, но Делфи всё равно
запускает свой механизм выделения памяти под String, но только
приходится обнулять массив...FillChar(A, SizeOf(A), 0)

В общем наверное, где-то так всё и работат...shit...


 
Внук ©   (2002-05-31 15:59) [41]

>>Kozhanov © (31.05.02 15:56)
Согласен. "...только приходится обнулять массив...FillChar(A, SizeOf(A), 0)...", чтобы она это начала делать с начала и правильно :)


 
Kozhanov ©   (2002-05-31 16:05) [42]

> Внук
Мда уж :)
А вообще я думаю это можно взять на вооружение.
Мне это нравиться, ничего не делаешь, а память всё равно
выделяется,хотя наверное стоит ещё поиграться с этим делом...


 
Kozhanov ©   (2002-05-31 16:23) [43]

> Игорь Шевченко
В твоей структуре - PString.
А как же использовать всё это для отражения массива, записи или
ещё круче...массива элемент, которого - запись ?


 
MBo ©   (2002-05-31 16:28) [44]

>Kozhanov
Не разъяснишь, какая конечная цель, что именно хочется сделать?


 
Kozhanov ©   (2002-05-31 16:37) [45]

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

простые структуры :
Integer, String, Byte и т.д.

сложные структуры :
записи и массивы (или и то и другое вместе)

Вот я тут пробую... пока ничего эффективного и красивого придумать немогу :(

Может есть мыслишки ?
Мне думается что это можно сделать через массив (динам-кий видимо) и через структуру, через которую можно будет узнать по какому смещению что лежит...

Если что можешь присоветовать (или на мысль натолкнуть)
буду очень признателен.


 
MBo ©   (2002-05-31 16:41) [46]

Я пока не очень понял, но часто в таких случаях удобно использовать pbytearray. Кстати, строки, как видишь, трудно отнести к простым структурам ;)


 
Kozhanov ©   (2002-05-31 16:47) [47]

> MBo
1. Я согласен, что проблемка не совсем тривиальная
2. pbytearray - это и есть указатель на массив байт
3. Про строки я понял... Хотя и не до конца.
4. Советовать не будите ???


 
MBo ©   (2002-05-31 16:51) [48]

Трудно советовать в видимо непростом вопросе, не осознав всей задачи ;(


 
Kozhanov ©   (2002-05-31 16:54) [49]

> MBo
Согласен (полностью).



Страницы: 1 2 вся ветка

Текущий архив: 2002.06.10;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.011 c
1-30888
Great DAN
2002-05-29 11:37
2002.06.10
Записи типа RECORD


1-30798
Kaldr
2002-05-31 11:25
2002.06.10
Speedbutton не поднимается


3-30683
ed_30
2002-05-17 15:26
2002.06.10
UpdateSQL


1-30805
Dummi
2002-05-31 08:45
2002.06.10
Преобразование типов


1-30796
allrussia
2002-05-31 04:48
2002.06.10
Как из исполняемого файла в RunTime вырвать кусок текста