Форум программистов, компьютерный форум, киберфорум
Assembler для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/21: Рейтинг темы: голосов - 21, средняя оценка - 4.57
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
1

Поиск всех вхождений любого символа второй строки в первой (реализация strpbrk)

28.10.2017, 17:04. Показов 4165. Ответов 14
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Заданы две строки. Поиск всех вхождений любого символа второй строки в первой.
Реализовала так:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
section '.data' data readable writeable      
 
MESSAGE db "Enter string %d",13,10,0
RESULT_1 db "RESULT is %d",13,10,0
s1 db 250 dup(0)
s2 db 250 dup(0)
pos db 250 dup(0)
LEN dd 0
LEN2 dd 0
 
section '.code' code readable executable     
 
start:                                       
        
 
        ccall [printf], MESSAGE, dword 1
        ccall [gets], s1
        ccall [printf], MESSAGE, dword 2
        ccall [gets], s2
        
 
        ccall [strlen],s1
        mov [LEN], eax
        ccall [strlen], s2
        mov [LEN2], eax
 
        push  ds
        pop   es
        cld
        xor    bx,bx
        lea ebx,[s2]
        push ebx
        mov esi, ebx
 
        mov  edx,[LEN]   
L1:
        lodsb             
        mov   ecx,[LEN2]
        lea eax,[s1]
        mov edi, eax
        repe scasb    ;сканируем 1-ую строку  
        jz  equal ;такой символ есть в 1-ой строке     
        mov eax,esi
        pop ebx
        sub eax,ebx
        dec eax
        mov byte ptr pos[ebx],ax ;   ??????
        inc ebx
equal:
        dec  edx
        jnz L1
        ccall [printf], RESULT_1, ebx
        jmp exit
 
        
exit:
        ccall [getchar]
        stdcall [ExitProcess], 0
Ошибку выдает в строчке,где я пытаюсь записать в массив pos позицию непредставленного символа. Подскажите, что делать?
Миниатюры
Поиск всех вхождений любого символа второй строки в первой (реализация strpbrk)   Поиск всех вхождений любого символа второй строки в первой (реализация strpbrk)  
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.10.2017, 17:04
Ответы с готовыми решениями:

Ввести две символьных строки. Выполнить поиск второй строки в первой и вывести номер позиции первой строки, с которой вторая строка содер-жится в ней
Ввести две символьных строки. Выполнить поиск второй строки в первой и вывести номер позиции первой...

Ввести две символьных строки. Выполнить поиск второй строки в первой и вывести номер позиции, с которой вторая строка содержится в первой.
Ввести две символьных строки. Выполнить поиск второй строки в первой и вывести номер позиции, с...

Заданы 2 строки, состоящие из слов, разделенных пробелами. Приписать три символа второй строки к первой
Заданы 2 строки, состоящие из слов, разделенных пробелами. Приписать три символа второй строки к...

Определить, совпадают ли первые два символа первой строки с двумя последними символами второй строки?
Помогите решить задачку... Определить совпадаеют ли первые два символа первой строки с двумя...

14
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
28.10.2017, 21:26 2
Поясните на каком-нибудь примере, что вы пытаетесь реализовать.
А также, зачем при публикации кода добавлять скрины этого же кода?
0
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
29.10.2017, 07:37  [ТС] 3
Пытаюсь в массив pos запомнить индексы встречающихся в строке 1 символов, которые есть в строке 2. Нашла команду mov byte ptr pos[bx],al ; но как для своей программы это переделать, не очень понимаю. Строка 1: 23489 Строка 2:123 pos: 01 . Про скрины учту, спасибо.
0
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
29.10.2017, 08:11 4
Вы объявили массив pos, как массив байт
Assembler
47
mov byte ptr pos[ebx],ax ;   ??????
Но регистр ax размером 2 байта, поэтому в строке 47 ошибка.

А решение задачи действительно создание массива pos или что-то другое? Что должно выводится на экран в качестве результата?

Добавлено через 17 минут
Просто я пытаюсь сообразить, что служит ответом на задачу о поиске.
0
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
29.10.2017, 08:33  [ТС] 5
На экран должны выводиться индексы символов из строки 1, которые встречаются в строке 2. То есть при предыдущем примере 01 выведется
0
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
29.10.2017, 08:54 6
Т.е. в псевдокоде
Код
  for (i=0; i<length(s1); i++)
  {
    if s1[i] присутствует в s2
      printf("%d", i)
  }
Тогда удобнее использовать базово индексную адресацию (кажется так называется)
Покажу идею
Assembler
1
2
3
4
5
6
    lea ebx, [s1]
    mov esi, 0
For:
    mov al, [ebx+esi]
    ............
    inc esi
И без сохранения сразу печатать esi. Вместо esi можно использовать edi.

Добавлено через 5 минут
Я напутал с номерами строк, в которых проверяется вхождение - s1 и s2.

Добавлено через 1 минуту
Нет, не перепутал.
0
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
30.10.2017, 18:00  [ТС] 7
Вот к чему пришла, только не получается загружать каждый символ из 2 строки и сравнивать его с символами в 1-ой
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
MESSAGE db "Enter string %d",13,10,0
RESULT_1 db "RESULT is %d",13,10,0
RESULT_2 db "values not found",13,10,0
s1 db 250 dup(0)
s2 db 250 dup(0)
LEN dd 0
LEN2 dd 0
 
section '.code' code readable executable     
 
start:                                       
 
        ccall [printf], MESSAGE, dword 1     ;ввод первой строки
        ccall [gets], s1
        ccall [printf], MESSAGE, dword 2      ;ввод второй строки
        ccall [gets], s2
        
 
        ccall [strlen],s1
        mov [LEN], eax
        ccall [strlen], s2
        mov [LEN2], eax
 
        push  ds
        pop   es
        cld
        xor    bx,bx
    lea edx,[s2]
        push edx
        mov edi, 0
        lea ebx,[s1]
        push ebx
        mov esi, 0  
L1:
        lodsb 
    mov dl,[искомый символ] ;символ из строки 2           
        mov  al,[ebx+esi]
    std         ;обратный обход
    repne scasb     ;повторить пока символ в строке не совпадет с искомым
    cld
    jne  NOT_FOUND      ;переход к выводу сообщения no solution, если искомый символ не найден
    sub esi, ARR        ;узнаем позицию найденного символа
    inc esi         ;инкрементируем, так как esi указывает на следующий символ
    ccall [printf], RESULT_1, esi         ;вывод сообщения если искомый символ найден
    jmp exit
NOT_FOUND:
    ccall [printf], RESULT_2          ;вывод сообщения если искомый символ не найден
    
exit:
        ccall [getchar]
        stdcall [ExitProcess], 0
0
2 / 2 / 1
Регистрация: 30.10.2017
Сообщений: 8
30.10.2017, 19:54 8
А зачем в программировании под Win32 такие странные манипуляции с сегментными регистрами?
Assembler
1
2
push  ds
pop   es
Добавлено через 8 минут
Намек:
Команда scasb принимает в edi адрес строки, в которой ищет байт, загруженный в регистр al. edi (указатель на строку) увеличивается/уменьшается автоматически.
Команда SCAS производит сканирование строки с целью поиска заданного значения. Искомое значение необходимо предварительно поместить в AL/AX/EAX в зависимости от размера искомого элемента. SCAS вычитает элемент строки приемника из AL/AX/EAX и устанавливает флаги AF, SF, ZF, PF, CF, OF в соответствии с результатом. Если сравниваемые элементы равны, то устанавливается флаг ZF, иначе он сбрасывается в ноль. Единственный операнд — элемент сканируемой строки, указанный при помощи DI/EDI:
SCAS BYTE [ES: DI]
SCASW
SCAS DWORD [ES:EDI]
1
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
30.10.2017, 22:14 9
ОвчинниВики, мне легче не в FASM, а в MASM32. Также, для ввода и вывода я использую WinAPI, а не mvcrt - при чтении строки ReadConsole в конец добавляются символы перевода строки, которые приходится удалять.
Но, думаю, что алгоритм будет виден.

Алгоритм тот же, что и ранее приведён на псевдокоде.
При использовании wsprintf портятся какие-то регистры, поэтому в цикле, когда значение регистров важно, вызов WinAPI обрамлён pushad/popad

Действительно, в линейном режиме адресации нет нужды настраивать регистр es.
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
.486
.model flat, stdcall
option casemap :none
 
        include d:\masm32\include\windows.inc
 
        include d:\masm32\include\user32.inc
        include d:\masm32\include\kernel32.inc
        include d:\masm32\include\masm32.inc
 
        includelib d:\masm32\lib\user32.lib
        includelib d:\masm32\lib\kernel32.lib
        includelib d:\masm32\lib\masm32.lib
.data
 
        Prompt          db      "Enter the string %d",13,10,0
        RESULT_1        db      "RESULT is %d",13,10,0
        RESULT_2        db      "values not found",13,10,0
        aszPressEnter   db      0Dh, 0Ah, "Press ENTER to exit", 0
        hConsoleOutput  HANDLE  ?
        hConsoleInput   HANDLE  ?
 
        s1              db      250 dup(0)
        s2              db      250 dup(0)
        LEN1            dd      0
        LEN2            dd      0
 
        Buffer          db      250 dup(?)
        BufLen          dd      ?
.code
 
start:
 
        ; получение описателей ввода и вывода консоли
        invoke  GetStdHandle,   STD_INPUT_HANDLE
        mov     hConsoleInput,  eax
 
        invoke  GetStdHandle,   STD_OUTPUT_HANDLE
        mov     hConsoleOutput, eax
 
        invoke  ClearScreen
 
        ;ввод 1-й строки
        invoke  wsprintf, ADDR Buffer, ADDR Prompt, dword ptr 1
        mov     BufLen,         eax
        invoke  WriteConsole, hConsoleOutput,\
                ADDR Buffer, BufLen, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput,\
                ADDR s1, LENGTHOF s1, ADDR LEN1, NULL
        sub     [LEN1], 2               ;удаляем из введённой строки
        lea     esi,    [s1]            ;символы перевода строки 0Dh, 0Ah
        add     esi,    [LEN1]
        mov     [esi],  byte ptr 0
        ;ввод 2-й строки
        invoke  wsprintf, ADDR Buffer, ADDR Prompt, dword ptr 2
        mov     BufLen,         eax
        invoke  WriteConsole, hConsoleOutput,\
                ADDR Buffer, BufLen, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput,\
                ADDR s2, LENGTHOF s2, ADDR LEN2, NULL
        sub     [LEN2], 2               ;удаляем из введённой строки
        lea     esi,    [s2]            ;символы перевода строки 0Dh, 0Ah
        add     esi,    [LEN2]
        mov     [esi],  byte ptr 0
 
        ;обработка строк
        mov     edx,    0               ;Count=0 - счётчик найденных символов
        lea     ebx,    [s1]            ;for (i=0; i<length(s1); i++)
        mov     esi,    0
        mov     ecx,    [LEN1]
        cld
        @For:                           ;{
 
                push    ecx
                mov     al,     [ebx+esi]; if s1[i] присутствует в s2
                lea     edi,    [s2]    ;  {
                mov     ecx,    [LEN2]
                repne   scasb
                jnz     @Next
                pushad                  ;    printf("%d", i)
                invoke  wsprintf, ADDR Buffer, ADDR RESULT_1, esi
                mov     BufLen,         eax
                invoke  WriteConsole, hConsoleOutput,\
                        ADDR Buffer, BufLen, ADDR BufLen, NULL
                popad
                inc     edx             ;    Count++
                                        ;  }
        @Next:
                inc     esi
                pop     ecx
        loop    @For                    ;}
 
        test    edx,    edx             ;if (!Count)
        jnz     @Found
                                        ;  printf("values not found");
        invoke  WriteConsole, hConsoleOutput,\
                ADDR RESULT_2, LENGTHOF RESULT_2, ADDR BufLen, NULL
        @Found:
 
        ;ожидание нажатия ENTER
        invoke  WriteConsole, hConsoleOutput, ADDR aszPressEnter,\
                LENGTHOF aszPressEnter - 1, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput, ADDR Buffer,\
                LENGTHOF Buffer, ADDR BufLen, NULL
 
        invoke  ExitProcess, 0
 
end start
0
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
12.11.2017, 19:16  [ТС] 10
Переделала код под FASM
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
MESSAGE db "Enter string %d",13,10,0
RESULT_1 db "RESULT is %d",13,10,0
RESULT_2 db "Not found",13,10,0
s1 db 250 dup(0)
s2 db 250 dup(0)
LEN1 dd 0
LEN2 dd 0
 
section '.code' code readable executable     
 
start:                                       
        
 
        
 
    lea     esi,    [s2]    
    add    esi,    [LEN2]   
            
        ;обработка строк
        mov     edx,    0               ;Count=0 - счётчик найденных символов
        lea     ebx,    [s1]            ;for (i=0; i<length(s1); i++)
        mov     esi,    0
        mov     ecx,    [LEN1]
        cld
        @For:                           ;{
 
                push    ecx
                mov     al,     [ebx+esi]; if s1[i] присутствует в s2
                lea     edi,    [s2]    ;  {
                mov     ecx,    [LEN2]
                repne   scasb
                jnz     @Next
                ccall [printf], RESULT_1 ,esi
                inc     edx             ;    Count++
                                        ;  }
        @Next:
                inc     esi
                pop     ecx
        loop    @For                    ;}
 
        test    edx,    edx             ;if (!Count)
        jnz     @Found
        call [printf], RESULT_2
        @Found:
    
        ccall [getchar]
        stdcall [ExitProcess], 0
Теперь пытаюсь сделать отдельную процедуру на С, ниже пример, а ещё ниже, то, что я пыталась сделать со своим кодом
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
include 'include\win32a.inc'
 
format MS COFF
 
public my_proc1 as '_my_proc1@8'
 
section '.text' code readable executable
 
my_proc1:                             ; процедура stdcall без использования макросов
    push ebp                          ; пролог
    mov ebp, esp
    
    label .string dword at ebp+8      ; первый аргумент
    label .position dword at ebp+12   ; второй аргумент
    
    sub esp, 8
    label .loc1 dword at ebp-4
    label .loc2 dword at ebp-8
 
    push ebx                          ; сохраняем ebx в стек
    mov ebx, [.string]
    add ebx, [.position]              ; получаем позицию нужного символа в строке...
    mov byte [ebx], '#'               ; ... и заменяем его
    pop ebx                           ; восстанавливаем ebx из стека
    
    mov esp, ebp                      ; эпилог
    pop ebp
    ret 8                             ; указываем размер данных очищаемых на стеке
Моя реализация
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
include 'include\win32a.inc'
 
format MS COFF
 
public my_proc1 as '_my_proc1@8'
 
section '.text' code readable executable
 
my_proc1:                             ; процедура stdcall без использования макросов
    push ebp                          ; пролог
    mov ebp, esp        ;фиксируем новый кадр
    
    label .string1 dbyte at ebp+8     ; первый аргумент
    label .string2 dbyte at ebp+8     ; второй аргумент
    
    sub esp, 8
    sub esp, 8
    label .loc1 dword at ebp-4
    label .loc2 dword at ebp-8
 
    ;что-то нужно написать
    ret 8                             ; указываем размер данных очищаемых на стеке
0
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
12.11.2017, 19:37 11
А какая структура программы:
1. На С ввод, вызов асм процедуры
2. Асм процедура - что-то ищет - что делать с результатом поиска?
0
Эксперт Hardware
Эксперт Hardware
6160 / 2397 / 398
Регистрация: 29.07.2014
Сообщений: 3,143
Записей в блоге: 4
13.11.2017, 08:23 12
Цитата Сообщение от ОвчинниВики Посмотреть сообщение
Переделала код под FASM
Я бы сделал так..
Дескрипторы клавы и монитора всегда постоянны: 3 и 7 соответственно.
Чтобы не вычислять длину ввода, можно сразу использовать API, которые возвращают эту длину... например тот-же ReadConsole или по-проще _LREAD\WRITE (R\W из файла), где вместо дескриптора файла просто подставить клаву.

Когда заканчиваешь ввод по ENTER, fn. LREAD вставляет в буфер(0Dh,0Ah) и чтобы SCASB не пропустил последний символ в строке, нужно убрать только(0Ah). Пример подобной реализации поиска первого символа подстроки в строке на FASM'e, может выглядеть так:

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
;FASM-code..
;Dev handles: Std_In   = 3 (клава)
;             Std_Out  = 7 (монитор)
;-----------------------------------
format    PE Console
include  'win32ax.inc'
include  'api/kernel32.inc'
entry     start
 
section '.data' data readable writable
mes       db   'String 1: '
len       =    $ - mes
err       db   10,'ERROR! No symbol..'
len1      =    $ - err
 
size      dd   0                  ; длина строки
str1      db   128 dup(0)         ; буферы для строк
str2      db   128 dup(0)         ; ^^^^
offset    dd   128*4 dup(0)       ; ..и для найденных позиций
 
section '.code' code readable executable
start:
;---// Запрос и вводим строку
        invoke  _lwrite, 7, mes, len     ; экран - вывод LEN-символов
        invoke  _lread,  3, str1, 128    ; клава - макс.126 в буфер 'str1'
 
        mov      [size],eax              ; запомнить длину ввода!
        dec      [size]                  ;   ..без маркера конца(0Ah)
        inc      byte[mes+7]             ; меняем мессагу на 2..
 
;---// Запрос и вводим под/строку
        invoke  _lwrite, 7, mes, len     ;
        invoke  _lread,  3, str2, 128    ;
 
;---// Настраиваемся на поиск вхождений
        xor      ah,ah                   ; AH будет счётчик найденных
        mov      edi,str1                ; где искать
        mov      al,byte[str2]           ; что искать (первый симовол под\строки)
        mov      ecx,[size]              ; длина строки для поиска
        mov      ebx,offset              ; куда сохранять адрес позиции
 
;---// Ищем кол-во вхождений
@@:     repne    scasb                   ;
        or       ecx,ecx                 ; конец строки?
        jz       @f                      ; да - на нижнюю метку
        inc      ah                      ; нет - счётчик +1
        dec      edi                     ;  ..(EDI проскачил позицию)
        mov      [ebx],edi               ; запомнить её!
        inc      edi                     ;
        add      ebx,4                   ; смещаемся в буфере позиций
        jmp      @b                      ; продолжить поиск..
 
;---// Выводим результ на экран
@@:     or       ah,ah                   ; есть чё выводить ???
        jnz      @prn                    ; да.
        invoke  _lwrite, 7, err, len1    ; иначе: ERROR!
        jmp      @exit                   ;    ..и на выход.
 
@prn:   mov      cl,ah                   ; кол-во найденных позиций в ECX
        mov      esi,offset              ; где они валяются
@@:     lodsd                            ; берём очередную позицию в EAX
        push     ecx  esi                ; PRINTF портит регистры.
        cinvoke  printf, <10,"  Offset: 0x%08X",0>,eax     ; выводим позицию на экран!
        pop      esi  ecx
        loop     @b
 
@exit:  invoke  _lread, 3, str2, 3       ;
        invoke   ExitProcess, 0          ; выход из программы!
;--------------------------------------------------------------
section '.idata' import data readable    ; импорт API..
library  kernel32, 'kernel32.dll',\
         msvcrt, 'msvcrt.dll'
 
import  msvcrt,\
        printf, 'printf'
Миниатюры
Поиск всех вхождений любого символа второй строки в первой (реализация strpbrk)  
0
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
13.11.2017, 08:35 13
R71MT, у ТС всё интереснее - теперь это не программа на asm, а программа на C со вставками на асме или с раздельной компиляцией (один файл C, другой файл asm и нужно их вместе собрать в одну программу).

Поэтому встаёт вопрос о взаимодействии между частями одной программы. На мой взгляд, процедура, находящая индексы в строке не должна их самостоятельно выводить, а лишь передавать вышестоящей программе, которая и будет распоряжаться этими данными.

Добавлено через 25 секунд
Хотя в учебных целях можно и выводить сразу.
0
2 / 2 / 3
Регистрация: 04.03.2017
Сообщений: 101
17.11.2017, 16:47  [ТС] 14
Принцип в том, что нужно создать библиотеку на asm. Будет cpp, в котором будет вызываться функция
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "conio.h"
#include "string.h"
 
//Описание внешних функций
extern "C"
{
    int __stdcall   STRPBRK(char *str1, int len1, char *str2, int len2);
}
 
using namespace std;
void main(void)
{
    setlocale(0,"Rus");
    // Вызов поиска в 1-й строке 2-й
    char str1[100], str2[100];
    int pos;
    cout<<"\nВведите первую строку: ";
    cin>>str1;
    cout<<"\nВведите вторую строку: ";
    cin>>str2;
    pos = STRPBRK (str1, strlen(str1), str2, strlen(str2));
    if (pos==0) cout<<"\nСимвола нет\n";
    else cout<<"\nСимвол есть\n";
 
    _getch();
}
А затем уже в отдельном файле -> lib.asm будет код функции на Ассемблер
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
.386
.model flat
.code
 
;вычитание си соглашение
 
 
;Поиск символов в строке stdcall
_STRPBRK@16 proc
    str1 equ dword ptr [ebp+8]
    len1 equ dword ptr [ebp+12]
    str2 equ dword ptr [ebp+16]
    len2 equ dword ptr [ebp+20]
    
    push ebp            ;Пролог
    mov ebp,esp
 
                        ;операция
    MOV ECX, len2   ;Загрузка количества символов в подстроке
    JCXZ    NOTFOUND    ;Пустая строка не является частью строк
    MOV ECX, len1   ;Загрузка количества символов в строке
    JCXZ    NOTFOUND    ;В пустой строке не может быть подстрок
    MOV ESI, str2   ;Адрес основной строки в источник
    CLD         ;Установка флага направления по возрастанию
    MOV ECX, len1   ;Инициализация счетчика
    MOV EBX, ECX
    MOV EDI, str1   ;Адрес подстроки в приемник
 
    STRPBRK:
    MOV EDI, str1   ;Адрес подстроки в приемник
    LODSB           ;Загрузка первого байта в AL из источника DS:[SI]
    REPNE   SCASB       ;Сравнение символов в AL и приемника ES:[DI]
    JE  FOUND       ;Если первый символ из TEXT1 есть в строке
    MOV ECX, EBX
;   DEC     EBX
    LOOP    STRPBRK ;Цикл продолжаем, если имеются еще не проверенные       символы в 1-й строке
 
    NOTFOUND:   
    MOV EAX, 0
    JMP EXIT
 
    FOUND:  
    MOV EDI, str2
    SUB ESI,EDI
    MOV EAX, ESI
    
    EXIT:
    mov esp,ebp         ;Эпилог
    pop ebp
    ret 16  
 
_STRPBRK@16 endp
 
public _STRPBRK@16
end
Только как сделать, чтобы символы выводились на экран, которые есть и в строке 1, и в строке 2? Подскажите, пожалуйста)

Добавлено через 19 минут
Это реализация функции STRPBRK, которая находит и выводит позицию первого вхождения любого символа второй строки в первой, я пытаюсь несколько изменить.

Добавлено через 1 час 14 минут
Вроде переделала, но что-то странное выдает
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
.386
.model flat
.code
 
;вычитание си соглашение
 
 
;Поиск символов в строке stdcall
_STRPBRK@16 proc
    Str1 equ dword ptr [ebp+8]
    Len1 equ dword ptr [ebp+12]
    Str2 equ dword ptr [ebp+16]
    Len2 equ dword ptr [ebp+20]
    
    Push ebp            ;Пролог
    Mov ebp,esp
 
                        ;операция
    MOV ECX, len2   ;Загрузка количества символов в подстроке
    JCXZ    NOTFOUND    ;Пустая строка не является частью строк
    MOV ECX, len1   ;Загрузка количества символов в строке
    JCXZ    NOTFOUND    ;В пустой строке не может быть подстрок
 
    Mov     edx,    0 
    MOV ESI, str2   ;Адрес основной строки в источник
    add    esi,  len2
    Mov     ebx, str1 
    mov     esi,    0
    mov     ecx,  len1
    CLD         ;Установка флага направления по возрастанию
  
@FOR:
    PUSH    ECX
    mov     al,     [ebx+esi]; if s1[i] присутствует в s2
    MOV     EDI,   STR2    ; Адрес подстроки в приемник {
    MOV     ECX,   LEN2
    REPNE   SCASB       ;Сравнение символов в AL и приемника ES:[DI]
    JNZ     @NEXT   ;Если первый символ из TEXT1 есть в строке 
    MOV EAX, ESI ; вывод в дальнейшем позиции, то есть esi
    INC     EDX             ;    Count++
@NEXT:
    INC     ESI
    POP     ECX
    LOOP @FOR       
 
    TEST EDX, EDX             ;IF (!COUNT)
    JNZ EXIT   
EXIT:
    MOV ESP,EBP         ;ЭПИЛОГ
    POP EBP
    RET 16  
 
NOTFOUND:   
    MOV EAX, 0
    JMP EXIT
 
_STRPBRK@16 ENDP
 
PUBLIC _STRPBRK@16
END
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "string.h"
 
//Описание внешних функций
extern "C"
{
    int __stdcall   STRPBRK(char *str1, int len1, char *str2, int len2);
}
 
using namespace std;
void main(void)
{
    setlocale(0,"Rus");
    // Вызов поиска в 1-й строке 2-й
    char str1[250], str2[250];
    int pos;
    cout<<"\nВведите первую строку: ";
    cin>>str1;
    cout<<"\nВведите вторую строку: ";
    cin>>str2;
    pos = STRPBRK (str1, strlen(str1), str2, strlen(str2));
    if (pos!=0) cout<<pos;
    else cout<<"\nСимвола нет\n";
 
    _getch();
}
0
Модератор
Эксперт по электронике
8532 / 4385 / 1650
Регистрация: 01.02.2015
Сообщений: 13,625
Записей в блоге: 9
19.11.2017, 22:07 15
У вас что-то непродуманно с алгоритмом.

Опишите словами, что должна делать функция.

Как я понимаю, что на вход подаются две строки.
На выходе - первая позиция (от 0) в строке 1 символа, который имеется в строке 2. Т.е. строка 2 это список интересующих символов. И мы проверяем наличие в строке 1 этих символов.

Тогда сам алгоритм процедуры должен быть иным.

У меня нет Visual Studio, поэтому сделаю в masm32. А дальше вы самостоятельно.

Добавлено через 1 час 11 минут
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
.486
.model flat, stdcall
option casemap :none
 
        include d:\masm32\include\windows.inc
 
        include d:\masm32\include\user32.inc
        include d:\masm32\include\kernel32.inc
        include d:\masm32\include\masm32.inc
 
        includelib d:\masm32\lib\user32.lib
        includelib d:\masm32\lib\kernel32.lib
        includelib d:\masm32\lib\masm32.lib
.data
 
        Prompt          db      "Enter the string %d",13,10,0
        RESULT_1        db      "RESULT is %d",13,10,0
        RESULT_2        db      "values not found",13,10,0
        aszPressEnter   db      0Dh, 0Ah, "Press ENTER to exit", 0
        hConsoleOutput  HANDLE  ?
        hConsoleInput   HANDLE  ?
 
        s1              db      250 dup(0)
        s2              db      250 dup(0)
        LEN1            dd      0
        LEN2            dd      0
 
        Pos             dd      ?
 
        Buffer          db      250 dup(?)
        BufLen          dd      ?
.code
 
MySTRPBRK       proc    pStr1:DWORD, pStr2:DWORD
        LOCAL   dwLen2:DWORD
        push    ecx
        push    esi
        push    edi
        pushfd
 
        ;для последующих цепочечных команд определяем длину второй строки
        mov     ecx,    -1
        mov     edi,    [pStr2]
        mov     eax,    0
        repne   scasb
        jnz     @@NotFound
        mov     eax,    0-2
        sub     eax,    ecx
        mov     [dwLen2],       eax
        ;обработка строк
        mov     esi,    [pStr1]         ;i=0
        cld
        jmp     @@Next                  ;while (*pStr1[i]) do
        @@While:                        ;{
                                        ;  if s1[i] присутствует в s2
                lea     edi,    [pStr2] ;  {
                mov     ecx,    [dwLen2]
                repne   scasb
                jnz     @@Next
                mov     eax,    esi     ;       return i
                dec     eax
                jmp     @@Exit
                                        ;  }
        @@Next:
                lodsb
                or      al,     al
        jnz     @@While                 ;}
 
@@NotFound:
        mov     eax,    0
@@Exit:
 
        popfd
        pop     edi
        pop     esi
        pop     ecx
        ret
MySTRPBRK       endp
 
start   proc
 
        ; получение описателей ввода и вывода консоли
        invoke  GetStdHandle,   STD_INPUT_HANDLE
        mov     hConsoleInput,  eax
 
        invoke  GetStdHandle,   STD_OUTPUT_HANDLE
        mov     hConsoleOutput, eax
 
        invoke  ClearScreen
 
        ;ввод 1-й строки
        invoke  wsprintf, ADDR Buffer, ADDR Prompt, dword ptr 1
        mov     BufLen,         eax
        invoke  WriteConsole, hConsoleOutput,\
                ADDR Buffer, BufLen, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput,\
                ADDR s1, LENGTHOF s1, ADDR LEN1, NULL
        sub     [LEN1], 2               ;удаляем из введённой строки
        lea     esi,    [s1]            ;символы перевода строки 0Dh, 0Ah
        add     esi,    [LEN1]
        mov     [esi],  byte ptr 0
        ;ввод 2-й строки
        invoke  wsprintf, ADDR Buffer, ADDR Prompt, dword ptr 2
        mov     BufLen,         eax
        invoke  WriteConsole, hConsoleOutput,\
                ADDR Buffer, BufLen, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput,\
                ADDR s2, LENGTHOF s2, ADDR LEN2, NULL
        sub     [LEN2], 2               ;удаляем из введённой строки
        lea     esi,    [s2]            ;символы перевода строки 0Dh, 0Ah
        add     esi,    [LEN2]
        mov     [esi],  byte ptr 0
 
        invoke  MySTRPBRK, ADDR s1, ADDR s2
 
        mov     [Pos],  eax
        mov     esi,    eax
        mov     al,     [esi]
        ;ожидание нажатия ENTER
        invoke  WriteConsole, hConsoleOutput, ADDR aszPressEnter,\
                LENGTHOF aszPressEnter - 1, ADDR BufLen, NULL
        invoke  ReadConsole, hConsoleInput, ADDR Buffer,\
                LENGTHOF Buffer, ADDR BufLen, NULL
 
        invoke  ExitProcess, 0
start   endp
 
end start
Добавлено через 5 минут
Только учтите - Pos это не номер позиции (индекс), а указатель. Чтобы распечатать символ из строки 1 нужно разыменовывать указатель.
Что-то вроде
C
1
2
3
char * pos;
..................
if (!pos) cout<<*pos
Я путаюсь в типах и конструкциях C/C++ - исправьте если что.
0
19.11.2017, 22:07
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.11.2017, 22:07
Помогаю со студенческими работами здесь

Определить местоположение символа первой строки, который первым совпал с одним из символов второй строки.
Заданы 2 строки, состоящие из слов, разделенных пробелами. Определить местоположение символа первой...

Строки. Определить местоположение символа первой строки, который первым совпал с одним из символов второй
Заданы 2 строки, состоящие из слов, разделенных пробелами. Определить местоположение символа первой...

Заданы 2 строки, состоящие из слов, разделенных пробелами. Приписать три символа второй строки к первой
Заданы 2 строки, состоящие из слов, разделенных пробелами. Приписать три символа второй строки к...

Определить местоположение символа первой строки, который первым не совпал с одним из символов второй строки
помогите написать прогу &quot;Заданы 2 строки, состоящие из слов, разделенных пробелами. Определить...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru