Was ist in einer for-Schleife möglich?

Lesezeit: 9 Minuten

Also ging ich heute zu einem Interview und eine der Fragen war die folgende (C#-Kontext).

//Print the output for the following code:
for (int i = 10, j = 0; j <= 10; j++, i--)
{
    if (i > j)
        Console.WriteLine(j.ToString());
}

Ich habe noch nie zuvor ein solches Konstrukt gesehen und meine Kollegen gefragt, 4 von 5 an meinem Arbeitsplatz wussten es auch nicht (Vielleicht eher eine Reflexion über uns, aber ich schweife ab). Mit etwas grundlegender Logik konnte ich die Frage richtig beantworten, aber dieses Wissen hat mein Verständnis davon, wie for-Schleifen strukturiert werden können, radikal verändert.

Also ich denke, meine Frage läuft darauf hinaus.

  1. Implementieren alle auf C-Syntax basierenden Sprachen diese Funktionalität? IE: C, C++, Java, Javascript usw.
  2. Woher kommt diese Syntax?
  3. Gibt es noch andere “unbekannte” Strukturen, die eine for-Schleife annehmen kann?
  4. Wird das Schreiben von Code wie oben als schlechte Praxis angesehen, wenn man bedenkt, wie schwer er zu lesen ist?
  5. Gibt es gute Beispiele aus der Praxis für eine solche Struktur? erforderlich?

  • Ich bin 15 Jahre alt und benutze es manchmal für meine eigenen Projekte 😀 Für mich klingt es seltsam, dass Ihre Kollegen es nicht auch wussten.

    – Martin Courteaux

    2. Juni 2011 um 8:10 Uhr

  • @Coline : es ist noch eine Frage, ob man es verwenden sollte …

    – Henk Holtermann

    2. Juni 2011 um 9:55 Uhr

  • Kannst du tun j.ToString()? Ich dachte seitdem j war ein Primitiv, Sie konnten nicht auf eine Methode zugreifen, die nicht existiert. Ich nehme an, C# ist anders.

    – Ladaghini

    2. Juni 2011 um 11:43 Uhr

Benutzer-Avatar
Phoxie

for (statement1; statement2; statement3)
{
     /* body */
}

(1) Zuerst die statement1 wird ausgeführt.

(2) Weiter statement2 wird ausgeführt.

(3) Wenn die Bewertung von statement2 wahr ist, dann wird der Körper ausgeführt

(4) Dann statement3 wird ausgeführt.

(5) Ab Schritt (2) wiederholen

          |                  +<-----------------+
          |                  |                  ^
          V                  V                  |
 for (  (s1); -------->(s2 true? | false?);    (s3) )
 {                           |       |          ^
                             |       |          |
                             |       |          |
                             V       |          |
                          (body)-----|--------->+
 }                                   |
                                     |
                                     V
                                 (come out)

Die Struktur, die Sie gezeigt haben, ist die gleiche normale Struktur wie oben. Das statement n könnte jede Aussage sein. In Ihrem Beispiel haben Sie durch getrennt Komma-Operatoren in statement1 und statement3. Sie können eine beliebige Anzahl von Anweisungen durch Komma-Operatoren trennen.

Allgemein for Schleifen werden mit verwendet statement1 mit Initialisierung, da sie nur einmal ausgeführt wird. Das statement2 wird für die Prüfung der Endbedingung der Schleife verwendet, da der Bewertungswert dieser Anweisung verwendet wird, um zu entscheiden, ob in den Hauptteil des Ausbruchs eingetreten werden soll. Und die statement3 wird zur Aktualisierung der Schleifenterminierungsvariable verwendet, da sie nach dem Hauptteil ausgeführt wird. Aber im Allgemeinen könnten sie in irgendeiner Weise verwendet werden.

Zuerst statement1 ist i=10, j=0; Dadurch werden die Variablen initialisiert. Weiter im statement2 ist j <= 10 Wenn dies wahr ist, wird der Körper ausgeführt. Nachdem der Körper hingerichtet wurde, statement3 welches ist i--,j++ wird ausgeführt. Die Schleife wird iteriert 11 mal 0 zu 10. Wird aber gedruckt 5 Zeiten, wie an einem Punkt i und j wird gleich und die if (i > j) wird als falsch bewertet.

BEARBEITEN
Hier ist ein Beispiel, wo es verwendet werden könnte, nicht sehr praktisch, aber eine Beispielanwendung, um nach einer Palindrom-Kette zu suchen.

  int i, j, n, flag;
  char str[128];

  printf ("\nEnter string: ");
  scanf ("%s", &str);
  n = strlen (str);


for (flag=1, i=n-1, j=0; j<n/2; j++, i--)
{
  if (str[i] != str[j])
  {
    flag = 0;
    break;
  }
}

if (flag)
 printf ("\n\"%s\" is a palindrome");
else
 printf ("\n\"%s\" is not a palindrome");

Wir sollten immer versuchen, Code zu schreiben, der einfach zu lesen ist und keine Verwirrung stiftet. Dies hilft sowohl dem Codeschreiber als auch anderen, die den Code lesen.

  • @Martijn, ich helfe dir, denn ich stimme dir im ‘nice ascii’-Teil zu.

    – Gary Tsui

    2. Juni 2011 um 8:44 Uhr

  • Danke dafür, aber es wäre gut zu wissen, was die Ursache für die Ablehnung ist, ich würde es dann korrigieren.

    – phoxie

    2. Juni 2011 um 8:45 Uhr

  • gibt es nichts nettes außer dem ASCII ? Ich denke, das Hauptproblem des Fragestellers war die durch Kommas getrennte Syntax in den Anweisungen, die ich versucht habe, im ersten Absatz nach dem ‘nice ascii’ klarzustellen.

    – phoxie

    2. Juni 2011 um 8:47 Uhr

  • Phonix Kennen Sie das? ASCII-Fluss? Es wird Ihnen helfen, ein ASCII-Diagramm zu zeichnen … (PS: Wählen Sie mich nicht zurück. Ich stimme ab, nachdem ich die Antworten gelesen habe. Ich habe es komplett gelesen)

    – Grijesh Chauhan

    2. August 2013 um 7:53 Uhr

  • Ja, die Seite gesehen, und sie ist interessant. Aber ich habe mir angewöhnt, manuell zu zeichnen. Verwenden Sie für komplexe Diagramme kein ASCII. (Ja, ich kenne die SO-Kultur und halte mich daran.)

    – phoxie

    2. August 2013 um 7:58 Uhr

Benutzer-Avatar
ColinE

  1. Java und C# haben beide dieselbe Syntax
  2. Die Syntax stammt wahrscheinlich von C/C++, das die ‘Wurzel’ von Java & C# ist.
  3. Ja, Sie können auch null Initialisierer und Endbedingungen für Ihre for-Schleife haben.
  4. Ob es sich um eine schlechte Praxis handelt oder nicht, hängt wirklich davon ab, wie es verwendet wird. Sie können mit dieser Technik ziemlich kryptischen Code erstellen, aber es bedeutet nicht, dass es bei richtiger Anwendung vollkommen akzeptabel ist.
  5. Das bezweifle ich!

  • Schlag mich um Sekunden! Der einzige Teil des Codes, den ich überraschend finde, ist, dass Sie Argumente trennen können, die am Ende durch Kommas erhöht werden. Die anfängliche Koma-Syntax ist Standard für die Variableninitialisierung iirc.

    – Johannes Nikolaus

    2. Juni 2011 um 8:05 Uhr


  • 4. nicht wahr? Bei allem Respekt vor Maxim und seinen Kollegen, sie waren unwissend. Jetzt, wo sie es gesehen haben, werden sie nicht mehr darum kämpfen, es zu verstehen, bedeutet das also, dass es keine schlechte Übung mehr ist? Ich verstehe, dass es etwas schlecht ist, Konstrukte zu verwenden, die schwer zu lesen sind, selbst wenn Sie sie kennen, aber ich glaube nicht, dass Kommas in for-Schleifen dazu gehören. Es erscheint mir falsch, dies lieber zu vermeiden, als Ihre Kollegen die Sprache lernen zu lassen.

    – Steve Jessop

    2. Juni 2011 um 8:49 Uhr


  • Ihre Nr. 4 ist bestenfalls mehrdeutig. Dass bestimmten Code kann aufgrund der Verwendung als schlecht angesehen werden, nicht wegen der Syntax. Im Allgemeinen ist die Verwendung mehrerer Variablen sehr akzeptabel und einfach zu verstehen (falls zutreffend).

    – Wiz

    2. Juni 2011 um 8:50 Uhr


  • Wiz macht einen guten Punkt – in diesem Fall wäre es klarer, nur eine Variable zu verwenden (z j) in der Schleife und definieren Sie die andere als int i = 10 - j. Also, OK, dieser Code ist ein wenig fummelig, möglicherweise habe ich “Code wie oben” falsch interpretiert, um “jeden Code mit Kommas darin” zu meinen, dh das, was für Maxim neu war, und nicht “diese bestimmte Beziehung zwischen den Variablen “.

    – Steve Jessop

    2. Juni 2011 um 8:55 Uhr

Benutzer-Avatar
Bohemien

In C und Java for Schleifen können Sie eine unbegrenzte (oder null) Anzahl von kommagetrennten Initialisierern (des gleichen Datentyps) und End-of-Loop-Aktionen angeben.

Der Initializer-Abschnitt ist wirklich nur eine Java-Anweisung; Java-Variablendefinitionen können gruppiert werden, wenn sie vom gleichen Typ sind, d. h.:

int i = 0;
int j = 0;

ist äquivalent zu:

int i = 0, j = 0;

Sie können im End-of-Loop-Abschnitt tun, was Sie möchten – eine beliebige Anzahl von Anweisungen, die durch Kommas getrennt sind.

Seit Java 5 gibt es auch die foreach Syntax, zB:

List<String> list;
for (String element : list) {
    // do something with the variable element
}

Die Syntax funktioniert mit Iterable -Typen, zu denen Arrays und Sammlungen gehören.

  • Ich dachte, ich sollte nur darauf hinweisen, dass die mehrfache Initialisierungssyntax mit dem Komma nichts mit dem Kommaoperator zu tun hat, der in der ursprünglichen Frage zu sehen ist. Ich habe eine Weile gebraucht, um zu erkennen, welche Teile der Frage Sie beantwortet haben :).

    – Aib

    1. August 2011 um 10:21 Uhr


  1. Java unterstützt dies für die Struktur. In anderen Sprachen wie C können Sie anstelle einer Bedingungsklausel einen beliebigen Ausdruck verwenden. Diese Klausel muss nicht verwandt sein und könnte andere Variablen verwenden.

    for({declaration-clause}; {condition-clause}; {expression-clause})
    
  2. Die Syntax ist nur eine Erweiterung der Deklarations- und Ausdrucksnotationen in C.

    int i = 10, j = 0; // a declaration
    j++, i--; // an expression.
    
  3. Zu viele, um sie zu erwähnen.

  4. Es kann eine schlechte Praxis sein, wenn Sie nicht feststellen können, was der Code bedeutet. In Ihrem Fall konnten Sie es herausfinden, auch wenn Sie es nicht so geschrieben hätten.
  5. Eine for-Schleife ist nie erforderlich Sie können es immer durch eine While-Schleife ersetzen, also nein.

Nach meinen Erfahrungen und Recherchen ist diese Art von „Bedingungskonstrukt“ sehr häufig in der Bildverarbeitung zu sehen, sagen wir (wirklich, sagen wir), Sie müssen Pixel zwischen zwei Bildern in (sagen wir wieder) entgegengesetzten Richtungen vergleichen. Oder durchqueren Sie sogar Nachbarn in entgegengesetzten Richtungen. Ein weiteres Beispiel für diese Art von “Bedingungskonstrukt”, wenn Sie ein 32-Bit-BMP in 24-Bit oder umgekehrt konvertieren müssen. (nur dass das Inkrement bitweise unterschiedlich wäre wie i=i+4, j=j+3).

Als Antwort auf 5 ist eine häufige Verwendung etwa so (in C):

for (size_t pos = 0, end = strlen(something); pos < end; ++pos) {
    if isspace((unsigned)(something[pos])) {
        puts("contains whitespace");
        break;
    }
}

Anstatt von:

for (size_t pos = 0; pos < strlen(something); ++pos) { ... }

strlen könnte jede Operation sein, die im Verhältnis zur Schleife teuer ist, so dass es sinnvoll ist, sie hochzuziehen. Zum strlen im Speziellen kann sein Der Optimierer könnte dies automatisch tun, aber im Allgemeinen, wenn der Compiler nicht weiß, was der Aufruf tut, und Sie ihn in die Schleifenbedingung setzen, muss er ihn jedes Mal auswerten, weil er nicht weiß, ob er sich ändern wird.

Natürlich könntest du stattdessen auch schreiben:

const size_t end = strlen(something);
for (size_t pos = 0; pos < end; ++pos) { ... }

Es ist also sicherlich nicht unbedingt erforderlich, dass die zusätzliche Variable in der for-Anweisung definiert wird, und es gibt wohl einen kleinen Vorteil beim Erstellen end const (oder final) sowieso, die Sie durch die Definition verlieren pos und end zusammen. Einige Leute ziehen es jedoch vor, dass die “Schleifenvariablen” (in diesem Fall einschließlich einer “Schleifenkonstante”) alle in der for-Anweisung definiert werden, da sie dazu “gehören”.

Außerdem, bevor jemand darauf hinweist, brauchen Sie in meinem C-Beispiel überhaupt keine Indizierung:

for (const char *ptr = something; *ptr; ++ptr) { 
    if isspace((unsigned)*ptr) { ... }
}

aber wir können so tun, als hätten wir eine Aufgabe, bei der wir mit einem berechneten Endpunkt iterieren werden …

Benutzer-Avatar
Jeppe Stig Nielsen

Im C # -Kontext (den meine Antwort nur berücksichtigen wird) gibt es keine Komma-Operator wie in C++ und C, daher ist der Verweis auf den Kommaoperator für C# technisch nicht korrekt.

Aber das C# for Die Anweisung war immer noch darauf ausgelegt, Konstruktionen zuzulassen, die man bereits aus C++ kannte.

Die genauen Regeln sind in zu finden die Sektion Das for Aussage in dem C#-Sprachspezifikation. Wir sehen, dass die dritte und letzte “Komponente” in a for (;;) Aussage ist definiert als a Anweisungsausdruckslisteund ein Anweisungsausdrucksliste ist rekursiv als Liste von Anweisungsausdrücken definiert, die durch das Zeichen getrennt sind , (Komma).

Das erklärt also die j++, i-- Teil.

Wir sehen auch, dass der erste Teil in der for (;;) kann entweder a lokale Variablendeklaration oder ein Anweisungsausdrucksliste. Das erste kann auch ein Komma enthalten. Die Erklärung int i = 10, j = 0; ist als unabhängige Anweisung erlaubt (d. h. nicht innerhalb for) und muss als a interpretiert werden lokale Variablendeklaration.

1082380cookie-checkWas ist in einer for-Schleife möglich?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy