Форум: "Основная";
Текущий архив: 2002.06.10;
Скачать: [xml.tar.bz2];
ВнизКто внятно пояснит в чём проблема ? Найти похожие ветки
← →
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...
Страницы: 1 2 вся ветка
Форум: "Основная";
Текущий архив: 2002.06.10;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.005 c