Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
14-30995
Сатир
2002-05-07 21:38
2002.06.10
WinSocket


14-30968
VID
2002-05-02 01:41
2002.06.10
UBPFD: новое предложение


1-30900
Роман Мишин
2002-05-30 09:43
2002.06.10
печать шрифтов не установленных в системе


6-30935
SNTP beginner
2002-03-27 17:34
2002.06.10
Simple Network Time Protocol


14-30977
mimino
2002-05-06 22:00
2002.06.10
Поможет кто нибуть или нет?????????????????????????





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский