10 - Pętla For … Next


Tematem tej lekcji będą pętlę, dzięki którym można łatwo zautomatyzować wielokrotne wykonywanie identycznej czynności w kodzie, takiej jak np. wyświetlanie wartości w kolejnych wierszach arkusza.

Podstawowe informacje o pętlach

W przykładach zamieszczonych w początkowych lekcjach kursu pojawiło się makro printujące w arkuszu kolejne potęgi poszczególnych liczb. Makro to przedstawiało się następująco:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Sub wyswietlajPotegi(liczba As Byte, numerKolumny As Byte)
    Dim potega As Long

    potega = 1
    Worksheets("Arkusz1").Cells(1, numerKolumny) = potega

    potega = potega * liczba
    Worksheets("Arkusz1").Cells(2, numerKolumny) = potega

    potega = potega * liczba
    Worksheets("Arkusz1").Cells(3, numerKolumny) = potega

    potega = potega * liczba
    Worksheets("Arkusz1").Cells(4, numerKolumny) = potega

    potega = potega * liczba
    Worksheets("Arkusz1").Cells(5, numerKolumny) = potega

End Sub

Za wyświetlanie każdej kolejnej potęgi odpowiedzialna była oddzielna linijka kodu. Zgodnie z założeniem, makro miało wypisać tylko pięć pierwszych potęg danej liczby, dlatego w miarę łatwo było stworzyć dla każdej z nich oddzielny wiersz.

Zwróć jednak uwagę, że wszystkie linijki drukujące poszczególne potęgi w arkuszu są do siebie bliźniaczo podobne (różnią się tylko numerem wiersza). Zawsze gdy napotkasz w kodzie niemal identyczne fragmenty, powinno to zwrócić Twoją uwagę - prawdopodobnie można z tych fragmentów stworzyć jeden wspólny, korzystając z jakichś wbudowanych elementów języka VBA (np. pętli, tak jak w tym przypadku) lub pisząc własną funkcję. Dzięki stworzeniu uniwersalnego fragmentu kodu, zastępującego kilka podobnych fragmentów, cały kod będzie łatwiejszy do zrozumienia i zajmie mniej miejsca, a w razie potrzeby wprowadzenia później jakichkolwiek zmian, będzie trzeba zmodyfikować tylko ten jeden wspólny fragment, zamiast kilku podobnych kawałków porozrzucanych po całej aplikacji.

Przytoczona powyżej argumentacja powinna wystarczyć, abyś przekonał się, że dotychczasowa postać kodu printującego potęgi nie jest optymalna. Jest jednak jeszcze jeden argument, można by rzec, że koronny. Wyobraź sobie bowiem sytuację, w której musiałbyś zmodyfikować powyższe makro tak, aby zamiast pięciu pierwszych potęg, wyświetlało ich 50 (albo napisać inne makro, które ma wyświetlić jakąś określoną wartość dla 10 tysięcy wierszy). Oczywiście ręczne wpisywanie jednego wiersza po drugim, tak jak to było dotychczas praktykowane w makrze printującym potęgi, byłoby kompletnie niedorzecznym pomysłem. Po ukończeniu tej czynności taki plik prawdopodobnie nie byłby już nikomu do niczego potrzebny, bo dane w nim zawarte byłyby nieaktualne o co najmniej kilka miesięcy. Zdecydowanie lepszym wyjściem z tej sytuacji byłoby wpisanie i przeciągnięcie odpowiednich formuł bezpośrednio w arkuszu Excela.

Na szczęście z pomocą idą pętlę, za pomocą których wystarczy jeden raz opisać wielokrotnie wykonywaną operację (w tym przypadku wstawianie potęg w komórkach arkusza), a potem określić tylko liczbę powtórzeń tej operacji.

Poniżej znajdziesz kod przedstawiający makro do printowania potęg zmodyfikowane w taki sposób, aby korzystało z pętli, oraz analizę tego kodu linijka po linijce.
1
2
3
4
5
6
7
8
9
10
11
Sub wyswietlajPotegi(podstawa As Byte, ilePoteg As Integer, kolumna As Byte)
    Dim i As Integer
    Dim potega As Long

    potega = 1

    For i = 1 To ilePoteg
        Worksheets("Arkusz1").Cells(i, kolumna) = potega
        potega = potega * podstawa
    Next i
End Sub

Aby przetestować działanie makra, wykonaj w oknie Immediate polecenie:
 
Call wyswietlajPotegi(2, 20, 1)
które powinno wyświetlić 20 pierwszych potęg dwójki w pierwszej kolumnie arkusza Arkusz1.

Procedura wyswietlajPotegi posiada teraz trzy argumenty wejsciowe:
  • podstawa: liczba typu Byte (a więc z zakresu 0-255); jest to liczba, która będzie podnoszona do potęgi,
  • ilePoteg: liczba typu Integer; argument ten określa ile pierwszych potęg danej liczby (podanej jako argument podstawa) ma zostać wyświetlonych w arkuszu,
  • kolumna: liczba typu Byte; określa, w której kolumnie arkusza mają być wyświetlone te potęgi.

Dodatkowo w sekcji deklaracji zmiennych (wiersze 2-3) pojawiają się dwie kolejne zmienne:
  • i: zmienna liczbowa służąca jako licznik w pętli; jej działanie zostanie szczegółowo opisane w dalszej części lekcji przy okazji omawiania schematu działania pętli,
  • potega: zmienna typu Long; przechowuje wartości poszczególnych potęg; przy każdym kolejnym powtórzeniu pętli zmienna ta będzie mnożona przez zmienną podstawa, tworząc tym samym kolejną potęgę.

W wierszu 5 do zmiennej potega przypisana zostaje liczba 1. Do tego momentu zmienna potega miała domyślną wartość 0 i gdyby nie przypisano do niej wartości 1, mnożenie jej przez zmienną podstawa, wykonywane przy każdym kolejnym powtórzeniu pętli, nie odnosiłoby żadnego skutku i nadal wynosiłaby ona 0.

Wreszcie w wierszach 7-10 znajduje się pętla printująca poszczególne potęgi w arkuszu.

Postać ogólna pętli wygląda następująco:
 
 
 
For i = liczbaPoczatkowa To liczbaKoncowa
    'operacje do wykonania
Next i

Każda pętla rozpoczyna się od słowa kluczowego For. Po tym słowie musi nastąpić nazwa tzw. iteratora, czyli zmiennej przechowującej liczbę powtórzeń pętli. Przyjęło się, aby zmienną iteracyjną nazywać i (tak też uczyniono w omawianym przykładzie), ale nie jest to konieczne, więc możesz nadać iteratorowi swoją własną nazwę. Zmienna iteracyjna nie różni się niczym od pozostałych zmiennych, dlatego, podobnie jak one, przed swoim pierwszym wystąpieniem musiała zostać zadeklarowana.

Podstawowym zadaniem zmiennej iteracyjnej jest nadzorowanie, czy pętla nie powinna już zakończyć swojego działania.

Wywołując pętle należy podać wartość startową (liczbaPoczatkowa) oraz końcową (liczbaKoncowa) iteratora, na podstawie których sprawdza on stan wykonania pętli.

Przy uruchomieniu pętli do iteratora przypisywana jest wartość początkowa określona w wierszu wywołania przez argument liczbaPoczatkowa. Po każdym wykonaniu pętli wartość iteratora jest zwiększana o 1, a przed przystąpieniem do kolejnego powtórzenia sprawdzane jest czy aktualna wartość iteratora nie przekracza maksymalnej wartości (określonej w wierszu wywołania pętli za pomocą argumentu liczbaKoncowa). Jeżeli kompilator stwierdzi, że wartość zmiennej iteracyjnej przekroczyła już górną granicę, wykonywanie kodu zostaje przeniesione do poleceń znajdujących się bezpośrednio za pętlą.

Pamiętaj, że aby pętla wykonała jakiekolwiek operacje, wartość argumentu liczbaKoncowa nie może być mniejsza od wartości argumentu liczbaPoczatkowa. Jeżeli będzie inaczej, kompilator już przy pierwszym wywołaniu stwierdzi, że wartość iteratora (która przy starcie pętli przyjmuje wartość zmiennej liczbaPoczatkowa), jest większa od górnej granicy pętli (czyli wartości zmiennej liczbaKoncowa), a więc nadszedł czas na zakończenie działania pętli i przejście do kolejnych instrukcji.

Poniżej znajduje się przykład pętli, której instrukcje nigdy nie zostaną wykonane:
 
 
 
For i = 5 To 3
    'operacje do wykonania
Next i

Zauważ, że już na starcie zmienna iteracyjna i otrzymuje wartość 5. Równocześnie zostaje określone, że pętla ma zakończyć swoje działanie w momencie, gdy zmienna ta osiągnie wartość większą niż 3 - a więc już w momencie nadania zmiennej i wartości początkowej przekracza ona górny limit, co doprowadza do automatycznego wyjścia z pętli.

Najważniejszą częścią pętli jest jej wnętrze, w którym opisane są instrukcje, jakie mają być wykonane przy każdym powtórzeniu pętli.

W opisywanym przykładzie we wnętrzu pętli znajdują się dwie operacje: wpisanie wartości zmiennej potega w odpowiedniej komórce arkusza oraz pomnożenie tej zmiennej przez podstawę potęgi przechowywaną w argumencie podstawa i stworzenie tym samym kolejnej potęgi.

Zauważ, że w operacji printowania wartości do arkusza wykorzystana została zmienna iteracyjna i. Dzięki temu, że przy każdym powtórzeniu pętli jest ona zwiększana o 1, każda kolejna potęga jest wypisywana jeden wiersz niżej od swojej poprzedniczki.

Wykorzystanie zmiennej iteracyjnej w operacjach znajdujących się wewnątrz pętli jest powszechną praktyką i w zasadzie pętle, które tego nie czynią, należą do rzadkości.

Ostatnim elementem konstrukcji pętli jest wiersz zamknięcia:
 
Next i
składający się ze słowa kluczowego Next oraz nazwy iteratora.

Po dotarciu do wiersza zamknięcia pętli, kompilator zwiększa wartość iteratora o 1 i powraca do wiersza otwarcia pętli. Kolejnym krokiem jest sprawdzenie czy po wykonanym przed momentem zwiększeniu wartości iteratora nie przekroczyła ona górnego limitu i ewentualne opuszczenie pętli (w przypadku przekroczenia przez iterator górnej granicy) lub kontynuowanie jej wykonywania (w przypadku gdy wartość iteratora nadal jest mniejsza niż górna granica pętli).

Jak zatem zachowuje się pętla i poszczególne zmienne w omówionym przykładzie?

7
8
9
10
For i = 1 To ilePoteg
    Worksheets("Arkusz1").Cells(i, kolumna) = potega
    potega = potega * podstawa
Next i

Zmienną iteracyjną jest w tej pętli zmienna i, dla której początkową wartością jest liczba 1, a końcową wartość zmiennej ilePoteg (czyli liczba podana jako argument o takiej nazwie przy wywołaniu procedury; załóżmy, że wywołałeś tę procedurę z argumentem ilePoteg = 20).

Za każdym razem, kiedy wykonywanie kodu znajduje się w wierszu otwarcia pętli, zmienna iteracyjna sprawdzana jest pod kątem przekraczania górnej granicy pętli (nawet jeżeli jest to dopiero pierwsze wywołanie tej pętli). W tym przypadku zmienna i wynosi 1, a górna granica pętli - 20, więc pętla nie musi być zakończona i wykonywanie kodu jest przekazywane do wnętrza pętli.

Pierwszą instrukcją we wnętrzu pętli jest polecenie:
8
Worksheets("Arkusz1").Cells(i, kolumna) = potega
czyli wyprintowanie w arkuszu Arkusz1 wartości zmiennej potega (która wynosi 1, gdyż taka wartość została jej nadana przed wejściem do pętli, w wierszu 5). Wartość iteratora wynosi aktualnie 1, więc zmienna zostanie wyświetlona w pierwszym wierszu arkusza oraz w kolumnie takiej, jaką określono za pomocą argumentu kolumna w momencie wywoływania procedury.

Drugą czynnością wykonywaną przez tę pętlę jest pomnożenie zmiennej potega przez podstawę potęgi przechowywaną w zmiennej podstawa. Po wykonaniu tej operacji zmienna potega będzie miała wartość 2, czyli kolejną potęgę dwójki.

Następnie kompilator przechodzi do wiersza
10
Next i
w którym wartość zmiennej iteracyjnej i jest zwiększana o 1 (a więc będzie od teraz wynosiła 2).

Po opuszczeniu wiersza zamknięcia pętli wykonanie kodu zawsze wraca do wiersza otwarcia pętli, gdzie kompilator ponownie sprawdza czy wartość zmiennej iteracyjnej nie przekroczyła górnego limitu. Jak przed momentem wspomniano, iterator przyjął dopiero wartość 2 (przy górnej granicy równej 20), a więc ponownie wykonywane są instrukcje zawarte we wnętrzu pętli.

Wartość zmiennej potega wynosi w tym momencie 2 i taki wynik zostanie teraz wyprintowany w arkuszu Arkusz1 w jego drugim wierszu (ponieważ, jak widzisz w kodzie, o wierszu, w którym będzie wypisana zmienna potega decyduje wartość iteratora i, która aktualnie wynosi 2). W kolejnym wierszu zmienna potega ponownie jest mnożona przez podstawę, tworząc tym samym kolejną potęgę dwójki, po czym kod jest przekazywany do wiersza zamknięcia pętli, gdzie zmienna iteracyjna jest zwiększana o 1 i przyjmuje teraz wartość 3.

Opisana sekwencja operacji jest powtarzana tak długo, aż wartość iteratora osiągnie 20. Wówczas kompilator wykona jeszcze instrukcje zawarte we wnętrzu pętli, ponieważ iterator nie przekracza górnej granicy pętli, a jedynie się z nią zrównuje - makro wyświetli więc w dwudziestym wierszu arkusza wartość dwudziestej potęgi dwójki oraz zwiększy wartość zmiennej potega do dwudziestej pierwszej potęgi dwójki. Ale po nadaniu zmiennej iteracyjnej w wierszu Next i kolejnej wartości - 21, iterator nie przejdzie już weryfikacji w wierszu otwarcia pętli, ponieważ jego wartość jest od tej pory wyższa niż górny limit pętli (określony na 20). W tym momencie makro opuszcza więc pętlę i przechodzi do wykonywania kolejnych instrukcji, znajdujących się w kodzie pod tą pętlą (w omawianym przykładzie jest to już tylko zamknięcie procedury słowem kluczowym End Sub).

Zmiana kroku pętli

Podczas omawiania przykładu wypisującego w arkuszu potęgi, wielokrotnie wspomniano, że po dotarciu do wiersza zamknięcia pętli (Next i), wartość iteratora jest zwiększana o 1. Nie dla każdej pętli jest to jednak prawda, ponieważ w rzeczywistości sam możesz zadecydować o jaką wartość będzie powiększany iterator przy każdym wykonaniu pętli - masz w tej kwestii całkowitą dowolność i jako wartość powiększającą iterator możesz równie dobrze użyć liczby naturalnej, jak i ułamka czy liczby ujemnej.

Poniżej znajduje się omawiany wcześniej kod, zmodyfikowany tak, aby poszczególne potęgi były wyświetlane w co drugim wierszu (przed jego uruchomieniem i przetestowaniem wyczyść arkusz, tak aby poprzednie wpisy nie wymieszały się z nowymi).
1
2
3
4
5
6
7
8
9
10
11
Sub wyswietlajPotegi(podstawa As Byte, ilePoteg As Integer, kolumna As Byte)
    Dim i As Integer
    Dim potega As Long

    potega = 1

    For i = 1 To ilePoteg Step 2
        Worksheets("Arkusz1").Cells(i, kolumna) = potega
        potega = potega * podstawa
    Next i
End Sub

Jak widzisz, jedynym nowym elementem, jaki pojawił się w kodzie, jest polecenie Step 2 dopisane w wierszu otwarcia pętli. W poprzednim przykładzie słowo kluczowe Step zostało pominięte, co było równoznaczne z nadaniem pętli wartości domyślnej 1. W obecnej postaci pętli, za każdym razem, kiedy wykonanie kodu dojdzie do wiersza zamknięcia pętli, wartość iteratora będzie zwiększana o 2, a nie ja dotychczas o 1.

Zwróć też uwagę, że w tej sytuacji zostanie wyświetlonych tylko dziesięć pierwszych potęg dwójki, ponieważ od wartości startowej, wynoszącej 1, do górnej granicy pętli równej 20, przy każdorazowym zwiększaniu iteratora o 2, nastąpi tylko 10 wywołań pętli.

Pętla może być również skonstruowana w taki sposób, aby przy każdym jej wywołaniu wartość iteratora była zmniejszana. Zasada działania jest w tym przypadku identyczna, należy po prostu w wierszu otwarcia pętli wstawić po słowie kluczowym Step liczbę ujemną, o jaką ma być pomniejszany iterator przy każdym powtórzeniu pętli.

1
2
3
4
5
6
7
8
9
10
11
Sub wyswietlajPotegi(podstawa As Byte, ilePoteg As Integer, kolumna As Byte)
    Dim i As Integer
    Dim potega As Long

    potega = 1

    For i = ilePoteg To 1 Step -1
        Worksheets("Arkusz1").Cells(i, kolumna) = potega
        potega = potega * podstawa
    Next i
End Sub

Powyższe makro jest kolejną modyfikacją makra wyświetlającego w arkuszu dwadzieścia pierwszych potęg dwójki, z tym że teraz wyświetlane są one w odwrotnej kolejności - od dwudziestego do pierwszego wiersza.

Zauważ, że w wierszu otwarcia początkowa wartość iteratora jest większa od jej limitu, co jak wcześniej kilkukrotnie wspomniano powinno oznaczać automatyczne zakończenie działania pętli. Otóż w przypadku zadeklarowania w pętli ujemnej wartości Step, sytuacja ulega zmianie o 180 stopni - teraz górny limit staje się dolnym limitem, a pętla kończy działanie, kiedy wartość iteratora jest od tego limitu mniejsza.

Wykorzystując słowo kluczowe Step można bardzo łatwo stworzyć nieskończoną pętlę. Wystarczy wpisać w wierszu otwarcia pętli polecenie Step 0.

Zmiana wartości iteratora wewnątrz pętli

We wszystkich omawianych dotychczas pętlach wartość iteratora była zmieniana tylko poprzez wiersz zamknięcia pętli - Next i. Nie oznacza to jednak, że zmienna iteracyjna nie może być modyfikowana wewnątrz pętli.

Poniżej znajduje się przykład makra, które wypisuje w arkuszu wszystkie daty przypadające w dni powszednie, modyfikując wartość iteratora tak, aby przeskakiwał dni przypadające w weekend.
1
2
3
4
5
6
7
8
9
10
11
12
13
Sub wyswietlajDniPowszednie()
    Dim data As Date
    Dim n As Long

    n = 1

    For data = #2010-01-01# To #2010-12-31#
        Cells(n, 1) = Format(data, "Long Date")
        n = n + 1
        If Weekday(data, vbMonday) = 5 Then data = data + 2
    Next data

End Sub

W makrze zadeklarowane zostały dwie zmienne:
  • data - zmienna typu Date. Przechowuje kolejne daty, a równocześnie służy w pętli jako zmienna iteracyjna,
  • n - zmienna typu Long. Przechowuje numer wiersza, w którym ma być wyświetlona kolejna data. Wartość tej zmiennej jest zwiększana o 1 przy każdym kolejnym wykonaniu pętli, tak aby każda kolejna data była wypisana jeden wiersz niżej od poprzedniej.
    W poprzednich przykładach jako numer wiersza wykorzystywana była zmienna iteracyjna. W tym przypadku nie można zastosować iteratora jako numeru wiersza z dwóch powodów: początkową wartością iteratora jest data 1 stycznia 2010, której odpowiada liczba 40 179, a więc printowanie rozpoczęłoby się dopiero od wiersza o takim numerze; poza tym, aby pominąć soboty i niedziele, wartość iteratora czasami przeskakuje o 2, więc gdyby został on wykorzystany jako numer wiersza, w arkuszu również występowałyby dwuwierszowe przerwy.

W wierszu 5 kodu do zmiennej n zostaje przypisana początkowa wartość 1, gdyż wypisywanie dat ma się rozpocząć od pierwszego wiersza arkusza.

W wierszu 6 rozpoczyna się pętla, w której iteratorem jest zmienna data, wartością początkową 1 stycznia 2010, a wartością końcową 31 grudnia 2010.

Wnętrze pętli składa się z trzech poleceń.

Najpierw aktualna wartość zmiennej data jest wyświetlana w arkuszu, w jego pierwszej kolumnie i wierszu określonym przez zmienną n (przy pierwszym wykonaniu pętli jest to pierwszy wiersz arkusza). Zmienna Data przed wyświetleniem w arkuszu jest jeszcze obrabiana przez funkcję Format z parametrem Long Date, która formatuje datę do postaci zawierającego pełną nazwę miesiąca (np. 1 styczeń 2010).

W kolejnym wierszu wartość zmiennej n jest zwiększana o 1, tak aby każa kolejna data była wyświetlana w jednym wierszu poniżej swojej poprzedniczki.

W ostatnim wierszu wnętrza pętli znajduje się instrukcja warunkowa, sprawdzająca czy aktualna data, przechowywana w zmiennej data, przypada w piątek. Jeżeli tak się dzieje, do wartości iteratora dodawana jest liczba 2, tak aby ominąć dwa dni: sobotę oraz niedzielę. Zwróć uwagę, że po dodaniu do piątkowej daty dwóch dni, zmienna data przyjmie wartość będącą datą niedzielną. Należy jednak pamiętać, że w wierszu zamknięcia pętli (Next data), wartość zmiennej iteracyjnej jest dodatkowo zwiększana o 1, więc ostatecznie przed kolejnym wkroczeniem kodu do wnętrza pętli zmienna data będzie przechowywała poniedziałkową datę.

Manipulując wartością iteratora we wnętrzu pętli również można łatwo stworzyć nieskończoną pętlę.

Wystarczy przed wierszem zamknięcia pętli odejmować od aktualnej wartości iteratora 1 (lub inną liczbę przypisaną w wierszu otwarcia do argumentu Step). Wówczas, tuż przed wejściem kodu do linii zamykającej pętlę, iterator będzie zmniejszany o 1, a w samym wierszu zamknięcie będzie zwiększany o 1, w związku z czym cały czas będzie miał tę samą wartość i nigdy nie przekroczy górnego limitu pętli.

Opuszczenie pętli przed jej zakończeniem

Czasem zdarzają się sytuacje, że pomimo określenia górnego limitu pętli, powinna ona zakończyć swoje działanie przed jego osiągnięciem, ponieważ po spełnieniu określonego warunku, jej dalsze działanie staje się bezcelowe.

Przykład takiej pętli znajdziesz w przedstawionej poniżej funkcji znajdzOdPrawej. Funkcja ta znajduje pierwsze od prawej strony wystąpienie znaku określonego jako argument char w tekście podanym jako argument tekst.

Pętla powinna sprawdzić po kolei wszystkie znaki podanego tekstu, począwszy od ostatniego, a na pierwszym skończywszy. Jednak w momencie, gdy szukany znak zostanie odnaleziony, pętla powinna zakończyć działanie, ponieważ wynik funkcji jest już w tym momencie znany i nie ma sensu marnowanie czasu na dalsze wykonywanie pętli, skoro i tak w żaden sposób nie wpłynie to już na końcowy wynik funkcji.

Poniżej znajduje się kod oraz jego analiza:
1
2
3
4
5
6
7
8
9
10
Function znajdzOdPrawej(char As String, tekst As String) As Integer
    Dim i As Integer

    For i = Len(tekst) To 1 Step -1
        If Mid(tekst, i, 1) = char Then
            znajdzOdPrawej = i
            Exit For
        End If
    Next i
End Function

Funkcja wymaga zadeklarowania dwóch argumentów: char - czyli znaku, który będzie szukany w tekście bazowym oraz sam tekst bazowy, określony w powyższym przykładzie jako tekst.

Oprócz tego w funkcji zadeklarowana jest zmienna typu Integer, która posłuży za zmienną iteracyjną w pętli.

Cała funkcja składa się jedynie z opisywanej pętli. W wierszu otwarcia pętli jako wartość początkowa iteratora została podana długość tekstu bazowego, która jest wyliczana za pomocą funkcji Len(tekst) (o funkcji Len możesz poczytać tutaj).

Jako końcowy limit pętli podana została wartość 1. Określono również argument Step i nadano mu wartość -1, co oznacza, że po każdym powtórzeniu pętli wartość iteratora będzie zmniejszana o 1.

Wnętrze pętli składa się tylko z jednej instrukcji warunkowej, która sprawdza czy dany znak tekstu bazowego jest poszukiwanym znakiem, określonym jako argument char. Do sprawdzania poszczególnych znaków wyrazu bazowego wykorzystana została funkcja Mid(tekst, i, 1), która zwraca pojedynczy znak z tekstu tekst, znajdujący się w tym tekście na pozycji takiej, jak argument i (czyli na pozycji takiej, jaka jest aktualnie wartość zmiennej iteracyjnej w pętli). Przy pierwszym wykonaniu pętli sprawdzany więc będzie ostatni znak tekstu bazowego, przy drugim wykonaniu - przedostatni, itd. aż zmienna iteracyjna osiągnie wartość 1, czyli sprawdzony będzie pierwszy znak tekstu.

W instrukcji warunkowej znajdującej się w pętli pominięty został blok Else, ponieważ w sytuacji, gdy sprawdzany znak nie jest szukanym znakiem, nie mają być wykonywane żadne czynności poza przejściem do następnego wykonania pętli.

Natomiast w sytuacji, gdy okaże się, że sprawdzany znak jest szukanym znakiem, jako wartość funkcji zostaje przypisana aktualna wartość zmiennej iteracyjnej i, ponieważ na takiej właśnie pozycji został znaleziony poszukiwany znak (wiersz 6).

Oprócz tego, w bloku czynności przewidzianych dla spełnionego warunku znajduje się instrukcja Exit For (wiersz 7), która oznacza natychmiastowe opuszczenie pętli bez względu na to, jaka jest aktualna wartość zmiennej iteracyjnej. Tak jak wcześniej wspomniano, polecenie to jest w tej sytuacji użyte, ponieważ po odnalezieniu w tekście bazowym szukanego znaku znana jest już końcowa wartość funkcji i nie ma potrzeby dalszego wykonywania tej pętli. W zasadzie dalsze wykonywanie pętli mogłoby nawet zniekształcić wynik funkcji, ponieważ jeśli szukany znak zostałby ponownie odnaleziony w bazowym tekście (bliżej początku tego tekstu), to wynik funkcji zostałby nadpisany i funkcja zwracałaby pierwsze wystąpienie szukanego znaku od lewej strony, zamiast od prawej.

Na koniec możesz sprawdzić działanie napisanej przed momentem funkcji znajdzOdPrawej, wpisując kilka zapytań w oknie Immediate:

Wyniki funkcji znajdzOdPrawej

Zagnieżdżanie pętli

Pętle, podobnie jak instrukcje warunkowe czy funkcje, mogą być w sobie zagnieżdżane.

Przykład takiej zagnieżdżonej pętli znajduje się w poniższym makrze, które wyświetla w arkuszu tabliczkę mnożenia o dowolnym rozmiarze (podawanym jako argument przy wywoływaniu makra).
1
2
3
4
5
6
7
8
9
10
Sub tabliczkaMnozenia(rozmiar As Integer)
    Dim i As Integer
    Dim j As Integer

    For i = 1 To rozmiar
        For j = 1 To rozmiar
            Cells(i, j) = i * j
        Next j
    Next i
End Sub

W procedurze tabliczkaMnozenia zadeklarowany został jeden argument wejściowy - rozmiar, który decyduje o rozmiarze wyświetlanej w arkuszu tabliczki mnożenia.

Oprócz tego procedura zawiera dwie zmienne typu Integer - i oraz j, które pełnią rolę iteratorów w pętlach.

Wiersz 5 jest wierszem otwarcia pierwszej pętli (z iteratorem i), która zostanie wykonana tyle razy, ile wynosi wartość argumentu rozmiar. Każde pojedyncze wykonanie tej pętli spowoduje wyświetlenie w arkuszu kolejnego wiersza tabliczki mnożenia.

We wnętrzu tej pętli zagnieżdżona jest druga pętla (wiersze 6-8), w której iteratorem jest zmienna j. Liczba powtórzeń tej pętli także jest równa argumentowi rozmiar. Jeżeli więc wywołując procedurę tabliczkaMnozenia jako wartość argumentu rozmiar podałeś przykładowo 40, to pierwsza pętla zostanie wykonana 40 razy, a w każdym jej pojedynczym wykonaniu dodatkowo 40 razy wykonana zostanie pętla, która jest w niej zagnieżdżona (ta druga pętla zostanie więc wykonana łącznie 1600 razy). Przy każdym powtórzeniu wewnętrznej pętli wykonywane jest jedno polecenie:
7
Cells(i, j) = i * j
które mnoży przez siebie wartość obu iteratorów, a następnie wyświetla wynik tego mnożenia w aktywnym arkuszu, w wierszu takim, jaka jest aktualna wartość iteratora i i kolumnie o numerze równym aktualnej wartości iteratora j.

Schemat działania powyższej procedury jest więc następujący (załóżmy, że przy wywołaniu funkcji jako argument rozmiar podano 40): kiedy wykonanie kodu dociera do wiersza 5 zostaje otwarta pierwsza pętla, a iterator i przyjmuje wartość 1. W kolejnym wierszu (6), otwarta zostaje druga pętla, której iterator (czyli zmienna j) również otrzymuje początkową wartość 1. Górną granicą tej pętli jest wartość argumentu rozmiar, a więc zostanie ona wykonana 40 razy. Zwróć uwagę, że podczas powtarzania wewnętrznej pętli wartość iteratora i cały czas jest równa 1, ponieważ kod nie dotarł jeszcze do wiersza zamknięcia pierwszej pętli. Natomiast wartość iteratora tej wewnętrznej pętli (j) przy każdym jej powtórzeniu zwiększa się o 1. W związku z tym, przy pierwszym wykonaniu zagnieżdżonej pętli wykonana zostanie operacja
7
Cells(1, 1) = 1 * 1
potem
7
Cells(1, 2) = 1 * 2
7
 
Cells(1, 3) = 1 * 3
'...
itd. Dopiero po wykonaniu 40 takich operacji opuszczona zostanie wewnętrzna pętla i kompilator natrafi na wiersz zamknięcia pierwszej pętli. Wówczas wartość iteratora i zostanie zwiększona o 1 (będzie teraz wynosić 2) i wykonywanie kodu ponownie trafi do wewnętrznej pętli. Cały ten proces powtarzany będzie tak długo, aż wartość iteratora i przekroczy górny limit wyznaczony dla zewnętrznej pętli (czyli w tym przypadku 40).