Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

Форум поддержки пользователей. LibreOffice, Apache OpenOffice, OpenOffice.org

28 Май 2017, 11:46 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Здесь можно поблагодарить участников форума Улыбка
 
   Начало   Помощь Поиск Войти Регистрация    задать вопрос  
Страниц: 1   Вниз
  Печать  
Автор Тема: Стек  (Прочитано 842 раз)
0 Пользователей и 1 Гость смотрят эту тему.
karpo518
Новичок
*
Offline Offline

Сообщений: 42


« Стартовое сообщение: 17 Январь 2017, 10:21 »

Добрый день. Потребовался функционал стека для массива строк. Реализовать самому не позволяет незнание некоторых моментов языка. К примеру, когда нужно и вернуть значение, и удалить его из массива(при извлечении из стека), не вижу другого способа реализации, кроме как использование указателей. Но для меня до сих пор остается загадкой, существуют ли в версии VB для OO указатели и как с ними работать. Если у кого-нибудь завалялась реализация стека, поделитесь, пожалуйста.
Записан

Linux Mint 18 (64 bit),  LibreOffice 5.1.6.2
mikekaganski
Старожил
****
Offline Offline

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 425


« Ответ #1: 17 Январь 2017, 10:28 »

Redim Preserve?
https://help.libreoffice.org/Basic/ReDim_Statement_Runtime/ru
https://wiki.openoffice.org/wiki/Documentation/BASIC_Guide/Arrays
« Последнее редактирование: 17 Январь 2017, 10:31 от mikekaganski » Записан

С уважением,
Михаил Каганский
karpo518
Новичок
*
Offline Offline

Сообщений: 42


« Ответ #2: 23 Январь 2017, 12:13 »

mikekaganski, спасибо за ответ. В данный момент мне непонятно, как функция, извлекающая из стека значение, может одновременно вернуть это значение и удалить его из массива. Если извлечённое значение будет возвращено самой функцией, то как из функции получить доступ к массиву, в котором хранятся данные, чтобы удалить извлекаемое значение?
Записан

Linux Mint 18 (64 bit),  LibreOffice 5.1.6.2
mikekaganski
Старожил
****
Offline Offline

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 425


« Ответ #3: 23 Январь 2017, 12:28 »

Код:
sub push(stack, val)
  dim lo as integer, hi as integer
  lo = LBound(stack)
  hi = UBound(stack)
  ReDim Preserve stack(lo to hi+1)
  stack(hi+1) = val
end sub

function pop(stack) as variant
  dim lo as integer, hi as integer
  lo = LBound(stack)
  hi = UBound(stack)
  pop = stack(hi)
  ReDim Preserve stack(lo to hi-1)
end function


sub tst
  dim stack(0) As Integer
  for i = 0 to 5
    push(stack, i)
  next

  for i = 0 to 5
   j = pop(stack)
   print j
  next 
 
end sub
Записан

С уважением,
Михаил Каганский
JohnSUN
Капитана в тот день называли на "ты"
Гуру
*******
Online Online

Пол: Мужской
Расположение: Киев
Сообщений: 2 264


Помогаю людям и компьютерам понимать друг друга


WWW
« Ответ #4: 23 Январь 2017, 12:39 »

+
Только я бы в pop добавил проверку на hi>=lo... Ну, на случай, если стек уже пуст
И не уверен, что ReDim подходит для удаления единственного (последнего) элемента.
Возможно, просто присвоить пустой Array() было бы проще (но это может изменить типизированный массив на Variant).
« Последнее редактирование: 23 Январь 2017, 12:43 от JohnSUN » Записан

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне
mikekaganski
Старожил
****
Offline Offline

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 425


« Ответ #5: 23 Январь 2017, 12:55 »

В данном случае подходит.
Я специально не делал проверку, поскольку мне больше импонирует перехват ошибки с помощью On Error ...
В стеке изначально выделен защитный первый элемент, который позволит успешно вызывать pop для всех push, но вызовет "Inadmissible value or data type. Index out of defined range." для лишнего.
Записан

С уважением,
Михаил Каганский
JohnSUN
Капитана в тот день называли на "ты"
Гуру
*******
Online Online

Пол: Мужской
Расположение: Киев
Сообщений: 2 264


Помогаю людям и компьютерам понимать друг друга


WWW
« Ответ #6: 23 Январь 2017, 13:10 »

Я имел в виду нечто вроде такого


* ReDim пустой стек.png (12.59 Кб, 541x263 - просмотрено 10 раз.)
Записан

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне
mikekaganski
Старожил
****
Offline Offline

Пол: Мужской
Расположение: Хабаровск -> Москва
Сообщений: 425


« Ответ #7: 23 Январь 2017, 13:16 »

Улыбка Именно.
Я ни в коем случае не спорю, что Ваша твоя (не сочти за фамильярность - использую это местоимение как знак глубочайшего уважения, зная твоё к этому отношение) трактовка верна.

Просто в реальном коде у меня это было бы обрамлено в On Error Goto Handler, поскольку для меня (любителя C++ и структурной обработки ошибок) факт вызова лишнего pop - это признак ошибки в коде, а ошибку надо (мне надо Улыбка ) обрабатывать отдельно... Улыбка
Записан

С уважением,
Михаил Каганский
JohnSUN
Капитана в тот день называли на "ты"
Гуру
*******
Online Online

Пол: Мужской
Расположение: Киев
Сообщений: 2 264


Помогаю людям и компьютерам понимать друг друга


WWW
« Ответ #8: 23 Январь 2017, 13:40 »

А я в свою очередь не спорю с твоим решением - я же уже плюсанул!  Всё хорошо

Просто недавно пришлось пободаться именно с ситуацией, когда функция должна была возвращать массив, но для некоторых данных результата просто не было. Возвращать Nothing и анализировать результат на IsEmpty/IsNull было скучно, выдумывать способ бросить исключение (а потом обрабатывать его в On Error) - ещё скучнее.

Взял на вооружение приём из Standard-Tools-UCB-ReadDirectories
Код:
If CurIndex > -1 Then
ReDim Preserve sFileArray(CurIndex,1) as String
Else
ReDim sFileArray() as String
End If
Просто и понятно... А вызывающая процедура как крутила цикл от LBound до UBound, так и крутит - ни дополнительных проверок не надо, ни обработки ошибок...
Записан

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне
karpo518
Новичок
*
Offline Offline

Сообщений: 42


« Ответ #9: 30 Январь 2017, 13:18 »

Спасибо за ответы. JohnSUN, я не использую обработку исключений. Покажите, пожалуйста, полный вариант кода с учетом вашего совета по дополнительной проверке параметра.
Также смущает 2 момента:

1. pop - function, а push - sub. Это сделано, чтобы в push была доступен для изменения массив stack? Если это так, то нет ли другого способа изменить массив? Не хотелось бы для внутренних процедур использовать оператор sub.

2. функция push не возвращает значение, а должна, как мне кажется, возвращать, например, новый размер стека.

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

Linux Mint 18 (64 bit),  LibreOffice 5.1.6.2
JohnSUN
Капитана в тот день называли на "ты"
Гуру
*******
Online Online

Пол: Мужской
Расположение: Киев
Сообщений: 2 264


Помогаю людям и компьютерам понимать друг друга


WWW
« Ответ #10: 30 Январь 2017, 14:33 »

Покажите, пожалуйста, полный вариант кода с учетом вашего совета по дополнительной проверке параметра.
Думаю, как-то так:
Код:
REM  *****  BASIC  *****
Option Explicit
Option Base  0

Rem Глобальное объявление массива для стека позволит не указывать
Rem его в качестве параметров функций push и pop
Dim str_stack() As String

Function push(val As String) As Long
Dim lo As Integer, hi As Integer
lo = LBound(str_stack)
hi = UBound(str_stack)+1
ReDim Preserve str_stack(lo to hi)
str_stack(hi) = val
push = hi - lo + 1
End Function

Function pop(Optional elemCount As Long) As Variant
Dim lo As Integer, hi As Integer
lo = LBound(str_stack)
hi = UBound(str_stack)
If Not IsMissing(elemCount) Then elemCount = 0
If lo = hi Then ' Сейчас стек лишится последнего элемента
pop = str_stack(hi)
ReDim str_stack() As String ' Теперь LBound(str_stack)>UBound(str_stack) - массив пуст
ElseIf lo > hi Then ' Стек уже пуст
pop = empty ' Нужно вернуть что-то, что скажет, что стек пуст,
' но не станет вызывать ошибку выполнения. Empty будет трактоваться как string "", а Null вызовет ошибку
Else
pop = str_stack(hi)
ReDim Preserve str_stack(lo to hi-1)
If Not IsMissing(elemCount) Then elemCount = hi - lo
EndIf
End Function

Sub tst
Dim i As Long, j As Long
Dim s As String
For i = 0 To 4
s = "Элемент " + i
Print "После добавления '" + s + "' размер стека " + push(s)
Next

s = pop(j)
Print "Снят верхний '" + s + "', осталось " + j + " элементов"
While j > 0 
Print "Снят '" + pop(j) + "'"
Wend

s = pop(j)
Print "Попытка чтения из стека c " + j + " элементами возвращает '" + pop() + "', что в виде строки выглядит как '" + s + "'"
End Sub
Также смущает 2 момента:
1. pop - function, а push - sub. Это сделано, чтобы в push была доступен для изменения массив stack? Если это так, то нет ли другого способа изменить массив?
Сделал функцией
Не хотелось бы для внутренних процедур использовать оператор sub.
Причина?
2. функция push не возвращает значение, а должна, как мне кажется, возвращать, например, новый размер стека.
Должна - значит вернет. Но тогда вроде как pop получится слишком "молчаливым"... Пусть он тоже рассказывает об оставшемся количестве элементов
Записан

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне
karpo518
Новичок
*
Offline Offline

Сообщений: 42


« Ответ #11: 31 Январь 2017, 14:28 »

JohnSUN, cпасибо за развернутый ответ.

Цитата:
Не хотелось бы для внутренних процедур использовать оператор sub. Причина?

Как я понял в sub запихивают самодостаточные модули для назначения кнопкам и прочего публичного использования. Всё остальное, включая функционал для внутреннего использования в макросе, следует засовывать в функции. Поправьте, если не прав.
Записан

Linux Mint 18 (64 bit),  LibreOffice 5.1.6.2
JohnSUN
Капитана в тот день называли на "ты"
Гуру
*******
Online Online

Пол: Мужской
Расположение: Киев
Сообщений: 2 264


Помогаю людям и компьютерам понимать друг друга


WWW
« Ответ #12: 2 Февраль 2017, 15:09 »

Извини, что долго не отвечал - старался подобрать формулировки, которые бы не очень сильно обидели того человека, который внушил тебе такое видение. Ответ получался или слишком лаконичным ("Нет, это не так"), или слишком длинным (и нецензурным).

Начнем с того, что в функцию тоже "запихивают самодостаточные" фрагменты кода. И даже используют эти функции в ячейках электронных таблиц. (Не "модули" - давай договоримся, что "модуль" это такая закладочка в редакторе макросов, в нем обычно может быть много и функций, и процедур).

С точки зрения компьютера разницы между функциями и процедурами нет. Например, процедуру можно считать функцией, которая возвращает специальное значение void, от которого программисту никакого особого проку нет.

Обычно функция что-то делает и возвращает одно (если программист не захотел сделать иначе) значение. Когда функция закончит работу, это значение будет лежать в переменной с точно таким же именем, что и имя самой вызванной функции. Перед завершением каждой функции отдельным оператором так и записывают <имя_функции>=<то-то_или_то-то>.
Процедура точно так же, оператор за оператором выполняет предусмотренный для нее код и может ничего не возвращать (ты такой вариант назвал "для назначения кнопкам"), может вернуть одно или несколько значений. Но процедура, в отличие от функции, их возвращает не в собственном имени, а через параметры.
Возьмем, например, старую задачу: получить по дню, месяцу, году дату и - обратная задача - имея дату, получить день, месяц и год.
В первом случае возвращаемое значение одно - значит пишем функцию. Во втором случае - возвращаемых значений много. Значит нужно написать процедуру с четырьмя параметрами: через первый параметр передадим значение даты, а в переменных, которые указали вторым-третьим-четвертым параметрами получим результаты.
Можно было поступить иначе. В первом случае написать процедуру с четырьмя параметрами - через три передать день-месяц-год, а в четвертом получить дату. А во втором случае - написать три разных функции, каждая из которых будет возвращать одно значение день, месяц или год. Можно было сделать и так. Но пришлось бы больше программисту писать, а компьютеру выполнять.

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

Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне
Страниц: 1   Вверх
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!