Dlaczego to się nie kończy? [Zamknięte]

95

Twoje zadanie: napisać program, który oczywiście powinien zakończyć się, ale nigdy (w przypadku awarii komputera) tak się nie dzieje. Spraw, by wyglądało na to, że powinno wykonywać proste zadanie: dodawanie liczb, drukowanie czegoś, ... Ale po prostu zostaje złapany w nieskończoną pętlę.

Postaraj się, aby twój program był bardzo przejrzysty i prosty, podczas gdy faktycznie utknie w nieprzewidzianej pętli. Wyborcy: oceń odpowiedzi na to, jak „są podstępni”!

To konkurs popularności: Bądź kreatywny!

Numer 9
źródło
6
Czy ktoś mógłby wyjaśnić, co mogę zrobić, aby pytanie było mniej ogólne? Jestem tu nowy. Dziękuję Ci!
Number9
6
To będzie po prostu duża lista literówek i błędów początkujących, które powodują pętle.
Bill Woodger
Ciekawe pytanie, ale nie widziałem jeszcze żadnych naprawdę kreatywnych odpowiedzi. Obiecuję głosować każdemu, kto nie używa pętli ani oczywistej rekurencji!
ApproachingDarknessFish
14
Nie wiem, czy to się liczy, ale w tej chwili mój pakiet Microsoft Office zachowuje się dokładnie tak.
Level River St
1
Głosuję za zamknięciem tego pytania jako nie na temat, ponieważ nieuczciwe wyzwania nie są już tutaj na temat. meta.codegolf.stackexchange.com/a/8326/20469
kot

Odpowiedzi:

185

JavaScript

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

prompt () zwraca ciąg znaków, a pętla dołącza znak „1”, nigdy nie będzie równy 100.

Michael M.
źródło
13
Dostałeś mnie z tym jednym… (tak naprawdę) wyżej głosowane przykłady po prostu nadużywają składni… ale ten jest fajny!
bwoebi
4
Chrome na Kubuntu przestał reagować, zawiesił wszystko i musiałem mocno zresetować :)
Sergey Telshevsky
4
@Vlakarados: Python nie wykona domyślnej konwersji typu JavaScript. W Pythonie równoważny kod używający raw_inputlub Python 3 inputwywołuje a TypeError.
user2357112,
2
Nie sprawdza się, czy wartość faktycznie jest
mniejsza
1
@Sankalp, +tutaj operator jest konkatenacją łańcucha, a nie dodatkiem.
Michael M.,
87

do

Tylko podstawowy przykładowy program ilustrujący trzy różne rodzaje pętli while w C.

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;
}

Podczas gdy pętle nie mają „zrobić” przed otwierającym nawiasami klamrowymi. To faktycznie tworzy pętlę „do while” w pętli (x <10), która jest zakończona następującą „instrukcją null” podczas pętli. Ponieważ x jest zwiększane wewnątrz pętli, a następnie zmniejszane w stanie pętli „do-while”, pętla wewnętrzna nigdy się nie kończy, podobnie jak pętla zewnętrzna. Pętla „pojedynczej instrukcji” na końcu nigdy nie jest osiągana.

Jeśli nadal jesteś zdezorientowany, zajrzyj tutaj (hostowany zewnętrznie, ponieważ codegolf.SE nie lubi bloków kodu w spoilerach).

Fraxtil
źródło
8
Haha, wymyśliłem ten, zanim spojrzałem na spoiler rozwiązania. : P
Joe Z.
54
Dlaczego przegapiłeś tak doskonałą okazję do skorzystania z operatora „idzie do”? (x --> 0)
corsiKa
2
Och wow. To jest cudownie złe. Znalazłem cztery czytanie.
Patrick M
1
@JoeZ. O wiele za łatwe. Najbardziej uprzywilejowane rozwiązanie było lepsze. Tego nie znalazłem.
Anonimowy Pi
3
@Hat Guy, Bash ma składnię for; do i while; do, dzięki czemu widzę, że ludzie są tym zaskoczeni, nawet jeśli znają języki inne niż C / C ++. tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html
nemec
85

JavaScript

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

Podnoszenie zmiennych: JavaScript faktycznie pobierze moją drugą definicję var a = true;, zadeklaruje ją na górze funkcji jako var a;i zmodyfikuje moje przypisanie do a = true;znaczenia, aktóre będzie niezdefiniowane w momencie wejścia w pętlę while.

Newbrict
źródło
3
Czy możesz dodać lepsze wyjaśnienie, dlaczego to się nigdy nie kończy? Proszę
zgłębić
1
@ Number9 Mam nadzieję, że to pomaga, Google ma znacznie lepsze przykłady niż to;)
Newbrict
25
Jasna cholera, to nawet gorsze niż wstawianie średnika. +1!
tomsmeding
2
Jedyny problem, jaki widzę w tym programie, to to, że nie wygląda na to, że wykonuje proste zadanie ... wygląda na to, że zasadniczo nie powinien nic robić. Może dodaj alertpo pętli.
PeterT
2
Powinieneś zmienić a = 1na a = true. Kod nadal będzie miał nieskończoną pętlę w ten sposób, ale będzie jasne, że przyczyną nie jest dziwactwo w konwersji JavaScript z ints na booleans.
Rory O'Kane
49

DO#

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");
    }
}

Literał liczbowy w pierwszym wierszu funkcji nie jest „201”, ale „20” z małym przyrostkiem „L” ( długi typ danych). Liczba przepełni się dość szybko, nawet nie uderzając w 6432, ale program będzie działał, dopóki nie zostanie włączone sprawdzanie przepełnienia w opcjach kompilacji.
Rozsądnie, Visual Studio 2013 (i prawdopodobnie także inne wersje) wyświetla ostrzeżenie dla tego kodu, zalecając użycie „L” zamiast „l”.

BenM
źródło
12
Och, lto ma wyglądać jak 1! Jestem głupi. : \
Joe Z.
6
Propozycja ulepszenia: zamień 1s w części oczekiwanego wyjścia również na ls (łatwiej jest dostrzec dziwną postać, gdy masz prawdziwe 1s do porównania)
Allen Gould
3
Tak, wydaje się być dość specyficzny dla środowiska. @ Czcionka Michaela wygląda zupełnie inaczej niż czcionka na moim komputerze domowym ( imgur.com/PKIuJpr - Chrome, Windows 8), a sztuczka wydaje się działać lepiej na moim komputerze roboczym niż na moim komputerze domowym, mimo że mają dość podobne okular. Przeglądarka mojego telefonu nie wyświetla kodu czcionką o stałej podziałce, a sztuczka w ogóle na nim nie działa.
BenM
1
FTR, oto jak to wygląda na moim komputerze służbowym ( imgur.com/Opfs3BH - Firefox, Windows 7). Sądzę, że można nawet oszukać całkiem bystrych ludzi.
BenM
15
DLACZEGO LUDZIE UTRZYMUJĄ NADUŻYCIE ZNAKÓW, KTÓRE WYGLĄDAJĄ TAKIE SAME?
Anonimowy Pi
39

do

A może precyzja?

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

Wyobraź sobie, że musisz zapisać zakres liczb całkowitych <0; 3> w pamięci komputera. W tym zakresie są tylko 4 liczby całkowite (0,1,2,3). Wystarczy użyć 2 bitów, aby zapisać to w pamięci. Teraz wyobraź sobie, że musisz zapisać zakres liczb zmiennoprzecinkowych <0; 3>. Problem polega na tym, że w tym zakresie jest nieskończona liczba liczb zmiennoprzecinkowych. Jak przechowywać nieskończoną liczbę liczb? To jest niemożliwe. Możemy przechowywać tylko skończoną liczbę liczb. Właśnie dlatego niektóre liczby, takie jak 0,1, są różne. W przypadku 0,1 jest to 0,100000000000000006. Zdecydowanie zaleca się, aby nie używać == lub! = W warunkach, o ile używasz liczb zmiennoprzecinkowych.

Scony
źródło
1
Jak to działa?
Mhmd,
5
Błędy zaokrąglania. 0,1 to w rzeczywistości 0,100000000000000006, ponieważ 0,1 w systemie binarnym to 1/3 w systemie dziesiętnym - to rozszerzenie binarne jest nieskończone i okresowe.
Orion
3
Naprawdę nie jest to błąd zaokrąglenia. Wartości zmiennoprzecinkowe są przybliżonymi reprezentacjami liczby. Dokonywanie dokładnych porównań wartości przybliżonych nie zadziała.
AKHolland
4
Właśnie dlatego (prawie) nigdy nie powinieneś porównywać liczb zmiennoprzecinkowych / podwójnych dla równości.
Emanuel Landeholm
1
Czekałem na to. Miły.
David Conrad,
33

HTML / JavaScript

Wyobraź sobie, że masz pole wprowadzania na swojej stronie:

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

A teraz chcesz coś w nim wpisać ... Wypróbuj w Chrome: http://jsfiddle.net/jZp4X/ .

Standardowe okno dialogowe przeglądarki wywoływane z alertfunkcją jest modalne, więc gdy jest wyświetlane, usuwa fokus z pola tekstowego, ale gdy jest odrzucane, pole tekstowe odbiera fokus z powrotem.

Wizja
źródło
5
w Firefoksie dane wejściowe nie mają automatycznego ustawiania ostrości po zamknięciu alertu, a po raz drugi oferuje mi nie pokazywanie kolejnych alertów, a następnie mogę normalnie pisać w polu tekstowym
Einacio
6
Niezłe. +1 za brak pętli lub rekurencji.
ApproachingDarknessFish
5
Brak pętli w przeglądarce Firefox lub Chrome. FF wyświetla alert raz po kliknięciu okna dialogowego, odrzucasz go i to jest koniec. Można kliknąć ponownie, aby powtórzyć. Chrome robi to samo, ale pozostawia pole skupione i możesz nawet pisać. Niestety, może w starszych wersjach był to problem, ale już nie.
RomanSt
6
IE11 działa dla mnie dokładnie tak samo jak Chrome. Myślę, że przypadkowo znalazłeś przykład czegoś, co działa w jedną stronę w każdej nowoczesnej przeglądarce na komputerze Mac, a inaczej w każdej nowoczesnej przeglądarce w systemie Windows!
RomanSt
1
Działa normalnie (bez pętli) na 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;
}

Warunek i >=0jest zawsze spełniony, ponieważ rozmiar_t jest niepodpisany.

FDinoff
źródło
2
Fajny, ale kompilatory zwykle generują ostrzeżenie;)
Synxis
2
@Synxis Tak kompilatory tak. Ale tylko jeśli włączysz ostrzeżenia kompilatora. g++nie ostrzeże cię przed nimi bez nich.
FDinoff,
5
I tak zawsze powinieneś używać -Wall --pedantic.
Martin Ueding
3
@queueoverflow Ostrzeżenie nie wyświetla się tylko z tymi flagami. Potrzebujesz, -Wsign-comparektóry można włączyć -Wextra.
FDinoff,
7
Jedna kreska -pantycka. #pedantic
David Conrad
29

grzmotnąć

(Zgłoszono żądanie braku pętli lub rekurencji)

#!/bin/bash

# Demo arrays

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

echo $foo

echo ${foo[0]}

foo[2] = `yes`

echo $foo

echo ${foo[2]}

Zamiast przypisywać ciąg „tak” do foo [2], wywołuje to polecenie systemowe yes, które wypełnia foo [2] niekończącą się liczbą „tak \ n”.

GreenAsJade
źródło
W końcu kończy bashsię pamięć i ulega awarii
Digital Trauma
4
Tak, rzeczywiście tak jest. Ale pytanie w pewien sposób pozwoliło na
awarię
Tak, tylko spostrzeżenie :). Pozytywne.
Cyfrowy uraz
W rzeczywistości uważam, że programy w tym małym komputerze, które faktycznie powodują awarię komputera lub inną odmowę usługi, powinny uzyskać dodatkowe znaki)
GreenAsJade
Korekta: yesto tylko program podstawowy. Nie wywołanie systemowe.
mniip
28

do

Litera „x” została utracona w pliku. Napisano program, aby go znaleźć:

#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");
  }
}

Został skompilowany i uruchomić, a na koniec krzyknął:

Hurray, letter lost in the file is finally found!

Przez wiele lat listy były ratowane w ten sposób, dopóki nie pojawił się nowy facet i nie zoptymalizował kodu. Znał typy danych i wiedział, że lepiej jest używać niepodpisanego niż podpisanego dla wartości nieujemnych, ponieważ ma szerszy zakres i zapewnia pewną ochronę przed przepełnieniem. Więc zmienił int na int bez znaku . Znał również ascii wystarczająco dobrze, aby wiedzieć, że zawsze mają one wartość nieujemną. Więc zmienił także char na niepodpisany char . Skompilował kod i wrócił do domu dumny ze swojej dobrej roboty. Program wyglądał następująco:

#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");
  }
}

Wrócił do spustoszenia następnego dnia. Brakowało litery „a” i mimo, że miała znajdować się w „pliku_pustynnym” zawierającym „abc”, program szukał go na zawsze, drukując tylko:

Searching file for missing letter a...

Zwolnili faceta i wycofali się do poprzedniej wersji, pamiętając, że nigdy nie należy optymalizować typów danych w działającym kodzie.

Ale jakiej lekcji powinni się tutaj nauczyć?

Po pierwsze, jeśli spojrzysz na tabelę ascii, zauważysz, że nie ma EOF. Wynika to z faktu, że EOF nie jest znakiem, ale specjalną wartością zwróconą przez fgetc (), która może zwracać znak rozszerzony do int lub -1 oznaczający koniec pliku.
Tak długo, jak używamy podpisanego znaku, wszystko działa dobrze - znak równy 50 jest rozszerzany przez fgetc () na liczbę całkowitą równą 50. Następnie przekształcamy go z powrotem na char i nadal mamy 50. To samo dzieje się z -1 lub dowolnym innym wyjściem pochodzącym z fgetc ().
Ale zobacz, co się stanie, gdy użyjemy niepodpisanego znaku. Zaczynamy od znaku w fgetc (), rozszerz go na int, a następnie chcemy mieć znak bez znaku. Jedynym problemem jest to, że nie możemy zachować -1 w niepodpisanym znaku. Program przechowuje go jako 255, który nie jest już równy EOF.

Zastrzeżenie
Jeśli spojrzysz na sekcję 3.1.2.5 Typy w kopii dokumentacji ANSI C , przekonasz się, że to, czy znak jest podpisany, czy nie, zależy wyłącznie od implementacji. Więc facet prawdopodobnie nie powinien zostać zwolniony, ponieważ znalazł bardzo podstępny błąd czający się w kodzie. Może pojawić się podczas zmiany kompilatora lub przejścia do innej architektury. Zastanawiam się, kto zostałby zwolniony, gdyby błąd wyszedł w takim przypadku;)

PS. Program został zbudowany wokół błędu wymienionego w Paul Assembly Language przez Paula A. Cartera

Legat
źródło
7
Uwielbiam to, że z rozwiązaniem jest historia.
jpmc26
Ha ha! Myślę, że to jedyny. Dziękuję za przeczytanie!
Legat
1
Kocham Cię. Nakarm mnie swoimi historiami,
proszę
To jest absolutnie genialne!
kirbyfan64sos
21

Regex

Przy odpowiednich danych wejściowych następujące wyrażenie regularne może spowodować, że większość silnika wyrażeń regularnych cofnie się do piekła:

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

Proste wprowadzanie, takie jak "Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"lub "AVerySimpleInputWhichContainsAnInsignificantSentence."(oba ciągi cytowane dla zachowania przejrzystości), wystarcza, aby większość silników cofania zwrotnego działała przez długi czas.

Ponieważ (\s*\w+)*pozwala na ekspansję \w+\w+\w+... \w+, co oznacza, że ​​silnik wyrażeń regularnych w zasadzie wypróbuje wszystkie możliwe sposoby rozdzielenia ciągu znaków słów . To jest źródło cofania się piekła.
To może być łatwo ustalony przez zmianę \s*celu \s+, wtedy (\s+\w+)*można rozszerzyć tylko \s+\w+\s+\w+... \s+\w+.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨d̷̰̀ĥ̷̳
źródło
3
Nienawidzę wycofywania silników regex.
David Conrad,
2
Najpierw próbowałem tego z Perlem, ale wygląda na to, że Perl może tutaj zauważyć pętlę. Nie próbowałem AWK, ponieważ żadne wyrażenie regularne nie może spowodować takiego zachowania w AWK. PHP automatycznie tworzy wyrażenie regularne, którego dopasowanie zbyt długo nie powiedzie się (co jest głupie, ale to PHP dla ciebie - automatycznie wstawia błędy do programów). Jednak tak naprawdę działa w Pythonie.
Konrad Borowski
1
@xfix: Jeśli chodzi o to, dlaczego Perlowi udało się uniknąć powrotu do piekła, ten artykuł wyjaśnia przyczynę. Jednak nie jest to wystarczające w stosunku do przypadku, jak pokazano tutaj (przewiń w dół do sekcji wydajności). PHP (właściwie biblioteka PCRE) ma limit cofania, a odpowiedni program powinien zawsze sprawdzać wartość zwracaną przez funkcję, aby zdecydować, czy wykonanie zostało zatrzymane, czy zakończone.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨dd
1
To takie ŚLIZNE.
alvonellos
20

JavaScript

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

050 jest stałą ósemkową w Javascript i zdarza się, że ma wartość dziesiętną 40.

Wuiyang
źródło
73
Uważam to za oczywiste. :-)
Justin
6
Nie wiedziałem, że javascript to zrobił. Ale po przeczytaniu kodu powiedziałem: „050 musi być jakimś sposobem reprezentowania 40, prawdopodobnie podstawy 8 lub czegoś takiego”
Cruncher
To musi być lepiej ukryte.
Paŭlo Ebermann
To oczywiste ..
Oliver Ni
18

Haskell

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

Pomyśl o tym! Byłoby to to samo, co head $ "Hello" ++ (repeat '!'), tj. Powinien po prostu wrócić 'H'.

W haskell listy są strukturami rekurencyjnymi, przy czym pierwszy element jest najwyższy. Aby dołączyć do listy, musisz rozwinąć wszystkie te elementy, umieścić dodatek i ponownie podnieść elementy. To nie działałoby na nieskończonej liście. Podobnie odwrócenie nieskończonej listy w magiczny sposób nie odwróci się od ciebie "Hello". Po prostu zawiesza się na zawsze.

mniip
źródło
1
Szkoda, że ​​tak naprawdę nie działa: - /
John Dvorak
1
Jak to nie działa
danmcardle
@crazedgremlin, kiedy testowałem to na Fedorze, system operacyjny ostatecznie zabił ten proces. (<5 minut), ponieważ zużył całą pamięć w systemie.
FDinoff
Ciekawy! Nie zdawałem sobie sprawy, że tak się stało. Tak często nie zapuszczam się na terytorium pełne pamięci.
danmcardle
4
To wciąż prawidłowe rozwiązanie: nie wychodzi, działa tak długo, jak to możliwe, dopóki system nie będzie w stanie go obsługiwać ...
GreenAsJade
16

Java pod 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();
    }
}

Program blokuje się przy użyciu zablokowanego standardowego strumienia wyjściowego z wiersza polecenia. Katalog WinSXS w systemie Windows zawiera wiele tysięcy plików o długich nazwach, więc prawie na pewno można zablokować standardowe wyjście i waitFornie można wrócić, więc program jest zakleszczony

masterX244
źródło
1
Może jestem gęsty, ale czy w końcu nie powróci? To może chwilę potrwać. Może nie rozumiem, co masz na myśli przez „zatkać [ging] stdout”.
asteri
4
jeśli strumień nie jest opróżniany, bloki programu spowodowały już pewne bóle głowy, dlatego go użyłem; długi katalog zapewnia tylko, że bufor działa pełny
masterX244
Ach, mam cię. Miły! +1
asteri
15

Aby porównać jabłka i pomarańcze ... w C

Jestem pod wrażeniem, że nie ma tu kodu używającego goto... (Wiesz: Goto jest złe! )

#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;
}

Sen służy tylko do czytania. Naciśnij ^ C, jeśli nie masz nieskończonej ilości czasu, aby poczekać na coś, co nigdy się nie wydarzy ;-)

max. pokój dzienny
źródło
9
Ty podstępny draniu, goto jest w tym niewinny :)
orion
jest używane losowe () vodoo?
masterX244,
1
ahh, „2”! = 2; got it
masterX244
2
Cóż, „2” prawdopodobnie nigdy nie może być 2, ale jeśli użyjesz większej liczby (i wielokrotności co najmniej 4), może się zdarzyć;)
orion
1
@orion: Tak, masz rację, może być. Goto jest nadal zły, ale odlewy złego typu są jeszcze bardziej złe!
max. Dzielnica
12

C, z pewnymi kompilatorami optymalizującymi

Ten program zwiększa zmienną całkowitą, aż się przepełni.

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

Przepełnienie ze znakiem całkowitym jest zachowaniem niezdefiniowanym. Zwykle w praktyce zawija się, gdy optymalizacje są wyłączone. Po włączeniu optymalizacji kompilatory mogą i x + 1 > xzawsze decydują, że to zawsze prawda.

immibis
źródło
Być może użyć int32_t; 64-bitowa int zajęłaby naprawdę, bardzo, bardzo długo (585 lat, gdyby każda iteracja trwała nanosekundę).
Paul Draper,
11

C ++

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

Dziwny styl komentowania to podstęp. Aluzja: trójkąciki.

Klamka
źródło
To zbyt podstawowy przykład nieskończonej pętli.
Ismael Miguel
64
Te Trigrafie są bardzo nadużywane tutaj :(
TimWolla
75
Prawie czuję, że w standardowej luce, która nie jest już śmieszna, powinny być umieszczane trigrafie.
undergroundmonorail
6
@TheDoctor: ?? / to trójgraniasty znak odwrotnego ukośnika, więc odwrotny ukośnik dzieli linię, w której x jest przypisane 0 do końca komentarza, czyniąc go częścią komentarza.
CasaDeRobison
4
@undergroundmonorail Wysłano
Justin
11

Jawa

Szczególnie podoba mi się ten efekt uboczny optymalizacji autoboxingu:

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");  
    }
  }
}

Ze względu autoboxing, Integerobiekty zachowują się prawie jak zwykły intjest tutaj, z jednym wyjątkiem: i != maxw forpętli porównuje referencje (tożsamość) Spośród Integerobiektów, a nie ich wartość (równość). W przypadku wartości do 100 to zaskakująco „działa”, jednak ze względu na optymalizację w JVM: Java wstępnie przypisuje Integerobiekty do „najczęstszych wartości” i wykorzystuje je ponownie podczas autoboxowania. Tak więc dla wartości do 100 mamy równość tożsamości <==>.

Daniel
źródło
5
Biorąc pod uwagę, że niektórzy ludzie Java nadal uważają przeciążanie operatora C ++ za zło ...
Daniel
Nie potrzebujesz inicjalizacji = new Integer(0), ponieważ i tak inicjujesz wartości. (To może sprawić, że powód będzie mniej oczywisty.)
Paŭlo Ebermann
@ PaŭloEbermann: Dobrze, edytowałem kod.
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;
}

To działa poprawnie w C , licząc w dół od 9 do 1 na standardowe wyjście. Po uruchomieniu w Ruby nie kończy się, ponieważ

0 nie jest wartością fałszywą w Ruby.

histocrat
źródło
Rób języki jednocześnie ... imponująco.
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]]);

Obie pętle używają tej samej zmiennej pętli, więc w zależności od danych wejściowych pętla wewnętrzna może uniemożliwić zakończenie pętli zewnętrznej.

Aleksi Torhamo
źródło
Jaki to język?
RononDex,
@ronondex Javascript
tomsmeding
1
Ach, tak, to Javascript. Pamiętałem o włączeniu podświetlania składni, ale musiałem też zapomnieć o umieszczeniu go w tytule :)
Aleksi Torhamo
1
Uważam to za oczywiste. :-)
rafaelcastrocouto
@rafaelcastrocouto Tak, to w pewnym sensie tak, ale bardzo łatwo go przeoczyć, na przykład podczas przenoszenia pętli z jednej funkcji do drugiej lub po prostu przeglądania kodu. Należy również pamiętać, że tak naprawdę działa to poprawnie w niektórych językach, w tym w C, ze względu na zmienne cieniowanie. :)
Aleksi Torhamo
7

do

Powinno to wydrukować tabelę kodów dla wszystkich znaków ASCII, od 0 do 255. A charjest wystarczająco duże, aby iterować nad nimi.

#include <stdio.h>

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

Wszystkie znaki są mniejsze niż 256. 255 ++ daje 0 z powodu przepełnienia, więc warunek i < 256zawsze obowiązuje. Niektóre kompilatory ostrzegają o tym, inne nie.

Rafał Cieślak
źródło
Wydaje się, że robienie czegoś jest bardziej przydatne, może printf("%3d %2x: %c", i, i, i);w pętli możesz użyć czegoś takiego jak (dla tabeli kodów).
Paŭlo Ebermann
@ PaŭloEbermann: Świetny pomysł.
Rafał Cieślak
Używam tej sztuczki w mojej klasie, z drukowanymi niepodpisanymi znakami między 32 a 128. :)
cpri
7

Pyton

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

tak powinno być exit()i nie exit. Jak rozumiem, exit()to polecenie wyjścia z interpretera Pythona. W tym przypadku wywołanie dotyczy przedstawienia funkcji, a nie funkcji patrz: wyjście-dyskusja . Alternatywnie breakbyłby lepszy wybór.

Willem
źródło
Czy mógłbyś wyjaśnić, co exittak naprawdę jest? Wygląda na klasę, ale do czego służy? Możesz także zmienić print mna, print(m)aby działało to również w Pythonie 3.
Martin Thoma,
1
Tego rodzaju rzeczy ... Jak wtedy, gdy mój elseif nie działał, ponieważ był elif .
Anonimowy Pi
Dzięki @moosezaktualizowana instrukcja drukowania i komunikat spoilera
Willem
6

C ++

Co powiesz na klasyczną C ++ - pułapkę programisty?

int main()
{
   bool keepGoing = false;

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

   return 0;
}
CompuChip
źródło
Nie rozumiem Czy chodzi o używanie. = zamiast ==?
Mhmd,
@ user689 dokładnie. keepGoing = truemiał porównać wartość keepGoing, zamiast tego przypisuje wartość do keepGoing; ponadto cała instrukcja keepGoing = trueocenia true(co pozwala na pisanie takich rzeczy a=b=c=d=0), co prowadzi do nieskończonej pętli.
CompuChip
3
Jest to coraz większy powód do stosowania warunków yoda.
Ryan
@RyanEdwardDougherty Haha, tak, że nigdy nie słyszałam, żeby dzwonili. Za poranny śmiech dzięki.
CompuChip
@RyanEdwardDougherty: Oczywiście == true(lub w stylu Yoda true ==) i tak jest zbędny, a warunek powinien po prostu przeczytać while (keepGoing).
celtschk
6

JavaScript

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

Zmienne używane w 1. i 3. linii są różne od zmiennych używanych w 2. i 3. linii.
Używa się (U + 0061), podczas gdy druga używa Á (U + 0430)

Clyde Lobo
źródło
Nie widzę tutaj problemu. Uruchomiłem i działało dobrze. czego mi brakuje?
Andrew Shepherd,
najprawdopodobniej zadziała to wszędzie, ponieważ Unicode prawdopodobnie zostanie przekonwertowany. Dostałem +1, ponieważ jest najbardziej niewidoczny na świecie!
rafaelcastrocouto
Aby go całkowicie ukryć (zamień á na U + 0430) Jeśli to był twój kod, powodzenia w znalezieniu problemu: var a;var points = 0;function fiftyfifty() {points++;if (Math.random() > 0.5)return true;}; á = fiftyfifty(); while (a === undefined) {á = fiftyfifty();} console.log("Points: " + points);poddałbym się, usunę to na zawsze, wyczyści mój komputer, być może skaner antywirusowy tylko dla pewności i przepisz go całkowicie. EDYCJA: Ponieważ var a = 0; a = 1;nie jest bardzo realistyczna
YoYoYonnY
6

Jawa:

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

„I = i ++” jest dość powszechnym błędem dla początkujących i może być zaskakująco trudne do znalezienia

Richo
źródło
5

C ++

Trochę losowo?

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);
}

Nie wywołuje funkcji, randale zamiast tego wywołuje Randomizer::randfunkcję rekurencyjnie .

calimbak
źródło
5
Dodatkowe nawiasy w instrukcji return, fuj.
David Conrad,
1
To będzie ostatecznie wysypać, choć.
kirbyfan64sos
5

Haskell

Trochę kodu obliczającego czas obliczenia danej wartości funkcji Ackermanna. W przypadku bardzo niskich wartości zwykle kończy się. Na mojej maszynie bardzo niskie wartości oznaczają około 3 5 lub mniej ze skompilowanym kodem i -O. W ghci niskie wartości oznaczają coś w rodzaju 3 3.

'Symbol wydaje się bałagan podświetlanie składni, nie wiem dlaczego. W niektórych miejscach są one potrzebne, więc nie można ich wszystkich usunąć.

Edytuj- zmieniony język.

{-# 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

To powoduje blokadę ruchu. Nić licząca wielokrotnie powoduje, że obliczenia Ackermanna wycofują się, ponieważ dotykają tego samego telewizora.

monokomórka
źródło
oznaczenie go jako lang-hs zamiast lang-haskell wydaje się działać lepiej (jest to jedno z rozszerzeń w
prettifier
5

Java - brak pętli lub rekurencji

Właśnie zacząłem uczyć się wyrażeń regularnych i napisałem swój pierwszy program, aby sprawdzić, czy mój ciąg znaków pasuje do wyrażenia regularnego.

Niestety program nie daje żadnych rezultatów. Podtrzymuje terminal. Proszę o pomoc w znalezieniu problemu. Nie korzystałem z pętli, nie ma żadnej rekurencji. Jestem całkowicie zaskoczony.

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!");
     }
}

Co zrobiłem źle? Dlaczego mój program się nie kończy? Proszę pomóż!

Link Ideone tutaj .

To głupi przykład katastrofalnego cofania . Złożoność wynosi O (2 n / 2 ). Chociaż program może nie działać w nieskończoność, prawdopodobnie przeżyje zarówno żywe, jak i nieożywione obiekty wokół i nie tak dookoła .

diabelnie
źródło
5

do

Potrzebujesz tylko jednej z dwóch pętli, ale ta, której potrzebujesz, zależy od twojego kompilatora.

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);
        }

}

Proste przekroczenie granic, które resetuje i do wartości nie kończącej. Kompilatory mogą różnić się tym, czy przydzielają i powyżej, czy poniżej a na stosie, więc uwzględniłem przekroczenia w obu kierunkach.

Alexis
źródło
5

C / C ++

C ++ zezwala tylko na proste deklaracje zmiennych wbudowanych użyte tutaj, ale równie łatwo jest popełnić ten błąd w zwykłym starym C ...

#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;
}

W wewnętrznej pętli „j” jest porównywane, ale nigdy nie jest zwiększane. („I ++” powinno być w rzeczywistości „j ++”). To nie jest tak podstępna sztuczka, ale raczej faktyczny błąd, który popełniłem w przeszłości;) Coś, na co trzeba uważać.

Dave Ceddia
źródło
2
Debugowanie zajmuje mi zwykle co najmniej 5 minut. Nienawidzę tego, kiedy to robiłem.
ace_HongKongIndependence
4

DO#

Poniżej przedstawiono prostą klasę wykonującą operację arytmetyczną (sumowanie) na dużej tablicy wejściowej za pomocą wątku w tle. Dołączony jest przykładowy program.

Jednak pomimo tego, że jest to dość proste, nigdy się nie kończy. Zwróć uwagę, że nie ma zręczności (podobieństwa postaci, ukryte / brakujące średniki, kaligrafie ;-) itp.)

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;
    }
}

To jest przykład paskudnego błędu w świecie rzeczywistym, który może pojawić się również w twoim kodzie. Zgodnie z modelem pamięci .NET i specyfikacją C # pętla taka jak ta WaitAndGetResultmoże nigdy nie zostać zakończona, chyba że zmienna zostanie określona jako niestabilna, ponieważ jest modyfikowana przez inny wątek. Zobacz to pytanie StackOverflow, aby uzyskać szczegółowe informacje. Błąd zależy od implementacji platformy .NET, więc może mieć na ciebie wpływ lub nie. Ale zwykle wydaje się, że uruchomienie wersji kompilacji na procesorze x64 wyświetla problem. (Próbowałem z „csc.exe / o + / debug- infinite.cs” .)

Mormegil
źródło