| 
| 
 | Вопрос # 2 700/ вопрос решён / | 
 |  Здравствуйте, эксперты!Проблема такова. Имеется код (часть его в приложении). Функция определяет имеющиеся накопители и информацию о них. При выполнении программы выдается ошибка. Для верности сделала скрин. Посмотрите, пожалуйста. Я днями-ночами сижу над этим, может, уже просто очевидного не замечаю.
 Заранее благодарю.
 К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса) Приложение:Переключить в обычный режим   type  TDriveRec = packed record    Name: String;    DrType: String;    Sectors: DWord;    Bytes: DWord;    FreeClust: DWord;    TotalClust: DWord;    FreeSpace: Int64;    TotalSpace: Int64;end; type TDrives = Array of TDriveRec;  //.....................  function GetDrives (var Drive: TDrives; var count: byte): boolean; const DriveTypes: array[0..6] of String = ('Unknown', 'Error disk name', 'FDD', 'HDD',                                      'Remote', 'CD-ROM', 'RAM-DISK');var Drives_: DWord; dType: UINT; i: byte; Dr: Char; SectorsPerCluster: DWord; BytesPerSector: DWord; NumFreeClusters: DWord; TotalClusters: DWord; FreeSpace: Int64; TotalSpace: Int64;begin count:=1; Drives_ := GetLogicalDrives; for i := 0 to 25 do   if Boolean(Drives_ and (1 shl i)) then     begin       Dr := Chr(i + $41);        dType := GetDriveType(PChar(Dr + ':'));       Drive[count].DrType:= DriveTypes[dType];       GetDiskFreeSpace(PChar(Dr + ':'), SectorsPerCluster, BytesPerSector, NumFreeClusters,
TotalClusters);       FreeSpace:=DiskFree(Integer(Dr));       TotalSpace:=DiskSize(Integer(Dr));       Drive[count].Sectors:= SectorsPerCluster;       Drive[count].Bytes:= BytesPerSector;       Drive[count].FreeClust:= NumFreeClusters;       Drive[count].TotalClust:= TotalClusters;       Drive[count].FreeSpace:= FreeSpace;       Drive[count].TotalSpace:= TotalSpace;      Inc(count);     endend;     var  Drive: TDrives; count: byte;// ............ begin // .......  GetDrives(Drive, count); // ....... end;
|  |   Вопрос задала: Insomnia (статус: Посетитель)Вопрос отправлен: 29 апреля 2009, 08:48
 Состояние вопроса: решён, ответов: 2.
 |  Ответ #1. Отвечает эксперт: Вадим К Здравствуйте, Insomnia!Типичная проблема - массив объявлен, а место под него не выделено. В данном случае "виноват" массив Drive. Исправить можно двумя способами.
 а)
 переписать объявление массива так
 
 type TDrives = Array[0..25] of TDriveRec;
 
 или явно выделить место под массив - над строкой GetDrives(Drive, count); дописать строку SetLength(Drive, 26);
 
|  | Ответ отправил: Вадим К (статус: Академик)Время отправки: 29 апреля 2009, 09:42
 Оценка за ответ: 5
 |  Ответ #2. Отвечает эксперт: Amidamaru Здравствуйте, Insomnia!Конечно будет ошибка выскакивать. У вас же Drive это динамический массив, значит прежде чем его использовать, нужно задать ему длинну. Например SetLength(Drive,26).
 
 У вас скорее всего нужно вставить это тут:
 
|  | Ответ отправил: Amidamaru (статус: 4-ый класс)Время отправки: 29 апреля 2009, 09:42
 Оценка за ответ: 5
 |  
 Мини-форум вопросаВсего сообщений: 4; последнее сообщение — 29 апреля 2009, 18:11; участников в обсуждении: 3. 
|   | Amidamaru (статус: 4-ый класс), 29 апреля 2009, 09:44 [#1]:Забыл дописать. После окончания ипользования динамического массива нужно освободить занимаемую им память: 
 SetLength(Drive,0);
 
 И ещё одно, индексы в динамичемских массивах начинаются с 0. Т.е. Drive[0] - первый элемент. Поэтому используйте Drive[count-1]
 |  
|   | Вадим К (статус: Академик), 29 апреля 2009, 10:18 [#2]:Дополняю свой ответ. Индексы.. либо используйте count:=0; вместо count:=1; , либо придется заменить все [count] на [count-1]
 В моем ответе я выделяю "заведомо достаточное место" - дисков может быть больше 26 в системе, но не букв дисков.
 Amidamaru предлагает довыделять память по мере надобности. Вызывать функцию SetLength при малых размерах массива достаточно не ресурсоемко.  Но вот уже при 10-20 начинает сказываться.
 Это для нас код Setlengt(a, length(a)+1) - довыделить места на один элемент выглядит просто, а делфи генерирует весьма большой код. Где то так
 //выделить место под новый массив
 //скопировать в него старый
 //удалить старый.
 Понятно, что это можно оптимизировать (и оно оптимизируется) - например выделятся сразу пачками по 16 элементов. Но...
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Amidamaru (статус: 4-ый класс), 29 апреля 2009, 10:29 [#3]:Да, можно оптимизировать. Выделить память сразу под весь массив, а в конце процедуры GetDrivers вставить строчку SetLength(Drive,count); |  
|   | Insomnia (статус: Посетитель), 29 апреля 2009, 18:11 [#4]:Спасибо, ребята! Все исправила, все работает   |  31 января 2011, 19:36: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5) Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |