English Русский 中文 Español 日本語 Português
preview
Von der Grundstufe bis zur Mittelstufe: WHILE- und DO WHILE-Anweisungen

Von der Grundstufe bis zur Mittelstufe: WHILE- und DO WHILE-Anweisungen

MetaTrader 5Beispiele | 2 Mai 2025, 08:59
63 0
CODE X
CODE X

Einführung

Die hier vorgestellten Materialien sind ausschließlich für didaktische Zwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.

Im vorigen Artikel „Von der Grundstufe zur Mittelstufe: IF ELSE-Anweisung“ habe ich erklärt, wie man den Code untersucht, um eine bedingte Ablaufkontrolle zu implementieren. Dies geschah, damit wir je nach dem zu analysierenden Ausdruck wählen konnten, ob die eine oder die andere Prozedur ausgeführt werden sollte.

Obwohl die IF-Anweisung zusammen mit ihrem Verbündeten ELSE so nützlich ist, dass sie uns erlaubt, fast jeden Code zu implementieren, wäre dies in der Praxis nicht sehr klug. Die Verwendung von nur zwei Anweisungen würde einige Teile des Codes ziemlich schwer verständlich und verdaulich machen.

Genau aus diesem Grund stützen sich Programmiersprachen nicht nur auf das IF-ELSE-Paar. Um den Code lesbarer und verständlicher zu machen, enthalten sie eine breitere Palette von Anweisungen, einschließlich Schleifenanweisungen.

Schleifenanweisungen gehören im Allgemeinen und ohne Übertreibung zu den gefährlichsten Kontrollflussanweisungen, die es gibt. Denn schon ein kleiner Programmierfehler bei der Implementierung einer Schleife kann zu einer Katastrophe führen. Und das ist ein ernstes Problem, denn Ihr Code wird in eine Endlosschleife geraten. Viele Anfänger geben auf, wenn sie auf ein solches Problem stoßen. Sie sind einfach entsetzt über die Aussicht, Schleifen in ihrem Code zu implementieren.

Es gibt im Wesentlichen zwei Möglichkeiten, eine Schleife in einem Programm zu erstellen. Bei der ersten werden Funktionen und Prozeduren außerhalb der Hauptroutine verwendet, in der die Schleife implementiert ist. Der zweite Weg ist der über Anweisungen zur Ablaufkontrolle.

Da die Verwendung von Anweisungen zur Ablaufkontrolle der einfachere Ansatz ist, werden wir zunächst damit beginnen. Im weiteren Verlauf werde ich jedoch zeigen, wie man Schleifen mit Funktionen und Prozeduren erstellt. Im Gegensatz zu dem, was viele vermuten, gibt es einen triftigen Grund für die Verwendung einer Funktion oder einer Prozedur zur Erstellung einer Schleife, anstatt sich nur auf Kontrollflussanweisungen zu verlassen. Aber das zu erklären, wird Gegenstand eines anderen Artikels zu einem geeigneteren Zeitpunkt sein.

Es gibt eine Voraussetzung, um diesem Artikel folgen zu können: ein Verständnis von Variablen und Konstanten. Wir haben dieses Thema bereits behandelt. Neben dem Wissen, was Variablen und Konstanten sind, kommt es hier vor allem darauf an, zu verstehen, wie sich die Bitbreite auf die Werte auswirkt und wie der Typ einer Variablen ihren Wert beeinflussen kann.

Wenn Sie nicht wissen, worauf ich mich beziehe, sehen Sie sich den Artikel „Von der Grundstufe bis zur Mittelstufe: Operatoren“ an, wo ich einige wichtige Konzepte zu diesem Thema erkläre. Der dortige Inhalt ist zwar grundlegend, sollte aber ausreichen, um dem hier Besprochenen folgen zu können. Ich empfehle Ihnen dringend, andere Artikel zu lesen, um ein umfassenderes Verständnis für die in diesem Artikel vorgestellten Themen zu erlangen.

An diesem Punkt befinde ich mich in einem kleinen Dilemma. Obwohl die FOR-Anweisung für die Erstellung von Schleifen im Allgemeinen einfacher ist und von Programmierern oft bevorzugt wird, hat sie einige Nachteile. Andererseits sind die alternativen Steueranweisungen für die Erstellung von Schleifen tendenziell etwas riskanter als die FOR-Anweisung. Ich überlege also, welche ich zuerst einführen soll. In der Zwischenzeit werden wir wie folgt vorgehen: Wir werden einen neuen Abschnitt beginnen, in dem ich einige wichtige Konzepte zu diesem Thema erläutern werde.


Warum Schleifen verwenden?

Viele Programmierer haben regelrecht Angst vor der Erstellung von Schleifen in ihrem Code. Andere vermeiden sie so weit wie möglich und verwenden sie nur, wenn es nicht anders geht. Aber warum gibt es so viel Angst vor der Verwendung von Schleifen? Der Grund dafür ist einfach: Schleifen sind von Natur aus mit Risiken verbunden. Jedes Mal, wenn Sie eine eingeben, werden Sie von der Ausführung Ihres Codes abhängig und benötigen eine bestimmte Bedingung, um die Schleife bei Bedarf ordnungsgemäß zu beenden. Andernfalls kann eine Schleife in eine Endlosschleife übergehen, ohne dass Sie es bemerken, was dazu führt, dass Sie fälschlicherweise glauben, dass der Computer einfach zu lange braucht, um etwas zu verarbeiten, während der Code in Wirklichkeit in einer Endlosschleife gefangen ist.

Ein weiterer Grund, warum viele Entwickler Schleifen fürchten, ist die Tatsache, dass die Analyse der Vorgänge innerhalb von Schleifen recht schwierig sein kann. Dies liegt daran, dass Schleifen in realen Anwendungen oft Tausende oder sogar Millionen von Malen ausgeführt werden müssen, bevor sie abgeschlossen sind. Je nach Art der durchgeführten Berechnung kann es Stunden dauern, bis ein endgültiges Ergebnis geliefert wird.

Ich weiß, dass dies für viele undenkbar erscheint. Wie ist es möglich, dass ein Programm Stunden braucht, um eine Aufgabe zu erledigen? Aber es kommt vor. Es gibt Szenarien, in denen die Erledigung einer Aufgabe wirklich Stunden der Bearbeitung erfordert. In den meisten Fällen, vor allem im Bildungskontext, werden die von Ihnen zu schreibenden Schleifen jedoch relativ klein sein und eine Größenordnung von Tausenden von Iterationen haben. Dies führt in der Regel zu Ausführungszeiten von nur wenigen Sekunden oder Minuten. Ein gutes Beispiel sind Anwendungen, die für das Training eines neuronalen Netzes entwickelt wurden.

In meinem anderen Profil zeige ich, wie man eine solche Anwendung implementiert: ein neuronales Netz, das vollständig in MQL5 geschrieben ist. Meiner Meinung nach handelt es sich um ein mittelschweres Projekt, da es nur ein solides Verständnis von MQL5 und der zugrunde liegenden Mathematik erfordert. Der Rest ist relativ einfach.

Nun, ich habe die im Titel dieses Abschnitts gestellte Frage noch immer nicht beantwortet: Warum Schleifen verwenden? Die Antwort liegt in der Einfachheit, die sie für Ihren Code mit sich bringen. Mit Schleifen können Sie steuern, wie oft ein bestimmter Vorgang ausgeführt wird, ohne den Code manuell zu wiederholen oder Strg+C und Strg+V zu verwenden. Betrachten Sie das folgende Beispiel. Vorhin habe ich einen einfachen Code vorgestellt, mit dem man die Fakultät einer bestimmten Zahl berechnen kann. Wie Sie sich vielleicht erinnern, war der Code selbst recht einfach. Für diejenigen, die es nicht gesehen haben, hier noch einmal:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 0;
07.     ulong value = 1;
08. 
09.     Print("Factorial of ", counter, " => ", value);
10.     counter = counter + 1;
11.     value = value * counter;
12.     Print("Factorial of ", counter, " => ", value);
13.     counter = counter + 1;
14.     value = value * counter;
15.     Print("Factorial of ", counter, " => ", value);
16.     counter = counter + 1;
17.     value = value * counter;
18.     Print("Factorial of ", counter, " => ", value);
19.     counter = counter + 1;
20.     value = value * counter;
21.     Print("Factorial of ", counter, " => ", value);
22. }
23. //+------------------------------------------------------------------+

Code 01

Code 01 kann bei kleinen Zahlen akzeptiert werden. Wenn sie jedoch zunehmen, werden die Dinge komplizierter. Selbst bei einer 20-fachen Multiplikation ist der Aufbau sehr schwierig, außerdem ist die Wahrscheinlichkeit von Fehlern bei der Code-Implementierung sehr hoch, selbst bei Verwendung von CTRL+C und CTRL+V. Daher haben wir in demselben Artikel, in dem dieser Code 01 erscheint, einen weiteren entwickelt, der unten zu sehen ist.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     Factorial();
07.     Factorial();
08.     Factorial();
09.     Factorial();
10.     Factorial();
11. }
12. //+------------------------------------------------------------------+
13. void Factorial(void)
14. {
15.     static uchar counter = 0;
16.     static ulong value = 1;
17. 
18.     Print("Factorial of ", counter, " => ", value);    
19.     counter = counter + 1;
20.     value = value * counter;
21. }
22. //+------------------------------------------------------------------+

Code 02

An dieser Stelle werden Sie feststellen, dass unser Code etwas kompakter geworden ist, was es etwas einfacher macht, Strg+C und Strg+V für kleine Fakultäten zu verwenden. Was aber, wenn Sie die Fakultät einer wesentlich größeren Zahl berechnen müssen? Wie können Sie das tun? Wenn Sie die 64-Bit-Obergrenze des ulong-Wertes nicht überschritten haben, müssten Sie die faktoriellen Ebenen mehrfach kopieren und einfügen. Darin ist natürlich nicht der gesamte zusätzliche Aufwand enthalten, der erforderlich war, um den Code jedes Mal anzupassen, wenn eine neue Fakultät berechnet werden musste. Das wäre natürlich viel mühsamer als erfreulich. Aus diesem Grund macht die Verwendung einer Schleife den Code viel überschaubarer. Und das erklärt, warum Schleifen so wichtig sind.

Nachdem wir nun dieses Verständnis geschaffen haben, können wir mit der Diskussion über die zu verwendenden Aussagen beginnen. Die FOR-Schleife ist zwar bei vielen Programmierern beliebt (auch bei dem, der diese Zeilen schreibt), aber wir wollen mit einer anderen Anweisung beginnen. Diese Alternative hat zwei mögliche Implementierungen, ist aber einfacher zu erklären und daher leichter zu verstehen als die FOR-Schleife, die bestimmte Nuancen aufweist, die mich dazu brachten, mit einem anderen Ansatz zu beginnen.


Die Anweisungen WHILE und DO WHILE

Trotz der spielerischen Formulierung im Titel dieses Abschnitts ist diese Schleife recht einfach zu verstehen, da sie denselben Prinzipien folgt wie die IF-Anweisung. Es gibt jedoch einige wichtige Vorsichtsmaßnahmen zu beachten. Es ist nicht ungewöhnlich, dass Entwickler bei der Verwendung dieser Schleife Schwierigkeiten haben. Der Grund dafür ist einfach: Vergesslichkeit. Viele Programmierer vergessen, die Bedingung anzupassen oder zu korrigieren, die bestimmt, wann die Schleife beendet werden soll. Erstaunlicherweise machen selbst erfahrene Entwickler diesen Fehler. Betrachten Sie dies also als eine Warnung: Seien Sie vorsichtig, wenn Sie Code implementieren, der diese Anweisung verwendet.

Der Unterschied zwischen dem Paar WHILE und DO-WHILE ist ganz einfach. WHILE führt die interne Routine möglicherweise überhaupt nicht aus, während DO-WHILE garantiert, dass die Routine mindestens einmal ausgeführt wird. Das ist im Grunde alles. Einfach, nicht wahr? Die damit verbundenen Risiken werden dadurch jedoch nicht verringert. Beginnen wir also mit der einfacheren der beiden: der WHILE-Anweisung. Der Ablauf der Ausführung ist im Folgenden dargestellt.

Abbildung 01

Beachten Sie die Ähnlichkeit mit der IF-Anweisung, die im vorherigen Artikel besprochen wurde. Die Funktionsweise von Ausdrücken folgt hier den gleichen Prinzipien. Das bedeutet, dass die Schleife die definierte Routine nur dann ausführt, wenn der Ausdruck als wahr ausgewertet wird. Mit anderen Worten: Der Ausdruck muss ungleich Null sein, damit die Schleife durchlaufen wird. Aus diesem Grund habe ich die IF-Anweisung zuerst vorgestellt. Das Verständnis dieser Aussage ist entscheidend für jeden, der ein erfahrener Programmierer werden will, oder auch für diejenigen, die nur zum Spaß Code schreiben wollen.

Perfekt. Da diese Struktur der WENN-Anweisung recht ähnlich ist - und ich hoffe, dass Sie, liebe Leserin, lieber Leser, Ihre Hausaufgaben gemacht haben, indem Sie sie studiert haben - können wir nun direkter vorgehen.

Beginnen wir mit einem sehr einfachen Stück Code, um Ihnen eine grundlegende Einführung in Schleifen zu geben. Ich möchte Sie nicht ins Straucheln bringen, sondern Ihnen helfen zu verstehen, wie sie in der Praxis funktionieren. Analysieren wir dazu den folgenden Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     char info = 10;
07. 
08.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
09. 
10.     while (info)
11.     {
12.         info = info - 1;
13.         Print(__FUNCTION__, " : ", info);
14.     }
15. 
16.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
17. }
18. //+------------------------------------------------------------------+

Code 03

Dieser Code 03 veranschaulicht, wie eine WHILE-Schleife funktioniert. Bei der Ausführung wird die unten gezeigte Ausgabe erzeugt.

Abbildung 02

Der hervorgehobene Abschnitt in Abbildung 02 stellt den Teil der Ausgabe dar, der von der Schleife erzeugt wird. Dies ist die Routine, die innerhalb der WHILE-Schleife ausgeführt wird. Schauen wir uns nun kurz an, wie es dazu kam und warum der Countdown bei neun begann und bei null endete.

Um dies zu verstehen, müssen Sie zwei wichtige Details beachten. Zunächst initialisieren wir in Zeile sechs die Variable mit dem Wert zehn. Wenn die WHILE-Anweisung die Bedingung, d. h. den Wert der in Zeile 6 gesetzten Variablen, auswertet, stellt sie fest, dass die Bedingung erfüllt ist, und löst damit die Schleife aus. Aber, und das ist der zweite wichtige Punkt, bevor wir den Wert in Zeile 13 auf dem Terminal ausgeben, vermindern wir die Variable info in Zeile 12 um eins. Aus diesem Grund läuft der Countdown von neun bis null. Die Schleife wird bei Null beendet, da Null als boolescher falscher Wert gilt.

Was würde aber passieren, wenn wir die Variable info in Zeile 12 nicht vermindern, sondern um eins erhöhen würden? Würde die Schleife in einen unendlichen Zyklus übergehen? Das ist eine ausgezeichnete Frage, liebe Leserin, lieber Leser, mit der Sie selbst experimentieren können, um die Ergebnisse zu sehen. Bevor wir es jedoch testen, sollten wir zunächst verstehen, warum die Schleife in diesem speziellen Fall nicht in einen unendlichen Zyklus eintritt.

Entgegen der allgemeinen Vorstellung, dass sich Zahlen von negativ unendlich bis positiv unendlich erstrecken, funktionieren die Dinge beim Rechnen anders. Jeder Wert, den ein Computer ausdrücken kann, hat eine Ober- und Untergrenze. Diese Grenze wird durch die Bitbreite des verwendeten Variablentyps bestimmt. Wir haben dies bereits in einem früheren Artikel erörtert. Aufgrund dieser Einschränkung (und bedenken Sie, dass einige Sprachen keine derartige Einschränkung vorsehen, was hier jedoch den Rahmen sprengen würde) wird die Schleife irgendwann abgebrochen, wenn die Wertänderung dafür sorgt, dass die Variable schließlich Null erreicht. Unabhängig davon, wie lange es dauert, wird es irgendwann zu Ende sein. Die WHILE-Schleife birgt in diesem Szenario jedoch einige besondere Herausforderungen. Um in diesem Stadium Verwirrung zu vermeiden, werden wir diese Diskussion auf ein anderes Mal verschieben. Höchstwahrscheinlich im nächsten Artikel.

Das ist im Grunde alles, was man über die WHILE-Anweisung sagen kann. Es gibt jedoch ein zusätzliches Detail, das an dieser Stelle erläutert werden sollte. Wenn wir wollen, dass ein Code kontrolliert abläuft, vor allem wenn es sich um Schleifen handelt, fügen wir oft eine sekundäre Exit-Bedingung zusätzlich zu der üblichen Abbruchbedingung ein. Dies dient als Ausfallsicherung und ermöglicht es uns, das Ende der Schleife zu erzwingen, damit das Programm seine normale Ausführung fortsetzen kann.

Da MQL5 eine ereignisgesteuerte Sprache ist (ein Thema, auf das wir später noch näher eingehen werden), ist es unüblich, Schleifen zu erstellen, die unendlich lange auf ein Ereignis warten. Dieses Verhalten ist eher typisch für Sprachen wie C oder C++, die nicht von Natur aus ereignisgesteuert sind.

In der Praxis verwenden wir häufig Schleifen, um eine kontrollierte Pause in einer Anwendung zu schaffen. Diese Pause bleibt für einen bestimmten Zeitraum oder bis zum Eintreten eines bestimmten Ereignisses aktiv. Es ist jedoch nicht sehr üblich, eine WHILE-Schleife direkt für diesen Zweck zu verwenden. Der Grund dafür ist, dass eine WHILE-Schleife nur dann ausgeführt wird, wenn die Anfangsbedingung erfüllt ist. Und in vielen Fällen ist das nicht ganz das, was wir brauchen.

In Fällen, in denen ein Notausgang erforderlich ist, ist eine WHILE-Schleife jedoch oft die bessere Wahl. Wenn die Bedingung von Anfang an als falsch bewertet wird, wird die Schleife nicht ausgeführt. Dies ist von entscheidender Bedeutung, denn in vielen Fällen kann die Schleifenroutine direkt beeinflussen, ob die Schleife auf der Grundlage bestimmter Kriterien weiterlaufen soll oder nicht. Wir werden dieses Konzept bei der Erörterung der DO-WHILE-Schleife näher untersuchen.

Gehen wir nun wie folgt vor. Wir werden absichtlich eine Schleife erzeugen, die theoretisch unendlich sein kann. Wir werden jedoch auch eine Bedingung einführen, die es ermöglicht, das Programm zu beenden. Dieser Ansatz ist im Folgenden dargestellt.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     char info = 5;
07. 
08.     Print("Press ESC to finish counting...");
09. 
10.     while (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE))
11.     {
12.         info = info - 1;
13.         Sleep(200);
14.         Print(__FUNCTION__, " : ", info);
15.     }
16. 
17.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
18. }
19. //+------------------------------------------------------------------+

Code 04

In Code 04 haben wir in Zeile 10 eine Schleife, die theoretisch unbegrenzt ausgeführt werden könnte. Dies geschieht jedoch nicht, wenn der Nutzer die ESC-Taste drückt. Ein wichtiges Detail ist, dass die Warnmeldung nur einmal angezeigt wird, bevor die Schleife beginnt. Wenn der Nutzer diese Meldung, die auf dem Terminal ausgedruckt wird, übersieht, kann dies zu Verwirrung führen. Im Terminal sehen Sie eine Ausgabe ähnlich der untenstehenden.

Abbildung 03

Beachten Sie, dass der Wert der Variablen „info“ dieses Mal auf Null gesetzt wurde, die Schleife jedoch fortgesetzt wurde. Dies geschieht, weil die Bedingung, die bestimmt, wann die Schleife beendet wird, nun davon abhängt, ob die ESC-Taste gedrückt wird. Mit anderen Worten, das Programm wartet auf ein Ereignis, bevor es die Ausführung fortsetzen kann. Ein weiterer häufiger Test in MQL5-Skripten ist die Prüfung, ob das Skript unterbrochen wurde. Dazu ersetzen wir einfach Zeile 10 in Code 04 durch die folgende Zeile.

    while ((!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)) && (!IsStopped()))

Mit dieser kleinen Änderung kann die Schleife in Code 04 auf zwei Arten beendet werden: durch Drücken der ESC-Taste und durch manuelles Entfernen des Skripts aus dem Diagramm. Ganz einfach, nicht wahr, mein lieber Leser? Es gibt keinen Grund, sich vor Schleifen zu fürchten. Es gibt jedoch noch ein Problem: Die Warnmeldung in Zeile 8 könnte bei der Ausführung leicht übersehen werden. Das bedeutet, dass der Nutzer möglicherweise nicht weiß, dass das Drücken von ESC auch die Anwendung beendet.

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, Zeile 8 innerhalb der Schleife zu platzieren. Anstatt jedoch unsere WHILE-Schleife direkt zu ändern, sollten wir diese Gelegenheit nutzen, um die DO-WHILE-Schleifenvariante zu untersuchen. Aus Gründen der besseren Übersichtlichkeit werden wir dies in einem neuen Kapitel behandeln.


Die DO...WHILE-Schleife

Ich konnte nicht widerstehen, in der Überschrift dieses Abschnitts ein wenig Humor zu zeigen. Aber in gewisser Weise beschreibt es perfekt die DO-WHILE-Schleife. Obwohl es sich um eine einzelne Anweisung handelt, funktioniert sie eher wie ein Paar, genau wie IF ELSE. Doch hier liegen die Dinge ein wenig anders.

Aus der vorangegangenen Diskussion wissen Sie vielleicht noch, dass eine WHILE-Schleife nur dann ausgeführt wird, wenn ihre Bedingung wahr ist. Der entscheidende Unterschied besteht darin, dass die DO-WHILE-Schleife ihre Routine mindestens einmal ausführt, unabhängig davon, ob die Bedingung anfangs wahr oder falsch ist. Das liegt daran, dass die Anweisung DO (was wörtlich „MACH“ bedeutet) vor der WHILE-Bedingung (was „SO LANGE“ bedeutet) steht. Dadurch wird sichergestellt, dass die Routine innerhalb der Schleife mindestens einmal abläuft, bevor die Bedingung geprüft wird. Dieses Verhalten kann in bestimmten Szenarien besonders nützlich sein, da es uns ermöglicht, die Funktionsweise bestimmter Routinen besser zu steuern, insbesondere wenn sie mindestens einmal ausgeführt werden müssen, bevor eine Bedingung ausgewertet wird.

Um dies zu veranschaulichen, ändern wir den Code 04 so, dass die Warnmeldung regelmäßig erscheint. Wir könnten dies zwar direkt in Code 04 erreichen, aber nehmen wir an, dass das Duplizieren von Zeile 8 keine Option war. Noch wichtiger ist, dass wir sicherstellen wollen, dass die Schleife mindestens einmal ausgeführt wird, unabhängig von allen vorherigen Bedingungen.

Daraus ergibt sich der folgende Code:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     char info = 10;
07. 
08.     do
09.     {
10.         if (((info / 5) * 5) == info) Print("Press ESC to finish counting...");
11.         info = info - 1;
12.         Sleep(200);
13.         Print(__FUNCTION__, " : ", info);
14.     }while (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE));
15. 
16.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
17. }
18. //+------------------------------------------------------------------+

Code 05

Wenn Sie diesen Code ausführen, erhalten Sie ein ähnliches Bild wie das folgende.

Abbildung 04

Wir haben es hier mit einigen Dingen zu tun, die in gewissem Sinne recht interessant zu verstehen sind. Der Grund dafür ist, dass einige Aktionen in Code 05 auf den ersten Blick unlogisch erscheinen mögen. Wenn Sie aber gut aufgepasst und die zuvor veröffentlichten Artikel gewissenhaft studiert haben, werden Sie sie relativ schnell verstehen.

Nun, lassen Sie uns herausfinden, was hier los ist und warum die Meldung, die Sie auffordert, ESC zu drücken, jetzt von Zeit zu Zeit erscheint. Wie Sie sehen, wird die Prüfung, ob die Prozedur innerhalb der Schleife weiter ausgeführt werden soll, in Zeile 14 durchgeführt, und die gesamte Schleifenprozedur wird mindestens einmal ausgeführt. Es ist nun hoffentlich klar, warum das DO-Element in dieser Kombination mit dem WHILE-Element koexistiert.

Hören Sie gut zu, was ich Ihnen jetzt erklären werde, denn es ist sehr wichtig. Die Idee ist hier die gleiche wie bei der WHILE-Anweisung. Die Schleife wird so lange ausgeführt, bis der Ausdruck der WHILE-Anweisung falsch wird. Aber woher wissen Sie, wo die Schleife beginnt? Wenn Sie die achte Zeile löschen, wissen Sie nicht genau, wo die Schleife beginnt. Und was noch schlimmer ist, die Prozedur, die in der Schleife sein muss, die von Zeile 10 bis Zeile 13 geht, wird NICHT als Prozedur wahrgenommen, sondern als gewöhnlicher Code.

Die WHILE-Anweisung in Zeile 14 wird tatsächlich eine Schleife sein. Die Prozedur wird jedoch leer sein, da innerhalb der Schleife keine weiteren Befehle ausgeführt werden. Er blieb einfach stehen und wartete darauf, dass die ESC-Taste gedrückt wurde, um ihn zu beenden.

Nur aufgrund der Kombination der Elemente DO und WHILE können sowohl der Compiler als auch andere Programmierer feststellen, dass die Schleife in Zeile 8 beginnt und in Zeile 14 endet. Das mag alles etwas verwirrend erscheinen, aber es macht viel mehr Sinn, wenn wir das DO-Element aus Zeile 8 entfernen, wodurch der Code etwa so aussehen wird:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     char info = 10;
07. 
08. 
09.     {
10.         if (((info / 5) * 5) == info) Print("Press ESC to finish counting...");
11.         info = info - 1;
12.         Sleep(200);
13.         Print(__FUNCTION__, " : ", info);
14.     }while (!TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE));
15. 
16.     Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
17. }
18. //+------------------------------------------------------------------+

Code 06

Wie wir sehen können, ist das Ergebnis aufgrund dieser kleinen Änderung im Code, die leicht unbemerkt bleiben könnte, völlig anders. Um die Dinge klarer zu machen, werde ich kein Bild verwenden, sondern stattdessen mit dem folgenden GIF zeigen, was passiert.

Animation 01

Hier liegt eine der Gefahren bei der Erstellung von Schleifen, die nicht richtig beachtet werden. Beachten Sie, dass wir nicht mehr das gleiche Verhalten wie in Abb. 04 sehen. Hier wurde das, was eigentlich der Schleifenkörper sein sollte, wie eine normale Codesequenz ausgeführt. An dieser Stelle wurde jedoch angehalten, und der Code trat in die in Zeile 14 gezeigte Schleife ein. Wenn also die Abbruchbedingung der Schleife von einer Aktion innerhalb der Schleifenroutine abhängt, würde diese Aktion nie stattfinden. Folglich würde eine Schleife, die für eine Ausstiegsbedingung vorgesehen war, niemals beendet werden, was zu der gefürchteten Endlosschleife führt.

Lassen Sie uns nun analysieren, wie und warum die Meldung in Zeile 10 in Intervallen gedruckt wird. Um dies zu verstehen, müssen wir den Ausdruck innerhalb der IF-Anweisung in Zeile 10 untersuchen. Während dieser Ausdruck für einen Menschen vielleicht keinen Sinn ergibt, ist er für einen Computer völlig logisch, insbesondere in einer stark typisierten Sprache wie MQL5.

In einem anderen Artikel wurden bereits mathematische Berechnungen in Programmiersprachen behandelt. Die scheinbar unsinnige Operation, den Wert der Variablen info durch eine Zahl zu dividieren und das Ergebnis dann sofort mit derselben Zahl zu multiplizieren, mag jedoch sinnlos erscheinen. Ich empfehle Ihnen jedoch dringend, die vorherigen Artikel zu lesen, wenn Sie gerade erst mit dem Programmieren beginnen. Der Grund dafür ist, dass die Durchführung dieser Berechnung ein Ergebnis liefern kann, das entweder mit dem ursprünglichen Wert in „info“ übereinstimmt oder davon abweicht. Wenn die Werte übereinstimmen, wird die Meldung gedruckt. Wenn sie anders sind, wird es nicht sein.

Da dieser Code als Anhang verfügbar sein wird, können Sie ihn genauer studieren. Wichtig ist, dass Sie bei der Division und Multiplikation denselben Wert verwenden und immer erst dividieren und dann multiplizieren. Seien Sie jedoch vorsichtig bei der Verwendung von Ganzzahlwerten. Fließkommazahlen funktionieren aufgrund bestimmter Faktoren, auf die wir später noch eingehen werden, nicht.

Zum Abschluss dieses Themas betrachten wir das Flussdiagramm für die DO-WHILE-Schleife. Es ist unten dargestellt:

Abbildung 05

Wie Sie sehen, ist es nicht so kompliziert, wie es auf den ersten Blick erscheinen mag, bevor Sie es in Aktion sehen. Das Verständnis des Ausführungsablaufs ist weitaus wichtiger als das bloße Auswendiglernen von Befehlen und Syntax. Wenn Sie erst einmal begriffen haben, wie der Ausführung ablaufen, werden Sie klarer denken können. Mit fortgesetzter Übung können Sie erkennen, wie jede kleine Entscheidung im Ablauf das Endergebnis beeinflusst. Mit der Zeit werden Sie natürlich Programmierkenntnisse entwickeln, auch als Hobbyist. Sie werden so kompetent, dass Sie andere Programmiersprachen erlernen können, ohne auf eine einzige beschränkt zu sein.


Abschließende Überlegungen

In diesem Artikel habe ich versucht, dieses Thema so zugänglich und einfach wie möglich darzustellen. Für viele Programmieranfänger sind Schleifen ein Alptraum. Ich hoffe jedoch, gezeigt zu haben, dass man mit Geduld, Konzentration und sorgfältiger Aufmerksamkeit, egal ob man den Code selbst implementiert oder die Arbeit eines anderen Programmierers studiert, einige wirklich interessante Dinge erreichen kann. Dies sind die Dinge, die äußerst nützlich sein können.

Wenn sie richtig und effizient eingesetzt werden, können Schleifen nicht nur bei der Strukturierung von Bedingungen, sondern auch bei der Vereinfachung der Logik viel Zeit sparen. Die ersten Beispiele in diesem Artikel, in denen ich die Fakultät einer Zahl ohne Schleifen und nur mit sequentiellen Aufrufen demonstriert habe, können in einer viel kompakteren und daher effizienteren Weise umgeschrieben werden. Dies wird im Folgenden veranschaulicht, um zu zeigen, wie Schleifen elegante und praktische Lösungen ermöglichen.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     uchar counter = 0;
07.     ulong value = 1;
08. 
09.     while (counter < 5)
10.     {
11.         counter = counter + 1;
12.         value = value * counter;
13.     }
14. 
15.     Print("Factorial of ", counter, " => ", value);
16. }
17. //+------------------------------------------------------------------+

Code 07

Versuchen Sie, Code 02 so zu ändern, dass er eine Schleife anstelle der sequentiellen Aufrufe zwischen den Zeilen 6 und 10 verwendet. Wenn Sie keine Möglichkeit finden, dies zu tun, machen Sie sich keine Sorgen. Wir werden im nächsten Artikel mehr über Schleifen sprechen, da wir noch nicht alles behandelt haben. Fangen Sie also an zu üben, bevor es zu spät ist.

Übersetzt aus dem Portugiesischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/pt/articles/15375

Beigefügte Dateien |
Anexo.zip (1.64 KB)
Neuronale Netze im Handel: Hierarchische Vektortransformer (Letzter Teil) Neuronale Netze im Handel: Hierarchische Vektortransformer (Letzter Teil)
Wir fahren fort mit der Untersuchung der Methode der hierarchischen Vektortransformation. In diesem Artikel werden wir die Konstruktion des Modells abschließen. Wir werden es auch anhand echter historischer Daten trainieren und testen.
Entwicklung eines Replay-Systems (Teil 62): Abspielen des Dienstes (III) Entwicklung eines Replay-Systems (Teil 62): Abspielen des Dienstes (III)
In diesem Artikel befassen wir uns mit dem Problem eines Übermaßes an Ticks, der die Anwendungsleistung bei der Verwendung echter Daten beeinträchtigen kann. Dieses Übermaß beeinträchtigt häufig das korrekte Timing, das erforderlich ist, um einen einminütigen Balken im entsprechenden Fenster zu erstellen.
Neuronale Netze im Handel: Hierarchische Vektortransformer (HiVT) Neuronale Netze im Handel: Hierarchische Vektortransformer (HiVT)
Wir laden Sie ein, die Methode Hierarchical Vector Transformer (HiVT) kennenzulernen, die für die schnelle und genaue Vorhersage von multimodalen Zeitreihen entwickelt wurde.
Von der Grundstufe bis zur Mittelstufe: IF ELSE Von der Grundstufe bis zur Mittelstufe: IF ELSE
In diesem Artikel geht es um die Arbeit mit dem Operator IF und seinem Pendant ELSE. Diese Anweisung ist die wichtigste und aussagekräftigste, die es in jeder Programmiersprache gibt. Trotz ihrer einfachen Handhabung kann sie jedoch manchmal verwirrend sein, wenn man keine Erfahrung mit ihrer Verwendung und den damit verbundenen Konzepten hat. Der hier dargestellte Inhalt ist ausschließlich für Bildungszwecke bestimmt. Die Anwendung sollte unter keinen Umständen zu einem anderen Zweck als zum Erlernen und Beherrschen der vorgestellten Konzepte verwendet werden.