5. Funkcje własne.

5.7. Przekazywanie danych: wskaźniki

W tym rozdziale zobaczymy, że funkcja jest w stanie podmienić oryginalne wartości zmiennych, jeśli zostaną one przekazane za pomocą wskaźników. W celu demonstracji tego efektu użyjmy kod 1 z poprzedniego rozdziału z tą zaś różnicą, że teraz w opisie funkcji własnej między typem a nazwą parametru dopiszemy &. Niżej zapisałem skróconą wersję takiego kodu (kod 1).

Kod 1
#property strict

void OnStart()
  {
   //...
  }

//--- opis funkcji własnej CylinderVolume()
double CylinderVolume(double & radius, double & height)
  {
   //...
  }

Po uruchomieniu tego skryptu w logach zobaczymy następujące wpisy (rys. 1):

Rys. 1. Wynik działania skryptu.


Wartości argumentów r i h przed wywołaniem funkcji są następujące "Test EURUSD,H1: 1) Przed wywołaniem funkcji własnej: r = 1.0, h = 2.5", oraz parametrów radius i height przed ich zmianą "Test EURUSD,H1: 2) Wewnątrz funkcji własnej przed zmianą: radius = 1.0, height = 2.5" są identyczne i tak powinno być.

Trzeci wpis "Test EURUSD,H1: 3) Wewnątrz funkcji własnej po zmianie: radius = 6.0, height = 0.3" informuje nas o zmianach w radius i height. A teraz najważniejsza część, ostatni czwarty wpis "Test EURUSD,H1: 4) Po wywołaniu funkcji własnej: r = 6.0, h = 0.3" uświadamia nam o zmianach w zmiennych r i h, które zostały zmienione przez funkcję.

Na tym przykładzie zobaczyliśmy, że stosowanie wskaźników niesie ze sobą ryzyko podmiany oryginalnych wartości.


Teraz w tym samym kodzie przed typem parametru dopiszmy const (kod 2).

Kod 2
#property strict

void OnStart()
  {
   //...
  }

//--- opis funkcji własnej CylinderVolume()
double CylinderVolume(const double & radius, const double & height)
  {
   //...
  }

Podczas kompilacji takiego kodu w MetaEditor 4 kompilator wyświetli 2 błędy: " 'radius' - constant cannot be modified " oraz " 'height' - constant cannot be modified " (rys. 2). Takiego programu po prostu nie można będzie uruchomić w terminalu.

Rys. 2. Błąd kompilacji.


Stało się to tak dlatego, że za pomocą specyfikatora const ustaliliśmy, że radius i height nie mogą być zmienione przez funkcję. Dlatego próba ich zmiany wywołała gniew kompilatora. Aby nie było takich błędów można: a) albo wewnątrz funkcji własnej nie zmieniać tych parametrów, b) albo wewnątrz funkcji utworzyć 2 nowe zmienne, skopiować do nich wartości radius i height i pracować z nowymi zmiennymi, c) albo zamiast wskaźników stosować kopiowanie danych jak opisano w poprzednim rozdziale.

Teraz wiemy, że do funkcji własnej wartość można przekazać poprzez jej kopiowanie lub używając wskaźnika (&) na oryginał. Rodzi się pytanie, co jest lepsze? Z reguły funkcje tworzy się po to aby pewne działania wynieść poza granice głównej części kodu i poprawić jego czytelność. Raz przygotowaną funkcję można stosować w wielu różnych programach, dlatego najlepiej opisać ją tak aby pracowała ona z kopiami, a nie z oryginałami (za wyjątkiem tablic, patrz następny rozdział). Dodatkowo przy kopiowaniu w funkcji można tworzyć domyślne wartości parametrów oraz statyczne zmienne o czym mowa pójdzie w kolejnych rozdziałach.