· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.ASSEMBLER —› массив указателей

. 1 . 2 . >>

Посл.отвђт Сообщен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  ; восстанавливаем стек

. 1 . 2 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.084