|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Июл 12, 2004 01:02:30 Всем привет. Люди, помогите, а то совсем замучался :( Пытаюсь сделать запись и чтение из файла построчно, с записью строк в массив, чтобы иметь удобный доступ к адресам строк в цикле. Действую в такой последовательности: 1.hFile=CreateFile 2.nSize=GetFileSize 3.ArrAddr=выделяю память под данные 4.invoke ReadFile, hFile, dword ptr[ArrAddr], nSize, ADDR RetVal - имею массив байт, считанный из файла. Здесь начинаются проблемы с созданием массива указателей на адреса строк, усугубляемые тем, что в массив строк могут добавляться в произвольных позициях новые строки. Массив строк - двумерный. Скажем, 9 списков(фиксировано), в каждом от 0 до 10 строк. Подскажите какую-нибудь идею по упорядочению всего этого месива, а то я совсем в ступоре :( Пожалуйста. |
|
|
Дата: Июл 12, 2004 01:24:29 Не очень вник, но вот для динамических изменений данных, точнее для их хранения, можешь попробывать 2-х(1-х) связанные списки. Отдельная proc разбивает на строки и строет список указателей, а другая proc удаляет/измен./доб. |
|
|
Дата: Июл 12, 2004 09:00:30 Не уверен, что связанный список подойдет. Я бы использовал массив индексных указателей. Гемор, конечно, тот еще, но если вникнуть - легко. :) Где-то у меня была лаба по "структурам и алгоритмам", там я как раз реализовывал эту пакость. Могу дать. |
|
|
Дата: Июл 12, 2004 09:20:01 Мдяя.. Посмотрел свою лабу.. Давай я лучше объясню на пальцах. Вобщем, тебе понадобятся два куска памяти. Один кусок будет содержать дворды, а другой - собственно данные. Как ты, возможно, догадался, дворды - это адреса начала новой строки в большом массиве. Для упрощения будем считать, что строки твои оканчиваются 0 (asciiz). Таким образом, для обращения к следующей строке тебе надо последовательно брать указатели из массива и работать с той строкой. Если тебе надо отсортировать/добавить/удалить строку, тебе не надо трогать большой массив - только указатели. Просто переставляешь их в нужном порядке и все. Сложности: Если надо редактировать строку и при этом она станет больше первоначальной, придется делать хитрость. Редактируемую строку обычно редактируют, скопировав в какой-нить буфер. Так что задача сводится к добавлению в хвост массива строк новой строки и правки указателя на редактируемую строку. Троку по старому адресу можно забивать нулями. Забивать нулями ее нужно вот зачем: при добавлении новой строки можно считать ее длину и искать в массиве строк дырку, подходящую под такую длину. Это сэкономит расход памяти, но понизит быстродействие. Удаление - просто убиваем указатель и строку затыкаем нулями. При убивании указателя придется сдвинуть все последующие указатели на его место, но проблем вызвать не должно. Вобще, я этот алгоритм использую везде, где только можно. На асме он реализуется гораздо проще, чем на сях. Хотя, возможно, многие со мной не согласятся. Просто я на сях это делал в виде шаблона класса, а это заметно все усложняет. :) Короче, если что неясно - спрашивайте. |
|
|
Дата: Июл 12, 2004 09:23:29 Млин, написал так, что сам не понял.. :) Тяжкий день - понедельник.. |
|
|
Дата: Июл 12, 2004 15:45:24 PavPS Связанные списки-немного не то, они только усложняют дело n0p Да, примерно так я сначала и делал (с небольшими отличиями- элементы в массиве указателей не передвигал, просто записывал в него нули, а при чтении считывал, если в указателе не ноль). Только вот подумал, что может как-то попроще это можно реализовать. |
|
|
Дата: Июл 12, 2004 18:19:26 cresta Если я правильно понял, то строки могут добавляться в середину массива и размер строк & всего текста не велик? Может быть подойдёт что-то вроде такого варианта: dd 18,'Это строка 18 байт',18 dd 20,'А это строка 20 байт',20 ..... Если доступ к адресам строк нужно получать именно в цикле, то одно лишнее сложение не помешает, а от указателей можно совсем избавится (поскольку с ними проблемы). Предложенный вариант одинаково хорошо подходит для просмотра в 2х направлениях. Вариаций тут может быть несколько, например строки не обязаны располагаться строго одна за другой (возможны промежутки). Можно хранить относительные смещения не только для каждой строки, но и для групп строк (поскольку массив 2мерный) |
|
|
Дата: Июл 12, 2004 19:29:55 S_T_A_S_ Да, в этом что-то есть. Можно взять фиксированно по 256 байт на строку(в строках - пути к файлам), и не париться с указателями и смещениями отдельных строк, тогда адрес каждой строки = адрес первой строки+256*переменная цикла. Размер памяти особенно не волнует, 256*90=23040 байт - величина приемлимая. |
|
|
Дата: Июл 12, 2004 22:58:15 cresta Память всегда должна волновать. Это ассемблер. Здесь все имеет значение. Когда мне важен результат - я пишу на С++ с полным CRT. Когда мне важен процесс - я пишу на асме. Вариант Стаса мне нравится. Что-то в нем есть. Мой вариант больше из высокого уровня, да и использовал я его для задач, где по-другому можно, но будет очень сложно. |
|
|
Дата: Июл 12, 2004 23:32:41 Можно так: .DATA stroka1 db "одна строка",0 stroka2 db "ещё одна строка",0 stroka3 db "самая длиннннннннннннная строкаааааа",0 .DATA? spisok1 dd ? ; . . . spisok9 dd ? .CODE ; 1. Создаём массив списков строк ; ------------------------------- ; *** Этот код можно организовать в цикле invoke ST_Init,10 ; макс. 10 строк в каждом списке mov spisok1,eax ; . . . invoke ST_Init,10 ; макс. 10 строк в каждом списке mov spisok9,eax ; *** ; 2. Заполняем списки ; ------------------- invoke ST_Dup,spisok1,OFFSET stroka1 invoke ST_Dup,spisok1,OFFSET stroka2 invoke ST_Dup,spisok1,OFFSET stroka3 ; . . . ; 3. Удаляем массив списков ; ------------------------- invoke ST_Free,spisok1 ; . . . invoke ST_Free,spisok9 В аттаче код используемых функций + функции поиска/удаления строк. 1997857532__strtable.rar |
|
|
Дата: Июл 13, 2004 00:44:04 n0p >Память всегда должна волновать Согласен, но я не настолько знаком с ассемблером, чтобы сразу всё предусматривать. Если речь о результате, можно и на VB быстренько всё сделать. Просто я пытаюсь написать первую программу на ассемблере, вернее переделать то что делал на PowerBasic. Как запущу каркас, тогда и оптимизировать буду. Quantum Спасибо за пример, буду разбираться |
|
|
Дата: Июл 13, 2004 02:13:16 · Поправил: cresta Quantum Тут несколько вопросов по ST_Init PROC из аттача возникло, можно ли это объяснить ST_Init PROC uses edi maxStrings:DWORD
mov eax,maxStrings
test eax,eax ; --------------- ---- ----
jle @error ; Array of size
shl eax,2 ; pointers used
add eax,8 ; --------------- ---- ----
push eax ; EAX = maxStrings * 4 + 4 + 4
invoke GetProcessHeap
push 0 (?1)
push eax
call HeapAlloc
test eax,eax
jz @error
push eax
xchg edi,eax
mov ecx,maxStrings
mov [edi],ecx ; store "size"
add edi,4
xor eax,eax
stosd ; store "used" (?2)
rep stosd ; clear the whole buffer (?3)
pop eax
@@: ret
@error:
xor eax,eax
jmp @B
ST_Init ENDP
Вопрос 1: Второй параметр для вызова HeapAlloc должен быть HEAP_NO_SERIALIZE = &H1 или HEAP_ZERO_MEMORY = &H8. Почему делается push 0, а не push 1 или push 8 ? Вопрос 2: Что есть "used" ? Вопрос 3: Для чего делать clear the whole buffer если есть HEAP_ZERO_MEMORY ? И напоследок дурной вопрос:PROC uses edi - для чего указывается, что задействован регистр edi ? Значит edi при входе в процедуру должен сохраняться и по возвращению восстанавливаться- я так понял, это верно? |
|
|
Дата: Июл 13, 2004 02:38:13 2. Возможно used - это количество использованных байт в куче (Очень похоже на то). 3. Для меня это тоже оказалось загадкой. 4. Именно так. |
|
|
Дата: Июл 13, 2004 05:23:58 cresta 1. Да, лучше заменить на HEAP_ZERO_MEMORY. jekyll 2. Возможно used - это количество использованных байт в куче (Очень похоже на то). Количество задействованных (не null) указателей в куче. 3. Для меня это тоже оказалось загадкой. Для наглядности :-) Если серьёзно, то я просто забыл про zero memory. |
|
|
Дата: Июл 13, 2004 06:22:07 cresta > Можно взять фиксированно по 256 байт на строку(в строках - пути к файлам), и не париться с указателями и смещениями отдельных строк, тогда адрес каждой строки = адрес первой строки+256*переменная цикла. imho, в данном случае, так будет лучше (и проще) всего. Начало массива можно выровнять по границе 256 байт (хотя это не обязательно) Переменую цикла можно организовать, например, в регистре BH. Так избавимся от умножения, и доступ к следующей строке будет: INC BH. Так даже можно обойтись регистром EBX сразу для 2х целей: для указателя на начало массива и для счётчика, вроде этого:
push ebx ; локальная переменная = адрес начала массива
@@: ;; здесь обрабатываем строку
;; предполагается, что ebx не изменяется
inc bh
pop eax
push eax
add ah, Number_of_Elements
cmp bh, ah
jc @b
pop eax ; восстанавливаем стек |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.084 |