Warum hört es nicht auf? [geschlossen]


95

Ihre Aufgabe: Ein Programm zu schreiben, das sich offensichtlich beenden sollte, dies jedoch niemals (im Ausmaß eines Computerabsturzes) tut. Lassen Sie es so aussehen, als ob es eine einfache Aufgabe erfüllen sollte: Zahlen hinzufügen, etwas drucken, ... Aber es gerät einfach in eine Endlosschleife.

Versuchen Sie, Ihr Programm sehr klar und einfach zu gestalten, während es tatsächlich in einer unvorhergesehenen Schleife hängen bleibt. Wähler: Beurteilen Sie die Antworten danach, wie "hinterhältig" sie sind!

Dies ist ein Beliebtheitswettbewerb: Sei kreativ!


6
Könnte jemand bitte erklären, was ich tun kann, um die Frage weniger umfassend zu machen? Ich bin neu hier. Danke!
Nummer 9

6
Dies wird nur eine große Liste von Tippfehlern und Anfängerfehlern sein, die Schleifen verursachen.
Bill Woodger

Interessante Frage, aber ich habe noch keine wirklich kreativen Antworten gesehen. Ich verspreche jedem, der keine Schleifen oder offensichtliche Rekursion verwendet, Stimmen zu gewinnen!
ApproachingDarknessFish

14
Ich weiß nicht, ob dies zählt, aber mein Microsoft Office verhält sich im Moment genau so.
Level River St

1
Ich stimme dafür, diese Frage als Off-Topic zu schließen, da hinterhältige Herausforderungen hier nicht mehr zum Thema gehören. meta.codegolf.stackexchange.com/a/8326/20469
cat

Antworten:


185

Javascript

var x=prompt('Enter a value under 100');
while (x != 100) {
  x=x+1;
}
console.log('End!');

prompt () gibt einen String zurück und die Schleife hängt das Zeichen '1' an, es wird niemals 100 sein.


13
Du hast mich mit dem hier erwischt ... die (tatsächlich) höher bewerteten Beispiele missbrauchen alle nur die Syntax ... aber das ist schön!
Bwoebi

4
Chrome auf Kubuntu wurde nicht mehr reagiert, hängen alles und ich musste hart zurücksetzen :)
Sergey Telshevsky

4
@ Vlakarados: Python führt die implizite Typkonvertierung, die Javascript durchführt, nicht durch. In Python löst der entsprechende Code mit raw_inputoder Python 3 inputa aus TypeError.
user2357112

2
Es wird nicht überprüft, ob der Wert tatsächlich unter 100 liegt.
Daher wird der Vorgang

1
@Sankalp, der +Operator hier ist die String-Verkettung, nicht die Addition.
Michael M.

87

C

Nur ein einfaches Beispielprogramm, das die drei verschiedenen Arten von while-Schleifen in C veranschaulicht.

int main() {

    int x = 0;

    // Multi-statement while loops are of the form "while (condition) do { ... }" and
    // are used to execute multiple statements per loop; this is the most common form
    while (x < 10) do {
        x++;
    }

    // x is now 10

    // Null-statement while loops are of the form "while (condition) ;" and are used
    // when the expression's side effect (here, decrementing x) is all that is needed
    while (x-- > 0)
        ; // null statement

    // x is now -1

    // Single-statement while loops are of the form "while (condition) statement;"
    // and are used as a shorthand form when only a single statement is needed
    while (x > -10)
        x--;

    // x is now -10

    return 0;
}

While-Schleifen haben vor der öffnenden geschweiften Klammer kein "do". Dies erzeugt tatsächlich eine do-while-Schleife innerhalb der (x <10) -Schleife, die durch die folgende "null-Anweisung" while-Schleife beendet wird. Da x innerhalb der Schleife inkrementiert und dann im Zustand der do-while-Schleife dekrementiert wird, wird die innere Schleife niemals beendet, und die äußere Schleife auch nicht. Die "single-statement" -Schleife am Ende wird nie erreicht.

Wenn Sie immer noch verwirrt sind, schauen Sie hier (extern gehostet, weil codegolf.SE keine Codeblöcke in Spoilern mag).


8
Haha, ich habe das herausgefunden, bevor ich mir den Lösungsspoiler angesehen habe. : P
Joe Z.

54
Warum haben Sie eine so hervorragende Gelegenheit verpasst, den Operator "gehe zu" zu verwenden? (x --> 0)
CorsiKa

2
Oh wow. Das ist wunderbar böse. Hat mich viermal durchgelesen, um es zu finden.
Patrick M

1
@JoeZ. Viel zu einfach. Die am besten bewertete Lösung war besser. Den habe ich nicht gefunden.
Anonymes Pi

3
@Hat Guy, Bash hat die Syntax for; do und while; do, damit ich sehen kann, dass die Leute davon abschrecken, auch wenn sie mit Nicht-C / C ++ - Sprachen vertraut sind. tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html
nemec

85

JavaScript

var a = true;
(function() {
  while(!a){}
  alert("infinite");
  var a = true;
})();

Variables Heben: JavaScript greift tatsächlich auf meine zweite Definition von zu var a = true;, deklariert sie oben in der Funktion als var a;und ändert meine Zuordnung zur a = true;Bedeutung aundefiniert sich zum Zeitpunkt des Eintritts in die while-Schleife.


3
Könnten Sie eine bessere Erklärung dafür hinzufügen, warum dies niemals endet? Bitte gehen Sie
näher auf

1
@ Number9 Ich hoffe, das hilft, google hat viel bessere Beispiele als diese;)
Newbrict

25
Heilige Scheiße, das ist noch schlimmer als das Einfügen von Semikolons. +1!
Tomsmeding

2
Das einzige Problem, das ich bei diesem Programm sehe, ist, dass es nicht so aussieht, als würde es eine einfache Aufgabe ausführen. Es sieht so aus, als sollte es im Wesentlichen nichts tun. Vielleicht fügen Sie eine alertnach der Schleife.
PeterT

2
Sie sollten ändern a = 1zu a = true. Der Code wird auf diese Weise immer noch die Endlosschleife haben, aber es wird klarer, dass der Grund nicht irgendeine Eigenheit bei der JavaScript-Konvertierung von ints in boolesche Werte ist.
Rory O'Kane

49

C #

class Program
{
    // Expected output:
    // 20l
    // 402
    // 804
    // l608
    // 32l6
    // game over man

    static void Main()
    {
        var x = 20l;
        while (x != 6432)
        {
            Console.WriteLine(x);
            x *= 2;
        }
        Console.WriteLine("game over man");
    }
}

Das Zahlenliteral in der ersten Zeile der Funktion ist nicht '201', sondern '20' mit einem kleinen Suffix 'L' ( langer Datentyp). Die Zahl wird ziemlich schnell überlaufen, ohne jemals 6432 zu erreichen, aber das Programm wird weiterarbeiten, es sei denn, die Überlaufprüfung wurde in den Erstellungsoptionen aktiviert.
Sinnvollerweise gibt Visual Studio 2013 (und wahrscheinlich auch andere Versionen) eine Warnung für diesen Code aus und empfiehlt die Verwendung von 'L' anstelle von 'l'.


12
Oh, das lsoll aussehen wie ein 1! Ich bin dumm. : \
Joe Z.

6
Verbesserungsvorschlag: Ersetzen Sie die Einsen im erwarteten Ausgabeabschnitt ebenfalls durch ls (es ist einfacher, den seltsamen Charakter zu erkennen, wenn Sie echte Einsen zum Vergleich haben)
Allen Gould

3
Ja, es scheint ziemlich umweltspezifisch zu sein. @ Michaels Schriftart unterscheidet sich stark von der Schriftart auf meinem Heimcomputer ( imgur.com/PKIuJpr - Chrome, Windows 8), und der Trick scheint auf meinem Arbeitscomputer besser zu funktionieren als auf meinem Heimcomputer, auch wenn sie ziemlich ähnlich sind Angaben. Der Browser meines Telefons scheint keinen Code in einer Schriftart mit fester Tonhöhe anzuzeigen, und der Trick funktioniert überhaupt nicht.
BenM

1
FTR, so sieht es auf meinem Arbeitscomputer aus ( imgur.com/Opfs3BH - Firefox, Windows 7). Ich denke, man könnte sogar sehr kluge Leute zum Narren halten.
BenM

15
Warum missbrauchen Menschen Charaktere, die gleich aussehen?
Anonymes Pi

39

C

Wie wäre es mit Präzision?

int main(void)
{
    double x = 0;
    while(x != 10) x += 0.1;
    return 0;
}

Stellen Sie sich vor, Sie müssen einen Bereich von Ganzzahlen <0; 3> im Computerspeicher speichern. Es gibt nur 4 Ganzzahlen in diesem Bereich (0,1,2,3). Es reicht aus, 2 Bits zu verwenden, um das im Speicher zu speichern. Stellen Sie sich nun vor, Sie müssen einen Bereich von Gleitkommazahlen <0; 3> speichern. Das Problem ist, dass es in diesem Bereich unendlich viele Gleitkommazahlen gibt. Wie kann man unendlich viele Zahlen speichern? Es ist unmöglich. Wir können nur eine begrenzte Anzahl von Zahlen speichern. Aus diesem Grund unterscheiden sich einige Zahlen wie 0.1 tatsächlich. Im Fall von 0.1 ist es 0.100000000000000006. Es wird dringend empfohlen, == oder! = Nicht unter Bedingungen zu verwenden, bei denen Sie Gleitkommazahlen verwenden.


1
Wie funktioniert das?
Mhmd

5
Rundungsfehler. 0.1 ist eigentlich 0.100000000000000006, weil 0.1 in binär 1/3 in dezimal ist - es ist binäre Expansion ist unendlich und periodisch.
Orion

3
Kein wirklicher Rundungsfehler. Gleitkommawerte sind ungefähre Darstellungen einer Zahl. Exakte Vergleiche zwischen ungefähren Werten können nicht durchgeführt werden.
AKHolland

4
Aus diesem Grund sollten Sie Float / Doubles (fast) nie auf Gleichheit prüfen.
Emanuel Landeholm

1
Ich habe darauf gewartet, diesen zu sehen. Nett.
David Conrad

33

HTML / JavaScript

Stellen Sie sich vor, Sie haben ein Eingabefeld auf Ihrer Seite:

<input onfocus="if (this.value === '') alert('Input is empty!');">

Und jetzt möchten Sie etwas eingeben ... Versuchen Sie es in Chrome: http://jsfiddle.net/jZp4X/ .

Das mit alertfunction aufgerufene Standardbrowser-Dialogfeld ist modal. Wenn es angezeigt wird, wird der Fokus aus dem Textfeld entfernt. Wenn es jedoch geschlossen wird, erhält das Textfeld den Fokus zurück.


5
In Firefox hat die Eingabe beim Schließen der Warnung keinen Autofokus. Ab dem zweiten Mal kann ich keine weiteren Warnungen mehr anzeigen und dann normal in das Textfeld schreiben
Einacio

6
Schön. +1 für keine Schleifen oder Rekursion.
ApproachingDarknessFish

5
Keine Schleifen in Firefox oder Chrome. FF zeigt die Warnung einmal an, wenn der Dialog angeklickt wird. Sie schließen ihn und das ist das Ende. Kann es noch einmal anklicken, um es zu wiederholen. Chrome macht dasselbe, lässt jedoch die Box fokussiert und Sie können sie sogar eingeben. Entschuldigung, vielleicht war dies bei älteren Versionen ein Problem, aber nicht mehr.
RomanSt

6
IE11 funktioniert bei mir genauso wie Chrome. Ich glaube, Sie haben versehentlich ein Beispiel für etwas gefunden, das auf jedem modernen Browser unter Mac und auf jedem modernen Browser unter Windows auf eine andere Weise funktioniert!
RomanSt

1
Funktioniert normal (keine Schleifen) auf MSIE11
kinokijuf

32

C ++

#include <iostream>
#include <cstddef>

int main() {
    size_t sum = 0;
    for (size_t i = 10; i >= 0; --i) {
         sum += i;
    }
    std::cout << sum << std::endl;
    return 0;
}

Die Bedingung i >=0ist immer wahr, da size_t nicht signiert ist.


2
Nizza, aber Compiler normalerweise eine Warnung dafür;)
Synxis

2
@Synxis Ja, Compiler schon. Aber nur, wenn Sie Compiler-Warnungen einschalten. g++Ich werde Sie ohne sie nicht davor warnen.
FDinoff

5
Du solltest -Wall --pedanticsowieso immer verwenden .
Martin Ueding

3
@queueoverflow Die Warnung wird nur mit diesen Flags angezeigt. Du brauchst -Wsign-comparewas mit eingeschaltet werden kann -Wextra.
FDinoff

7
Ein Schuss auf -pedantic. #pedantic
David Conrad

29

bash

(Es gab eine Anfrage für keine Schleifen oder Rekursion)

#!/bin/bash

# Demo arrays

foo=("Can I have an array?")

echo $foo

echo ${foo[0]}

foo[2] = `yes`

echo $foo

echo ${foo[2]}

Anstatt foo [2] die Zeichenfolge "yes" zuzuweisen, wird der Systembefehl aufgerufen yes, der foo [2] mit einer unendlichen Menge von "yes \ n" füllt.


Irgendwann geht bashder Speicher aus und es stürzt ab
Digital Trauma

4
Ja, in der Tat. Aber ein Absturz war irgendwie von der Frage erlaubt :)
GreenAsJade

Ja, nur eine Beobachtung :). Upvoted.
Digital Trauma

In der Tat, ich rechne damit , dass die Programme in diesem kleinen comp , die tatsächlich Ihre Maschine zum Absturz bringen, oder eine anderen Denial - of - Service, sollten Bonusmarken bekommen)
GreenAsJade

Korrektur: yesist nur ein Coreutils-Programm. Kein Syscall.
Mittwoch,

28

C

Der Buchstabe "x" ist in einer Datei verloren gegangen. Ein Programm wurde geschrieben, um es zu finden:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  FILE* fp = fopen("desert_file", "r");
  char letter;
  char missing_letter = argv[1][0];

  int found = 0;
  printf("Searching file for missing letter %c...\n", missing_letter);
  while( (letter = fgetc(fp)) != EOF ) {
    if (letter == missing_letter) found = 1;
  }
  printf("Whole file searched.\n");
  fclose(fp);
  if (found) {
    printf("Hurray, letter lost in the file is finally found!\n");
  } else {
    printf("Haven't found missing letter...\n");
  }
}

Es wurde kompiliert und lief und es schrie schließlich:

Hurray, letter lost in the file is finally found!

Seit vielen Jahren werden Briefe auf diese Weise gerettet, bis der neue Typ kam und den Code optimierte. Er war mit Datentypen vertraut und wusste, dass es besser ist, vorzeichenlose statt vorzeichenbehaftete Werte zu verwenden, da diese einen größeren Bereich haben und einen gewissen Schutz vor Überläufen bieten. Also hat er int in unsigned int geändert . Er kannte Ascii auch gut genug, um zu wissen, dass sie immer einen nicht negativen Wert haben. Also hat er auch char in unsigned char geändert . Er kompilierte den Code und ging stolz auf seine gute Arbeit nach Hause. Das Programm sah so aus:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  FILE* fp = fopen("desert_file", "r");
  unsigned char letter;
  unsigned char missing_letter = argv[1][0];

  unsigned int found = 0;
  printf("Searching file for missing letter %c...\n", missing_letter);
  while( (letter = fgetc(fp)) != EOF ) {
    if (letter == missing_letter) found = 1;
  }
  printf("Whole file searched.\n");
  fclose(fp);
  if (found) {
    printf("Hurray, letter lost in the file is finally found!\n");
  } else {
    printf("Haven't found missing letter...\n");
  }
}

Er kam am nächsten Tag zu einem Chaos zurück. Der Buchstabe "a" fehlte und obwohl er in der "desert_file" mit "abc" enthalten sein sollte, suchte das Programm danach und gab nur Folgendes aus:

Searching file for missing letter a...

Sie entließen den Kerl und kehrten zur vorherigen Version zurück, wobei sie sich daran erinnerten, dass man Datentypen im Arbeitscode niemals optimieren sollte.

Aber welche Lektion hätten sie hier lernen sollen?

Wenn Sie sich zunächst die ASCII-Tabelle ansehen, werden Sie feststellen, dass es keine EOF gibt. Dies liegt daran, dass EOF kein Zeichen ist, sondern ein spezieller Wert, der von fgetc () zurückgegeben wird. Dabei kann entweder ein Zeichen zurückgegeben werden, das auf int erweitert ist, oder -1, das das Dateiende angibt.
Solange wir signiertes Zeichen verwenden, funktioniert alles einwandfrei - Zeichen gleich 50 wird durch fgetc () ebenfalls in int gleich 50 erweitert. Dann wandeln wir es wieder in char um und haben immer noch 50. Gleiches gilt für -1 oder eine andere Ausgabe von fgetc ().
Aber schauen Sie, was passiert, wenn wir unsignierte Zeichen verwenden. Wir beginnen mit einem Zeichen in fgetc (), erweitern es auf int und möchten dann ein vorzeichenloses Zeichen haben. Das einzige Problem ist, dass wir -1 in nicht signiertem Zeichen nicht beibehalten können. Das Programm speichert es als 255, was nicht mehr EOF entspricht.

Vorbehalt
Wenn Sie sich Abschnitt 3.1.2.5 Typen in Kopie der ANSI C-Dokumentation ansehen, werden Sie feststellen, dass die Signatur von char ausschließlich von der Implementierung abhängt. Also sollte der Typ wahrscheinlich nicht entlassen werden, da er einen sehr kniffligen Fehler im Code gefunden hat. Es könnte herauskommen, wenn der Compiler geändert oder auf eine andere Architektur umgestellt wird. Ich frage mich, wer gefeuert werden würde, wenn der Bug in einem solchen Fall herauskommen würde;)

PS. Das Programm wurde um den in der PC-Assemblersprache von Paul A. Carter erwähnten Fehler herum erstellt


7
Ich finde es toll, dass es eine Geschichte mit der Lösung gibt.
jpmc26

Haha! Ich denke, es ist der einzige. Danke fürs durchlesen!
Legat

1
Ich liebe dich. Füttere mich mit deinen Geschichten pls :(
YoYoYonnY

Das ist absolut genial!
kirbyfan64sos

21

Regex

Bei entsprechender Eingabe kann der folgende reguläre Ausdruck dazu führen, dass die meisten regulären Rückverfolgungsmodule in die Hölle der Rückverfolgung geraten:

^\w+(\s*\w+)*$

Einfache Eingaben wie "Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"oder "AVerySimpleInputWhichContainsAnInsignificantSentence."(beide Zeichenfolgen werden aus Gründen der Übersichtlichkeit angegeben) reichen aus, um die meisten Backtracking-Regex-Engines lange laufen zu lassen.

Da (\s*\w+)*erlaubt die Erweiterung \w+\w+\w+... \w+, was bedeutet, dass die Regex-Engine im Grunde alle möglichen Möglichkeiten ausprobiert, um eine Folge von Wortzeichen aufzuteilen . Dies ist die Quelle der Hölle des Zurückverfolgens.
Es kann leicht durch eine Änderung festgelegt werden \s*zu \s+, dann (\s+\w+)*kann nur erweitert werden \s+\w+\s+\w+... \s+\w+.


3
Ich hasse es, Regex-Engines zurückzuverfolgen.
David Conrad

2
Ich habe dies zuerst mit Perl versucht, aber es scheint, dass Perl hier eine Schleife bemerken kann. Ich habe AWK nicht ausprobiert, da kein regulärer Ausdruck ein solches Verhalten in AWK hervorrufen kann. PHP bewirkt automatisch, dass reguläre Ausdrücke, die zu lange brauchen, um zu passen, fehlschlagen (was albern ist, aber das ist PHP für Sie - es fügt automatisch Fehler in Programme ein). Tatsächlich funktioniert es jedoch in Python.
Konrad Borowski

1
@xfix: In diesem Artikel wird der Grund dafür erläutert, warum Perl das Zurückverfolgen der Hölle vermieden hat . Gegen den hier gezeigten Fall ist dies jedoch nicht ausreichend (scrollen Sie nach unten zum Abschnitt "Leistung"). PHP (eigentlich die PCRE-Bibliothek) hat ein Backtracking-Limit, und ein geeignetes Programm sollte immer nach dem Rückgabewert der Funktion suchen, um zu entscheiden, ob die Ausführung angehalten oder vollständig ausgeführt wurde.
n̴̖̋h̴̖̋a̷̭̿h̷̭̿d̸̡̅ẗ̵̨́

1
Das ist so SLICK.
Alvonellos

20

JavaScript

function thiswillLoop(){
var mynumber = 40;
while(mynumber == 40){
mynumber = 050;
}
return "test";
}
thiswillLoop();

050 ist eine Oktalkonstante in Javascript und hat zufällig den Dezimalwert 40.


73
Ich finde das offensichtlich. :-)
Justin

6
Ich wusste nicht, dass Javascript dies tut. Aber nachdem ich den Code gelesen hatte, sagte ich: "050 muss eine Art der Darstellung von 40 sein, wahrscheinlich Basis 8 oder so"
Cruncher

Dies muss besser versteckt werden.
Paŭlo Ebermann

Es ist offensichtlich ..
Oliver Ni

18

Haskell

head $ reverse $ (repeat '!') ++ "olleH"

Nun, denk dran! Es wäre das gleiche wie head $ "Hello" ++ (repeat '!'), dh sollte gerade zurückkehren 'H'.

In Hashell-Listen handelt es sich um rekursive Strukturen, wobei das erste Element das oberste ist. Um an eine Liste anzuhängen, müssen Sie alle diese Elemente ausrollen, Ihren Anhang platzieren und die angehobenen Elemente zurücklegen. Das würde auf einer unendlichen Liste nicht funktionieren. Ebenso wird das Umkehren einer unendlichen Liste Ihnen nicht auf magische Weise den "Hello"Rücken kehren . Es wird nur für immer hängen.


1
Schade, das funktioniert nicht wirklich: - /
John Dvorak

1
Wie geht das nicht
Danmcardle

@crazedgremlin Als ich das auf Fedora getestet habe, hat das Betriebssystem den Prozess schließlich beendet. (<5 Minuten), da der gesamte Speicher des Systems belegt ist.
FDinoff

Interessant! Ich wusste nicht, dass das passiert ist. Ich wage mich nicht allzu oft in das Gebiet der Erinnerung.
Danmcardle

4
Das ist immer noch eine gültige Lösung: Es wird nicht beendet, es wird so lange ausgeführt, bis das System es nicht mehr unterstützt ...
GreenAsJade

16

Java unter Windows

public class DoesntStop
{
    public static void main(String[]a) throws InterruptedException, IOException
    {
        ProcessBuilder p = new ProcessBuilder("cmd.exe","/c","dir");
        p.directory(new File("C:\\windows\\winsxs"));
        Process P = p.start();
        P.waitFor();
    }
}

Das Programm verlässt sich auf einen gestauten Standardausgabestream von der Kommandozeile, um hängen zu bleiben. Das WinSXS-Verzeichnis unter Windows enthält mehrere tausend Dateien mit langen Namen, so dass fast garantiert wird, dass stdout verstopft wird, und waitFordas Programm nicht zurückkehren kann, sodass das Programm blockiert ist


1
Vielleicht bin ich dicht, aber kommt das nicht irgendwann wieder? Es könnte nur eine Weile dauern. Vielleicht verstehe ich nicht, was Sie mit "verstopfen" meinen.
Asteri

4
Wenn der Stream nicht geleert ist, hat das Programm einige Kopfschmerzen verursacht. Deshalb habe ich es benutzt. Das lange Verzeichnis stellt nur sicher, dass der Puffer voll ist
masterX244

Ah, gotcha. Nett! +1
Asteri

15

Äpfel und Orangen vergleichen ... in C

Ich bin beeindruckt, dass es hier keinen Code gibt, der ein goto... verwendet. (Sie wissen: Springen ist böse! )

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    char *oranges = "2";
    long int apples;

next_harvest:

    apples = random() % 3;

    printf("%ld apples comp. %s oranges ...\n", apples, oranges);

    if( apples != (long int)oranges )
    {
        sleep(1);
        goto next_harvest;
    }

    return 0;
}

Der Schlaf dient nur dazu, ihn lesen zu können. Drücke ^ C, wenn du nicht unendlich viel Zeit hast, um auf etwas zu warten, das niemals passiert ;-)


9
Du hinterhältiger Bastard, goto ist in diesem :) unschuldig
orion

wird das random () das vodoo verwendet?
masterX244

1
ahh, "2"! = 2; habe es
masterX244

2
Nun, "2" kann wahrscheinlich niemals 2 sein, aber wenn Sie eine größere Zahl (und ein Vielfaches von mindestens 4) verwenden, könnte dies passieren;)
orion

1
@orion: Ja du hast recht, es könnte sein. Und goto ist immer noch böse, aber böse Gussteile sind noch böser!
Max.Haredoom

12

C, mit bestimmten optimierenden Compilern

Dieses Programm erhöht eine Ganzzahlvariable, bis sie überläuft.

#include <stdio.h>
#include <stdint.h>
int main()
{
    int32_t x = 0;
    while(x + 1 > x)
        x++;
    printf("Got overflow!\n");
    return 0;
}

Überlauf von Ganzzahlen mit Vorzeichen ist undefiniertes Verhalten. Normalerweise bricht es ab, wenn Optimierungen deaktiviert sind. Wenn Optimierungen aktiviert sind, können Compiler entscheiden, dass dies x + 1 > ximmer der Fall ist.


Vielleicht benutzen int32_t; Ein 64-Bit-Int dauert sehr, sehr, sehr lange (585 Jahre, wenn jede Iteration eine Nanosekunde dauert).
Paul Draper

11

C ++

int main()
{
  int x = 1;
  //why doesn't this code terminate??/
  x = 0;
  while(x) {} //no-op/
  return 0;
}

Der seltsame Kommentarstil ist der Trick. Andeutung: Trigraphen.


Dies ist ein zu einfaches Beispiel für eine Endlosschleife.
Ismael Miguel

64
Diese Trigraphs sind hier sooo überbeansprucht :(
TimWolla

75
Ich habe fast das Gefühl, dass Trigraphen in Standardlücken gesteckt werden sollten, die nicht mehr lustig sind.
Undergroundmonorail

6
@TheDoctor: ?? / ist eine Trigraphie für ein Backslash-Zeichen, sodass der Backslash die Zeile, in der x zugewiesen ist, an das Ende des Kommentars anschließt und es zum Teil des Kommentars macht.
CasaDeRobison

4
@undergroundmonorail Posted
Justin

11

Java

Ich mag diesen Nebeneffekt der Autoboxing-Optimierung besonders:

class BoxingFun {
  public static void main( String[] args) {
    Integer max;
    Integer i;

    max = 100;
    for( i = 1; i != max; i++ ) {
      System.out.println("Not endless");  
    }
    max = 200;
    for( i = 1; i != max; i++ ) {
      System.out.println("Endless");  
    }
  }
}

Aufgrund des Autoboxing Integerverhalten sich Objekte hier fast wie normale ints, mit einer Ausnahme: In i != maxden forSchleifen werden die Referenzen (Identität) der IntegerObjekte verglichen , nicht ihr Wert (Gleichheit). Für Werte bis 100 "funktioniert" dies überraschenderweise dennoch aufgrund einer Optimierung in der JVM: Java reserviert IntegerObjekte für die "häufigsten Werte" vor und verwendet sie beim Autoboxen erneut. Für Werte bis zu 100 gilt also die Gleichheit <==>.


5
Angesichts der Tatsache, dass einige Java-Leute das Überladen von C ++ - Operatoren immer noch für böse halten ...
Daniel,

Sie brauchen die Initialisierung nicht = new Integer(0), da Sie die Werte danach sowieso initialisieren. (Dies könnte den Grund weniger offensichtlich machen.)
Paŭlo Ebermann

@ PaŭloEbermann: Guter Punkt, ich habe den Code bearbeitet.
Daniel

9

Ruby / C

#include <stdio.h>
#ifdef llama
def int(*args)
end
def main(arg)
  yield
end
void = nil
#endif
#define do {
#define end }
int main(void) {
  int x = 10;
  while(x-=1) do
    printf("%i\n",x);
  end
    return 0;
}

Dies funktioniert korrekt in C , wobei in STDOUT von 9 auf 1 heruntergezählt wird. Wenn es in Ruby ausgeführt wird, wird es nicht beendet, weil

0 ist in Ruby kein falscher Wert.


Machen Sie Sprachen auf einmal ... beeindruckend.
Paul Draper

7

JavaScript

// This multiplies the elements in the inner lists and sums the results.
function sum_of_products(var items)
{
        var total = 0;
        for(var i = 0; i < items.length; i++) {
                var subitems = items[i];
                var subtotal = 1;
                for(var i = 0; i < subitems.length; i++) {
                        subtotal *= subitems[i];
                }       
                total += subtotal;
        }
        return total;
}

// Should return 1*2 + 3*4*5 + 6*7*8*9 + 10*11 = 3196
sum_of_products([[1, 2], [3, 4, 5], [6, 7, 8, 9], [10, 11]]);

Beide Schleifen verwenden dieselbe Schleifenvariable. Abhängig von der Eingabe kann die innere Schleife also verhindern, dass die äußere Schleife jemals beendet wird.


Welche Sprache ist das?
RononDex

@ronondex Javascript
Tomsmeding

1
Ah ja, es ist Javascript. Ich erinnerte mich, die Syntax Hilighting zu aktivieren, musste aber vergessen, es auch in den Titel zu setzen :)
Aleksi Torhamo

1
Ich finde das offensichtlich. :-)
rafaelcastrocouto

@rafaelcastrocouto Ja, das ist es, aber es ist auch sehr leicht zu übersehen, zum Beispiel wenn man eine Schleife von einer Funktion zu einer anderen verschiebt oder nur einen Blick über den Code wirft. Beachten Sie außerdem, dass dies in einigen Sprachen, einschließlich C, aufgrund der variablen Schattierung tatsächlich korrekt funktioniert. :)
Aleksi Torhamo

7

C

Dies sollte eine Codetabelle für alle ASCII-Zeichen von 0 bis 255 ausgeben. A charist groß genug, um darüber zu iterieren.

#include <stdio.h>

int main(){
    char i;
    for(i = 0; i < 256; i++){
        printf("%3d 0x%2x: %c\n", i, i, i);
    }
    return 0;
}

Alle Zeichen sind kleiner als 256. 255 ++ ergibt 0 aufgrund eines Überlaufs, daher gilt die Bedingung i < 256immer. Einige Compiler warnen davor, andere nicht.


Zu machen, scheint etwas nützlicher zu sein, verwenden Sie vielleicht etwas wie printf("%3d %2x: %c", i, i, i);(für eine Codetabelle) in Ihrer Schleife.
Paŭlo Ebermann

@ PaŭloEbermann: Tolle Idee.
Rafał Cieślak

Ich benutze diesen Trick in meinem Klassenzimmer mit druckbaren Zeichen ohne Vorzeichen zwischen 32 und 128. :)
cpri

7

Python

a = True
m = 0
while a:
    m = m + 1
    print(m)
    if m == 10:
        exit

es sollte sein exit()und nicht exit. Wie ich es verstehe, exit()ist der Befehl, den Python-Interpreter zu beenden. In diesem Fall erfolgt der Aufruf zur Darstellung der Funktion und nicht zur Funktion, siehe: exit-discussion . Alternativ breakwäre eine bessere Wahl.


Könnten Sie bitte erklären, was exiteigentlich ist? Es scheint eine Klasse zu sein, aber wofür wird sie verwendet? Sie können auch ändern print m, print(m)so dass dies auch mit Python 3 funktioniert.
Martin Thoma

1
Solche Dinge ... Zum Beispiel, als mein elseif nicht funktionierte, weil es elif war .
Anonymes Pi

Vielen Dank @mooseaktualisierte print-Anweisung und die Spoiler-Nachricht
Willem

6

C ++

Wie wäre es mit der klassischen C ++ - Programmiererfalle?

int main()
{
   bool keepGoing = false;

   do {
       std::cout << "Hello, world!\n";
   } while( keepGoing = true );

   return 0;
}

Ich verstehe das nicht? Geht es um die Verwendung. = statt ==?
Mhmd

@ user689 genau. keepGoing = truesollte den Wert von vergleichen keepGoing, weist stattdessen den Wert zu keepGoing; zusätzlich die gesamte Aussage keepGoing = trueausgewertet true(das ist , was du Dinge wie schreiben kann a=b=c=d=0) , was zu einer Endlosschleife.
CompuChip

3
Dies ist immer mehr Grund, Yoda-Bedingungen zu nutzen.
Ryan

@ RyanEdwardDougherty Haha so habe ich noch nie gehört, dass sie gerufen wurden. Für den Morgen lachen danke.
CompuChip

@ RyanEdwardDougherty: Natürlich == true(oder Yoda-Stil true ==) ist sowieso überflüssig, und die Bedingung sollte einfach gelesen werden while (keepGoing).
Celtschk

6

Javascript

var а = 0;
a = 1;
while(а<10){
    a++;
}

Die in der 1. und 3. Zeile verwendeten Variablen unterscheiden sich von denen in der 2. und 3. Zeile.
Einer verwendet ein (U + 0061), während der andere ein (U + 0430) verwendet.


Ich sehe hier kein Problem. Ich habe es gelaufen und es hat gut funktioniert. Was vermisse ich?
Andrew Shepherd

Dies wird höchstwahrscheinlich überall funktionieren, da der Unicode wahrscheinlich konvertiert wird. Erhielt ein +1, da es das unsichtbarste ist, wie Sie bekommen können!
Rafaelcastrocouto

Nur um es komplett auszublenden (á durch U + 0430 ersetzen) Wenn dies Ihr Code wäre, viel Glück beim Finden des Problems: var a;var points = 0;function fiftyfifty() {points++;if (Math.random() > 0.5)return true;}; á = fiftyfifty(); while (a === undefined) {á = fiftyfifty();} console.log("Points: " + points);Ich würde aufgeben, dies für immer löschen, meinen Computer säubern, vielleicht einen Virenscanner, nur um sicherzugehen und es komplett neu zu schreiben. BEARBEITEN: Da var a = 0; a = 1;ist nicht sehr realistisch
YoYoYonnY

6

Java:

public class LoopBugThing{
   public static void main(String[] args)
   {
      int i = 0;
      while(i < 10)
      {
         //do stuff here
         i = i++;
      }
      System.out.println("Done!");
   }
}

Das "i = i ++" ist ein ziemlich häufiger Anfängerfehler und kann überraschend schwer zu finden sein


5

C ++

Ein bisschen zufällig?

class Randomizer
{
   private:
   int max;

   public:
   Randomizer(int m)
   {
      max = m;
      srand(time(NULL));
   }

   int rand()
   {
      return (rand() % max);
   }
};

int main()
{
  Randomizer r(42);
  for (int i = 0; i < 100; i++)
  {
     i += r.rand();
  }
  return (0);
}

Ruft die Funktion nicht auf, randsondern ruft sie rekursiv auf Randomizer::rand.


5
Zusätzliche Klammern in der return-Anweisung, yuck.
David Conrad

1
Dies wird jedoch irgendwann fehlschlagen.
kirbyfan64sos

5

Haskell

Einige Code, um die Berechnung eines bestimmten Wertes der Ackermann-Funktion zu verzögern. Bei sehr niedrigen Werten endet es normalerweise. Auf meinem Rechner bedeuten sehr niedrige Werte so etwas wie 3 5 oder kleiner mit kompiliertem Code und -O. In ghci bedeuten niedrige Werte so etwas wie 3 3.

Das 'Symbol scheint die Syntaxhervorhebung durcheinander zu bringen, nicht sicher warum. An einigen Stellen werden sie benötigt, sodass nicht alle entfernt werden können.

Bearbeitete Sprache.

{-# LANGUAGE NamedFieldPuns #-}
import Control.Concurrent.STM
import Control.Concurrent
import Data.Time.Clock.POSIX

data D = D { time :: !POSIXTime
           , m :: !Integer
           , n :: !Integer
           , res :: !(Maybe Integer)
           } deriving Show

startvalue = D 0 3 8 Nothing

-- increment time in D. I belive lensen make code like
-- this prettier, but opted out.
inctime t t' (d@D{time}) = d {time = time + t' - t }

-- Counting time
countTime :: TVar D -> POSIXTime -> IO ()
countTime var t = do
    t' <- getPOSIXTime
    atomically $ modifyTVar' var (inctime t t')
    countTime var t'

-- Ackermann function
ack m n
    | m == 0    = n + 1
    | n == 0    = ack (m - 1) 1
    | otherwise = ack (m - 1) (ack m (n - 1))

-- Ackerman function lifted to the D data type and strict
ack' (d@D{m, n}) = let a = ack m n
                   in seq a (d { res = Just a })

-- fork a counting time thread, run the computation
-- and finally print the result.
main = do
    d <- atomically (newTVar startvalue)
    forkIO (getPOSIXTime >>= countTime d)
    atomically $ modifyTVar' d ack'
    (atomically $ readTVar d) >>= print

Dies führt zu einer Lebenssperre. Der Zähl-Thread führt wiederholt zu einem Rollback der Ackermann-Berechnung, da sie dasselbe TVar berühren.


es als lang-hs anstelle von lang-haskell zu markieren, scheint besser zu funktionieren (es ist eine der Erweiterungen im Google Prettifier )
Einacio

5

Java - Keine Schleifen oder Rekursionen

Ich habe gerade angefangen, reguläre Ausdrücke zu lernen und habe mein erstes Programm geschrieben, um zu testen, ob meine Zeichenfolge mit einem regulären Ausdruck übereinstimmt.

Leider liefert das Programm kein Ergebnis. Es hält das Terminal hoch. Bitte helfen Sie bei der Suche nach dem Problem. Ich habe keine Schleifen benutzt, es gibt keine Rekursion. Ich bin völlig ratlos.

import java.util.regex.*;

public class LearnRegex {
     public static void main(String[] args) {
         Pattern p = Pattern.compile("(x.|x.y?)+");
         String s = new String(new char[343]).replace("\0", "x");
         if (p.matcher(s).matches())
             System.out.println("Match successful!");
     }
}

Was habe ich falsch gemacht? Warum endet mein Programm nicht? Bitte helfen Sie!

Ideone Link hier .

Dies ist ein dummes Beispiel für katastrophales Backtracking . Die Komplexität ist O (2 n / 2 ). Während das Programm nicht auf unbestimmte Zeit laufen könnte, würde es wahrscheinlich beide lebenden und nicht lebenden outlive Objekte herum und nicht so um .


5

C

Sie sollten nur eine der beiden Schleifen benötigen, aber welche Sie benötigen, hängt von Ihrem Compiler ab.

main()
{
        int i, a[10];

        i = 0;
        while (i <= 10) {
            i++;
            a[i] = 10 - i;
            printf("i = %d\n", i);
        }

        /* Now do it in reverse */

        i = 10;
        while (i >= 0) {
            i--;
            a[i] = 10 - i;
            printf("i = %d\n", i);
        }

}

Eine einfache Überschreitung von Grenzen, die i auf einen nicht abschließenden Wert zurücksetzt . Compiler können sich unterscheiden, ob sie i über oder unter a auf dem Stapel zuweisen , daher habe ich Überläufe in beide Richtungen eingeschlossen.


5

C / C ++

C ++ erlaubt nur die hier verwendeten einfachen Inline-Variablendeklarationen, aber es ist genauso einfach, diesen Fehler in ...

#include <stdio.h>

int main(void)
{
    int numbers[] = {2, 4, 8};

    /* Cube each item in the numbers array */
    for(int i = 0; i < 3; i++) {
      for(int j = 0; j < 3; i++) {
        numbers[j] *= numbers[j];
      }
    }

    /* Print them out */
    for(int i = 0; i < 3; i++) {
      printf("%d\n", numbers[i]);
    }

    return 0;
}

In der inneren Schleife wird 'j' verglichen, aber niemals inkrementiert. (Das 'i ++' sollte eigentlich 'j ++' sein). Dies ist nicht so sehr ein hinterhältiger Trick, sondern eher ein Fehler, den ich in der Vergangenheit gemacht habe.


2
Normalerweise benötige ich mindestens 5 Minuten zum Debuggen. Ich hasse es, wenn ich das tat.
ace_HongKongIndependence

4

C #

Das Folgende ist eine einfache Klasse, die eine arithmetische Operation (Summation) für ein großes Eingabearray unter Verwendung eines Hintergrundthreads ausführt. Ein Beispielprogramm ist enthalten.

Obwohl es ganz einfach ist, wird es nie beendet. Beachten Sie, dass es keine Fingerfertigkeit gibt (Zeichen-Lookalikes, versteckte / fehlende Semikolons, Trigraphen ;-) usw.)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

class Program
{
    static void Main()
    {
        var summer = new BackgroundSummer(Enumerable.Range(1, 1234567));
        Console.WriteLine(summer.WaitAndGetResult());
    }
}

public class BackgroundSummer
{
    private IEnumerable<int> numbers;
    private long sum;
    private bool finished;

    public BackgroundSummer(IEnumerable<int> numbers)
    {
        this.numbers = numbers;
        new Thread(ComputingThread).Start();
    }

    public long WaitAndGetResult()
    {
        while (!finished) { /* wait until result available */ }
        return sum;
    }

    private void ComputingThread()
    {
        foreach(var num in numbers)
        {
            sum += num;
        }
        finished = true;
    }
}

Dies ist ein Beispiel für einen bösen Fehler in der realen Welt, der möglicherweise auch in Ihrem Code auftritt. Gemäß dem .NET-Speichermodell und der C # -Spezifikation wird eine Schleife wie die in WaitAndGetResultmöglicherweise nie beendet, es sei denn, Sie geben die Variable als flüchtig an, da sie von einem anderen Thread geändert wird. Weitere Informationen finden Sie in dieser StackOverflow-Frage . Der Fehler ist von der .NET-Implementierung abhängig, sodass Sie möglicherweise davon betroffen sind oder nicht. In der Regel scheint das Problem bei einem Release-Build auf einem x64-Prozessor zu liegen. (Ich habe es mit "csc.exe / o + / debug- infinite.cs" versucht .)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.