Форум: "Основная";
Текущий архив: 2004.01.23;
Скачать: [xml.tar.bz2];
ВнизДинамические массивы Найти похожие ветки
← →
alexnmsk (2004-01-12 16:07) [0]Можно ли использовать записи в динамическом массиве?
Выпадает ошибка при использовании динамического массива
type
TPerson = record
Index:LongInt;
Name, SecondName, SurName,
Post, Address, HomePhone, AddInfo:ShortString;
end;
Var NoteBook: array of TPerson;
Если в программе выполняется код
l:=Length(NoteBook)+1;
SetLength(NoteBook,l);
NoteBook[l].Index:=IDX;
NoteBook[l].Name:="";
NoteBook[l].SecondName:="";
NoteBook[l].SurName:="";
NoteBook[l].Post:="";
NoteBook[l].Address:="";
NoteBook[l].HomePhone:="";
NoteBook[l].AddInfo:="";
то при ЗАКРЫТИИ ФОРМЫ выпадает ошибка, если код не выполнять или массив - статический то ошибки нет. SetLength(Notebook,0) или NoteBook:=nil не помогают.
← →
alex_*** (2004-01-12 16:13) [1]SetLength(NoteBook,sizeof(TPerson)*NUM);
← →
alex_*** (2004-01-12 16:15) [2]sorry... rollback... ->SetLength(NoteBook,NUM);
← →
alex_*** (2004-01-12 16:16) [3]индексы начинаются с 0 в дин. массивах
← →
GLFox (2004-01-12 16:17) [4]Попробуй вместо ShortString использовать String (и еще вроде должен быть {$H+}, хотя по-умолчанию так и есть).
← →
GLFox (2004-01-12 16:19) [5]Да! И не следует забывать что индексы считаются от нуля и заканчиваются на Length(DynArray)-1.
← →
AKul (2004-01-12 16:23) [6]l:=Length(NoteBook);
SetLength(NoteBook,l+1);
NoteBook[l].Index:=IDX;
....
....
← →
alexnmsk (2004-01-12 16:28) [7]Еще кое что обнаружил. Поле Index в моем случае - это индекс элемента из TreeView.
IDX:=(Source as TTreeView).Selected.AbsoluteIndex;
NoteBook[l].Index:=IDX;
Стоит мне убрать поле Index из записи и ошибка исчезает
← →
alex_*** (2004-01-12 16:34) [8]см. [6]
← →
AKul (2004-01-12 16:37) [9]Если не помогает, то дай больше информации, например, какая именно ошибка, в какой строке...
← →
alexnmsk (2004-01-12 16:39) [10]Наконец то дошло!! Списибо!
← →
Юрий Зотов (2004-01-12 17:05) [11]> alexnmsk
Явная ошибка индексации - выход за диапазон индексов массива.
Предположим, длина массива равна 7 - то есть, он содержит 7 элементов с индексами 0..6. Теперь выполняем строку:
l:=Length(NoteBook)+1;
и получаем l=8.
Далее идет строка
SetLength(NoteBook,l);
после которой длина массива стала равной 8 - теперь он содержит 8 элементов с индексами 0..7.
И дальше идет строка:
NoteBook[l].Index:=IDX;
в которой мы пытаемся обратиться к несуществующему 8-му элементу массива (ведь l=8). Вот и ошибка.
Если бы у Вас была включена опция $R+ (Range check), то ошибка обнаружилась бы сразу же в этом месте кода. Но по умолчанию эта опция выключена, поэтому эдесь происходит просто порча содержимого памяти, следующей непосредственно за массивом. Последствия этого могут быть любыми (и Вам еще повезло, что ошибка все же вылетела, гораздо хуже было бы, если бы программа работала вроде без явных ошибок, но неверно)
Не нужна здесь вообще никакая переменная l. Вот нормальный код:
SetLength(NoteBook, Length(NoteBook) + 1);
with NoteBook[High(NoteBook)] do
begin
Index := IDX;
Name := "";
SecondName := "";
SurName := "";
Post := "";
Address := "";
HomePhone := "";
AddInfo := "";
end;
Причем если бы строки у Вас были длинными, а не ShortString, то присвоения пустых строк, думаю, тоже не потребовалось бы (было бы достаточно присвоить только Index, а все строковые поля и так оказались бы пустыми - об этом должен позаботиться компилятор). Кстати, и количество потребляемой памяти при этом должно уменьшиться - накладные расходы составили бы по 13 байт на каждую строку, а в Вашем варианте из отведенных под строку 256 байт в среднем реально вряд ли используется больше 15, а остальные 240 просто пропадают зря. Итого - полтора лишних килобайта на каждый элемент массива.
← →
AKul (2004-01-12 17:21) [12]to Юрий Зотов ©:
Ключ $R+, по идее, не будет работь с динамическими массивами
← →
Anatoly Podgoretsky (2004-01-12 17:27) [13]Вроде должен работать, длина есть - хранится, поэтому сравнить индекс не представляет сложности.
← →
alex_*** (2004-01-12 17:29) [14]to [13]
так на момент компилляции размер массива неизвестен же еще?
← →
Юрий Зотов (2004-01-12 17:37) [15]> alex_*** © (12.01.04 17:29) [14]
Вы полагаете, что выход значения за допустимый диапазон контролируется на стадии компиляции?
А зачем он тогда вообще такой нужен?
← →
alex_*** (2004-01-12 17:41) [16]Нда... действительно.. не подумал.
← →
AKul (2004-01-12 17:48) [17]to Юрий Зотов ©:
На стадии компиляции проверяются значение индексов, заданные константами.
При {$R+} перед кодом обращения к элементу статического массива компилятор "вставляет" свой код на проверку правильности индекса, диапазон изменения которого он "знает".
А динамический массив для Delphi - это указатель, и об размере памяти, выделенной под него функцией SetLength(Size) Delphi не может даже догадаться.
← →
Anatoly Podgoretsky (2004-01-12 17:52) [18]У тебя очень оригинальные представления о динамических массивах и очень далекие от истины. Динамический массив по структуре почти не отличается от длинных строк.
← →
alex_*** (2004-01-12 17:57) [19]Range checking:
...
...
Note: Long strings are not range checked.
Мне помнится что я где-то таки встречал что для дин. массивов не проверяются границы.
← →
AKul (2004-01-12 18:04) [20]to Anatoly Podgoretsky:
Ну на счет "У тебя очень оригинальные представления о динамических массивах и очень далекие от истины" ты погарячился (или докажи обратное).
Кстати, длинная строка - это тоже указатель на структуру.
В любом случае сравни откомпилированный код с ключем R+ и R-(как со статическими, так и с динамическими массивами)
← →
Юрий Зотов (2004-01-12 21:43) [21]> AKul © (12.01.04 17:48) [17]
Во-первых, благодарю за разъяснения. Правда, все это мне давным-давно и очень хорошо известно, но все равно спасибо.
Во-вторых, несколько вопросов к Вам, с Вашего позволения.
1. То, что динамический массив есть указатель - это известно еще со времен Delphi 4, где они впервые и появились. Но указатель НА ЧТО?
Подсказка - где хранятся длина динамического массива и счетчик ссылок на него? Еще подсказка - в окне CPU перейдите по адресу массива и посмотрите, что находится по смещениям -4 и -8.
2. Зачем Delphi вообще о чем-то "догадываться", когда в run-time программа работает уже без всякой Delphi, а в ПРОГРАММЕ вся нужная информация есть? (см. п.1).
3. Что мешает компилятору вставить в ПРОГРАММУ код сравнения индекса запрашиваемого элемента с фактическим текущим диапазоном индексов массива? (что он при R+ и делает).
4. Что мешало Вам, прежде чем вступать в непонятный спор и толковать прописные истины, выполнить вот такой простенький код:
{$R+}
procedure TForm1.Button1Click(Sender: TObject);
var
A: array of integer;
begin
SetLength(A, 2);
A[3] := 0
end;
и в результате вполне успешно получить то самое "Range check error"? А потом заменить {R+} на {R-}, выполнить еще раз и на этот раз уже НЕ получить никаких сообщений. И в итоге прийти к очевидному выводу, что опция {$R+} вполне работает, что бы Вы там ни рассуждали.
5. Убедились, что, говоря "об размере памяти, выделенной под него функцией SetLength(Size) Delphi не может даже догадаться", Вы сказали, извините, двойную чушь? Двойную - это потому что говорили о Delphi, которая здесь уже совершенно ни при чем (раз) и еще потому что не надо "догадываться" о том, что и без догадок известно совершенно точно (два).
6. Будем спорить, или как?
==========================
P.S.
Вынужден повторить слова Анатолия: "у тебя очень оригинальные представления о динамических массивах и очень далекие от истины".
P.P.S.
> Кстати, длинная строка - это тоже указатель на структуру
Сколько лет прошло со времен появления длинных строк в Delphi? Вот столько же лет эта "новость" и известна.
← →
Anatoly Podgoretsky (2004-01-12 22:11) [22]alex_*** © (12.01.04 17:57) [19]
Ты во превых ты вырвал из контекста, не приведя первую часть
all array and string-indexing expressions are verified as being within the defined bounds,
во вторых ты не понял к чему относится приведенная фраза, а относится она к проверке пределов во время компиляции, поскольку это просто не возможно, а возможно только во время выполнения.
← →
Anatoly Podgoretsky (2004-01-12 22:14) [23]Да забыл самое главно, совсем не важно как ты понял, но Дельфи то у тебя есть, что мешало проверить свои предположения набрав допустим такой простой код, как этот
var
S: string;
a: array of Byte;
begin
S := "123456789 ";
if S[20] = " " then ;
SetLength(a,2);
if a[20] = 0 then ;
end;
← →
AKul (2004-01-13 10:04) [24]to Юрий Зотов ©:
Маленькое вступление:
До недавнего времени я сам считал, что ключ {$R+} работает с любыми массивами, но это не так (возможно это ошибка разрабочиков компилятора). Я сам на этом попался. Подробнее см. в ответе на 4 вопрос.
Во-первых, я никому детально не пытался разъяснить структуру представления динамических массивов и строк - для этого есть специальные форумы.
Вот ответы на Ваши вопросы:
1. На этот вопрос Вы ответили сами.
Кстати, я занимаюсь реверсированием программ не первый год, так что не думайте, что Вы сказали здесь что-то новое.
2. Если Вы прочитаете внимательно сообщение, которое начинается со слов "На стадии компиляции", то думаю поймете, что речь идет о компиляции программы и подстановке проверочного кода.
3. Вы спрашивали: "Что мешает компилятору вставить в ПРОГРАММУ код сравнения индекса запрашиваемого элемента с фактическим текущим диапазоном индексов массива? (что он при R+ и делает)."
Отвечу: на счет статических массивов - я так и написал (см. [17]), а на счет динамических читайте ниже.
4. Согласен, этот код прокатит.
НО ЕСТЬ МАЛЕНЬКОЕ "НО": в заголовке форума был пример динамического массива СТРУКТУР с индексированием по ПЕРЕМЕННОЙ.
Если Вы проверите вот такой код:
{$R+}
SetLength(NoteBook,6);
l:=7;
NoteBook[l].Index:=10;
NoteBook[l].Name:="";
NoteBook[l].SecondName:="";
NoteBook[l].SurName:="";
NoteBook[l].Post:="";
NoteBook[l].Address:="";
NoteBook[l].HomePhone:="";
NoteBook[l].AddInfo:="";
то думаю все поймете. (я продизассемблировал код как с включенной проверкой, так и без нее - никаких отличий нет).
5. На счет двойной чуши см. ответ на вопрос 2.
А на счет того что во время рантайма размер динамического массива известен тут я согласен - и это не отрицал.
А вот на стадии компиляции - Delphi знает только место (если можно так выразиться, так как оно тоже будет выделено во время рантайма), где будет храниться размер массива, но НЕ САМ РАЗМЕР. - Вот это я и написал!.
6. Я спорю до конца, пока не докажу свою точку зрения!
==========================
P.S. Внимательнее читайте собщения, а потом уже делайте подобные выводы.
P.P.S. Если хотите похвастаться своими знаниями, то это делается не таким образом.
to Anatoly Podgoretsky ©:
Согласен такой код пройдет, этого я и не отрицал (разве что выразился где не так), но как я уже писал:
в заголовке форума был пример динамического массива СТРУКТУР с индексированием по ПЕРЕМЕННОЙ.
Если Вы проверите вот такой код:
{$R+}
SetLength(NoteBook,6);
l:=7;
NoteBook[l].Index:=10;
NoteBook[l].Name:="";
NoteBook[l].SecondName:="";
NoteBook[l].SurName:="";
NoteBook[l].Post:="";
NoteBook[l].Address:="";
NoteBook[l].HomePhone:="";
NoteBook[l].AddInfo:="";
то думаю все поймете. (я продизассемблировал код как с включенной проверкой, так и без нее - никаких отличий нет).
← →
AKul (2004-01-13 10:31) [25]to Anatoly Podgoretsky © [22]:
ты написал: "относится она к проверке пределов во время компиляции, поскольку это просто не возможно, а возможно только во время выполнения".
Во-первых, я писал: "перед кодом обращения к элементу статического массива компилятор "вставляет" свой КОД на проверку", а как ты понимаешь (я надеюсь) код выполняется только во время рантайма!
Во-вторых, если ты считаешь, что во время компиляции нельзя проверить что-то типа:
var A[0..9] of integer;
....
A[10]:=0;
Тогда извини, здесь можно поспорить о твоем понимании процесса компиляции близком к истине.
← →
Anatoly Podgoretsky (2004-01-13 10:38) [26]Интересно как ты это проверишь для динамических структур?
← →
AKul (2004-01-13 10:51) [27]Я думаю за пропущенное ":array" в "var A[0..9] of integer;" меня критиковать не будут, так как здесь я акцентирую внимание на диапазоне массива а не на синтаксисе его определения.
var A:array [0..9] of integer;
← →
AKul (2004-01-13 10:57) [28]to Anatoly Podgoretsky ©:
Пожайлуста, читай внимательнее, повторяю: я писал "перед кодом обращения к элементу СТАТИЧЕСКОГО массива компилятор "вставляет" свой код на проверку",
и:
var A:array [0..9] of integer;// А так обявляется СТАТИЧЕСКИЙ массив
....
A[10]:=0;
Так что здесь я не вижу, где хотя бы раз упоминался динамический массив!
← →
Юрий Зотов (2004-01-13 13:53) [29]> AKul © (13.01.04 10:04) [24]
Знаете, я бы, пожалуй, отнесся более серьезно, если бы не это:
> Я спорю до конца, пока не докажу свою точку зрения!
Что ж, как говорится, флаг Вам в руки и барабан на шею. Желаю успехов в благородном деле всенепременного доказательства собственной правоты.
Но без моего участия. Не горю, знаете ли.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.01.23;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.007 c