Почему это не заканчивается? [закрыто]


95

Ваша задача: написать программу, которая должна завершаться, но никогда (в случае сбоя компьютера) этого не происходит. Сделать так, чтобы он выполнял простую задачу: добавление чисел, распечатка чего-либо, ... Но это просто попадает в бесконечный цикл.

Постарайтесь сделать вашу программу очень понятной и простой, в то время как она фактически застрянет в непредвиденном цикле. Избиратели: судите ответы, насколько они "закулисны"!

Это конкурс популярности: будь креативным!


6
Может кто-нибудь объяснить, что я могу сделать, чтобы сделать этот вопрос менее широким? Я новенький здесь. Спасибо!
Number9

6
Это будет просто большой список опечаток и ошибок новичка, которые вызывают петли.
Билл Вуджер

Интересный вопрос, но я пока не видел по-настоящему креативных ответов. Я обещаю голоса тем, кто не использует петли или очевидную рекурсию!
Приближается к

14
Я не знаю, имеет ли это значение, но в настоящий момент мой Microsoft Office ведет себя именно так.
Уровень Река St

1
Я голосую, чтобы закрыть этот вопрос как не по теме, потому что закулисные вызовы больше не обсуждаются здесь. meta.codegolf.stackexchange.com/a/8326/20469
кошка

Ответы:


185

Javascript

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

prompt () возвращает строку, и цикл добавляет символ «1», он никогда не будет равен 100.


13
Вы получили меня с этим ... (на самом деле) примеры с более высоким рейтингом просто злоупотребляют синтаксисом ... но этот классный!
bwoebi

4
Хром на Kubuntu стал не отвечать, все зависало и мне пришлось хард ресет :)
Сергей Тельшевский

4
@Vlakarados: Python не будет выполнять неявное преобразование типов, которое делает Javascript. На Python эквивалентный код, использующий raw_inputили Python 3, inputвызывает a TypeError.
user2357112

2
Не проверяется тот факт, что значение на самом деле меньше 100, поэтому оно обычно останавливается, когда вы вводите «100»: '- (
C.Champagne

1
@Sankalp, +оператор здесь - это конкатенация строк, а не сложение.
Майкл М.

87

С

Просто базовый пример программы, которая иллюстрирует три различных типа циклов while в 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;
}

В то время как циклы не имеют «до» до открытия фигурной скобки. Это фактически создает цикл do-while внутри цикла (x <10), который заканчивается следующим «нулевым оператором» цикла while. Поскольку x увеличивается внутри цикла, а затем уменьшается в условии цикла do-while, внутренний цикл никогда не завершается, как и внешний цикл. Цикл «одного оператора» в конце никогда не достигается.

Если вы все еще в замешательстве, посмотрите здесь (внешний хостинг, потому что codegolf.SE не любит блоки кода в спойлерах).


8
Ха-ха, я разобрался с этим, прежде чем посмотреть на спойлер решения. : P
Джо З.

54
Почему вы упустили такую ​​прекрасную возможность использовать оператора "уходит"? (x --> 0)
CorsiKa

2
Ух ты. Это чудесно зло. Я взял четыре чтения, чтобы найти его.
Патрик М

1
@JoeZ. Слишком просто. Наиболее одобренное решение было лучше. Тот, который я не нашел.
Аноним Пи

3
@Hat Guy, у Bash есть синтаксис for; do и while; do, так что я могу видеть, как это сбивает с толку людей, даже если они знакомы с языками не-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;
})();

Подъем переменной: JavaScript фактически захватит мое второе определение var a = true;, объявит его в верхней части функции как var a;и изменит мое назначение на a = true;значение, aкоторое будет неопределенным во время входа в цикл while.


3
Не могли бы вы добавить лучшее объяснение того, почему это никогда не заканчивается? Пожалуйста,
углубитесь

1
@ Number9 Надеюсь, это поможет, у Google есть намного лучшие примеры, чем эта;)
Newbrict

25
Святое дерьмо это даже хуже, чем вставка точки с запятой. +1!
Томсминг

2
Единственная проблема, которую я вижу с этой программой, заключается в том, что она не выглядит так, как будто выполняет простую задачу ... похоже, что по сути она ничего не должна делать. Может быть, добавить alertпосле цикла.
PeterT

2
Вы должны измениться a = 1на a = true. Код все еще будет иметь бесконечный цикл таким образом, но будет более понятно, что причина не в некоторой причуде в преобразовании JavaScript из int в логические значения.
Рори О'Кейн

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

Числовой литерал в первой строке функции - это не «201», а «20» с суффиксом «L» ( длинный тип данных) в нижнем регистре . Число будет переполнено довольно быстро, даже не достигнув 6432, но программа продолжит работу, если проверка переполнения не была включена в опциях сборки.
Очевидно, что Visual Studio 2013 (и, возможно, и другие версии) выдает предупреждение для этого кода, рекомендуя использовать «L» вместо «l».


12
О, lэто должно выглядеть как 1! Я тупой. : \
Джо З.

6
Предложение по улучшению: замените 1 в ожидаемом разделе вывода также на ls (легче обнаружить странный символ, когда у вас есть реальные 1 для сравнения)
Аллен Гулд

3
Да, это, кажется, довольно специфично для окружающей среды. Шрифт @ Michael очень отличается от шрифта на моем домашнем компьютере ( imgur.com/PKIuJpr - Chrome, Windows 8), и этот прием, похоже, работает лучше на моем рабочем компьютере, чем на моем домашнем компьютере, хотя они довольно похожи спецификации. Браузер моего телефона, кажется, не показывает код с фиксированным шрифтом, и хитрость не работает на нем вообще.
BenM

1
FTR, вот как это выглядит на моем рабочем компьютере ( imgur.com/Opfs3BH - Firefox, Windows 7). Я считаю, что можно было даже обмануть довольно проницательных людей.
BenM

15
ПОЧЕМУ ЛЮДИ ХОТЯТ НАДЕЖДАТЬСЯ ИЗ ХАРАКТЕРОВ, КОТОРЫЕ СМОТРИТ ОДНОВРЕМЕННО?
Анонимный Пи

39

С

Как насчет точности?

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

Представьте, что вы должны хранить диапазон целых чисел <0; 3> в памяти компьютера. В этом диапазоне всего 4 целых числа (0,1,2,3). Достаточно использовать 2 бита, чтобы сохранить это в памяти. Теперь представьте, что вам нужно хранить диапазон чисел с плавающей точкой <0; 3>. Проблема в том, что в этом диапазоне бесконечное число чисел с плавающей точкой. Как хранить бесконечное количество номеров? Это невозможно. Мы можем хранить только конечное число чисел. Вот почему некоторые числа, такие как 0,1, на самом деле разные. В случае 0,1 это 0,100000000000000006. Настоятельно рекомендуется не использовать == или! = В условиях, когда вы используете числа с плавающей запятой.


1
Как это работает?
Mhmd

5
Ошибки округления. 0.1 на самом деле 0.100000000000000006, потому что 0,1 в двоичном формате как 1/3 в десятичном виде - это двоичное расширение является бесконечным и периодическим.
Орион

3
Не совсем ошибка округления. Значения с плавающей точкой являются приблизительными представлениями числа. Выполнение точных сравнений между приблизительными значениями не сработает.
AKHolland

4
Вот почему вы (почти) никогда не должны сравнивать числа с плавающей запятой / double для равенства.
Эмануэль Ландехольм

1
Я ждал, чтобы увидеть это. Приятно.
Дэвид Конрад

33

HTML / JavaScript

Представьте, что у вас есть поле ввода на вашей странице:

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

А теперь вы хотите что-то набрать в нем ... Попробуйте в Chrome: http://jsfiddle.net/jZp4X/ .

Стандартное диалоговое окно браузера, вызываемое с помощью alertфункции, является модальным, поэтому, когда оно отображается, оно убирает фокус из текстового поля, но когда оно закрывается, текстовое поле получает фокус обратно.


5
в Firefox ввод не имеет автофокуса при закрытии оповещений, и со второго раза он предлагает мне не показывать больше оповещений, и тогда я могу нормально писать в текстовом поле
Einacio

6
Хороший. +1 за отсутствие петель или рекурсии.
Приближается к

5
Никаких циклов ни в Firefox, ни в Chrome. FF показывает предупреждение один раз, когда в диалоге нажимают, вы отклоняете его, и это конец. Можете нажать еще раз, чтобы повторить. Chrome делает то же самое, но оставляет поле сфокусированным, и вы даже можете ввести его. Извините, может быть, на старых версиях это было проблемой, но не больше.
RomanSt

6
IE11 работает точно так же, как Chrome для меня. Я думаю, что вы случайно нашли пример чего-то, что работает по одному в каждом современном браузере на Mac, и по-разному в каждом современном браузере в Windows!
RomanSt

1
Работает нормально (без петель) на 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;
}

Условие i >=0всегда верно, потому что size_t без знака.



2
@Synxis Да, компиляторы делают. Но только если вы включите предупреждения компилятора. g++не буду предупреждать вас об этом без них.
FDinoff

5
Вы должны всегда использовать в -Wall --pedanticлюбом случае.
Мартин Юдинг

3
@queueoverflow Предупреждение не отображается только с этими флагами. Вам нужно, -Wsign-compareкоторый может быть включен с -Wextra.
FDinoff

7
Один штрих на -педантике. #pedantic
Дэвид Конрад

29

удар

(Был запрос на отсутствие циклов или рекурсии)

#!/bin/bash

# Demo arrays

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

echo $foo

echo ${foo[0]}

foo[2] = `yes`

echo $foo

echo ${foo[2]}

Вместо назначения строки 'yes' для foo [2], это вызывает системную команду yes, которая заполняет foo [2] бесконечной суммой "yes \ n".


В конце концов не хватает bashпамяти и вылетает
Digital Trauma

4
Да, действительно так и есть. Но крушение было вроде разрешено вопросом :)
GreenAsJade

Да, просто наблюдение :). Upvoted.
Цифровая травма

На самом деле, я считаю, что программы в этом маленьком компе, которые фактически
приводят к поломке

Исправление: yesэто просто программа coreutils. Не системный вызов.
Мниип

28

С

Буква "х" была потеряна в файле. Программа была написана, чтобы найти это:

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

Он был скомпилирован и запущен, и наконец он кричал:

Hurray, letter lost in the file is finally found!

В течение многих лет письма спасались таким образом, пока не пришел новый парень и не оптимизировал код. Он был знаком с типами данных и знал, что лучше использовать без знака, чем со знаком, для неотрицательных значений, поскольку он имеет более широкий диапазон и обеспечивает некоторую защиту от переполнения. Таким образом, он изменил int на unsigned int . Он также знал ASCII достаточно хорошо, чтобы знать, что они всегда имеют неотрицательную ценность. Таким образом, он также изменил char на unsigned char . Он скомпилировал код и пошел домой, гордясь хорошей работой, которую он сделал. Программа выглядела так:

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

Он вернулся в хаос на следующий день. Буква «а» отсутствовала, и, хотя она должна была находиться в файле «desert_file», содержащем «abc», программа искала его навсегда, распечатывая только:

Searching file for missing letter a...

Они уволили парня и откатились к предыдущей версии, вспомнив, что нельзя оптимизировать типы данных в рабочем коде.

Но какой урок они должны были извлечь здесь?

Прежде всего, если вы посмотрите на таблицу ascii, вы заметите, что EOF отсутствует. Это потому, что EOF - это не символ, а специальное значение, возвращаемое функцией fgetc (), которая может возвращать символ, расширенный до int, или -1, обозначающий конец файла.
Пока мы используем подписанный char, все работает хорошо - char, равный 50, также расширяется с помощью fgetc () до int, равного 50. Затем мы преобразуем его обратно в char и оставляем 50. То же самое происходит для -1 или любого другого вывода, получаемого из fgetc ().
Но посмотрите, что происходит, когда мы используем unsigned char. Мы начинаем с символа в fgetc (), расширяем его до int, а затем хотим иметь неподписанный символ. Единственная проблема в том, что мы не можем сохранить -1 в неподписанном символе. Программа хранит его как 255, который больше не равен EOF.

Предостережение
Если вы взглянете на раздел 3.1.2.5 Типы в копии документации ANSI C, вы обнаружите, что то, является ли char подписанным или нет, зависит исключительно от реализации. Так что парня, вероятно, не стоит увольнять, поскольку он обнаружил в коде очень хитрую ошибку. Это может произойти при смене компилятора или переходе на другую архитектуру. Интересно, кого бы уволили, если бы баг вышел в таком случае;)

PS. Программа была построена вокруг ошибки, упомянутой в языке сборки ПК Полом А. Картером


7
Мне нравится, что есть история с решением.
jpmc26

Ха - ха! Я думаю, что это единственный. Спасибо, что прочитали!
Легат

1
Я люблю вас. Накорми меня своими историями,
пожалуйста

Это абсолютно великолепно!
kirbyfan64sos

21

Regex

При соответствующем вводе следующее регулярное выражение может привести к тому, что большинство движков обратного отслеживания попадут в ад обратного отслеживания:

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

Простого ввода, такого как "Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"или "AVerySimpleInputWhichContainsAnInsignificantSentence."(обе строки приведены для ясности), достаточно для того, чтобы большинство движков обратного отслеживания работало в течение длительного времени.

Так как (\s*\w+)*допускает расширение \w+\w+\w+... \w+, это означает, что механизм регулярных выражений в основном попробует все возможные способы разбить строку символов слова . Это источник отступления ада.
Это может быть легко исправлена путем изменения \s*в \s+, то (\s+\w+)*можно разложить только \s+\w+\s+\w+... \s+\w+.


3
Я ненавижу откатывать движки регулярных выражений.
Дэвид Конрад

2
Сначала я попробовал это с Perl, но похоже, что Perl может заметить петлю здесь. Я не пробовал AWK, потому что никакое регулярное выражение не может вызвать такое поведение в AWK. PHP автоматически делает регулярное выражение, которое занимает слишком много времени, чтобы соответствовать неудаче (что глупо, но для вас это PHP - он автоматически вставляет ошибки в программы). Тем не менее, это на самом деле работает в Python.
Конрад Боровски

1
@xfix: Что касается того, почему Perl удалось избежать возврата в ад, эта статья объясняет причину. Тем не менее, этого недостаточно для случая, как показано здесь (прокрутите вниз до раздела производительности). PHP (фактически библиотека PCRE) имеет предел возврата, и соответствующая программа всегда должна проверять возвращаемое значение функции, чтобы решить, было ли выполнение остановлено или завершено.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Это так скользко.
alvonellos

20

JavaScript

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

050 - восьмеричная константа в Javascript, и она имеет десятичное значение 40.


73
Я нахожу это очевидным. :-)
Джастин

6
Я не знал, что JavaScript сделал это. Но после прочтения кода я сказал: «050 должен быть каким-то образом представлять 40, вероятно, базу 8 или что-то в этом роде»
Cruncher

Это должно быть лучше скрыто.
Пауло Эберманн

Это очевидно ..
Оливер Ни

18

Haskell

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

Ну, подумай об этом! Это было бы так же, как head $ "Hello" ++ (repeat '!'), то есть должно просто вернуться 'H'.

В списках haskell представлены рекурсивные структуры, причем первый элемент является самым верхним. Чтобы добавить в список, вы должны развернуть все эти элементы, поместить свое приложение и вернуть поднятые элементы обратно. Это не сработает в бесконечном списке. Точно так же, обращение бесконечного списка волшебным образом не вернет вам "Hello"спину. Это будет просто висеть вечно.


1
Жаль, что на самом деле это не работает: - /
Джон Дворжак

1
Как это не работает?
Данмкардл

@crazedgremlin, когда я тестировал это на Fedora, операционная система в конечном итоге убила процесс. (<5 минут), потому что он израсходовал всю память в системе.
FDinoff

Интересно! Я не осознавал, что это случилось. Я не рискну все время прогуливаться по всей территории памяти.
Данмкардл

4
Это все еще верное решение: оно не завершается, оно работает столько, сколько может, пока система больше не сможет его поддерживать ...
GreenAsJade

16

Java под 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();
    }
}

Программа использует застрявший стандартный поток вывода из командной строки, чтобы застрять. В каталоге WinSXS в Windows есть несколько тысяч файлов с длинными именами, поэтому почти гарантировано засорение stdout, а waitForвозврат невозможен, поэтому программа заблокирована


1
Может быть, я плотный, но не вернется ли это в конце концов? Это может занять некоторое время. Может быть, я не понимаю, что вы подразумеваете под «засорением».
Астери

4
если поток не очищен, блоки программы уже вызвали некоторые головные боли, поэтому я использовал его; длинный каталог только гарантирует, что буфер будет заполнен
masterX244

Ах, понял. Приятно! +1
астери

15

Чтобы сравнить яблоки и апельсины ... в C

Я впечатлен тем, что здесь нет фрагмента кода, использующего goto... (Вы знаете: Goto - это зло! )

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

Сон только для того, чтобы читать его. Нажмите ^ C, если у вас нет бесконечного количества времени, чтобы ждать чего-то, что никогда не происходит ;-)


9
Ты подлый ублюдок, Гото невиновен в этом :)
orion

random () используется vodoo?
masterX244

1
ааа, "2"! = 2; получил
masterX244

2
Ну, «2», вероятно, никогда не может быть 2, но если вы используете большее число (и кратное по крайней мере 4), это может произойти;)
orion

1
@orion: Да, вы правы, это может быть. И goto все еще злой, но плохие кастинги еще более злые!
max.haredoom

12

C, с некоторыми оптимизирующими компиляторами

Эта программа увеличивает целочисленную переменную до тех пор, пока она не переполнится.

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

Целочисленное переполнение со знаком - неопределенное поведение. Обычно на практике это переносится, когда оптимизации отключены. С оптимизацией компиляторы могут и действительно решить, что x + 1 > xэто всегда так.


Возможно использовать int32_t; 64-битное int займет очень, очень, очень много времени (585 лет, если каждая итерация занимает наносекунду).
Пол Дрейпер

11

C ++

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

Странный стиль комментирования - хитрость. Подсказка: триграфы.


Это слишком простой пример бесконечного цикла.
Исмаэль Мигель

64
Эти триграфы ооочень используются здесь :(
TimWolla

75
Я почти чувствую, что триграфы должны быть помещены в стандартные лазейки, которые уже не смешные.
подземный

6
@TheDoctor: ?? / - это триграф для символа обратной косой черты, поэтому обратная косая черта объединяет строку, где x присваивается 0 в конце комментария, что делает его частью комментария.
CasaDeRobison

4
@undergroundmonorail Опубликовано
Джастин

11

Ява

Мне особенно нравится этот побочный эффект оптимизации автобокса:

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

Из-за автобокса Integerобъекты ведут себя почти как обычные ints, за одним исключением: циклы i != maxin forсравнивают ссылки (идентичность) Integerобъектов, а не их значение (равенство). Для значений до 100 это удивительно «работает» тем не менее из-за оптимизации в JVM: Java предварительно выделяет Integerобъекты для «наиболее распространенных значений» и повторно использует их при автобоксировании. Таким образом, для значений до 100 мы имеем равенство тождества <==>.


5
Учитывая, что некоторые ребята из Java до сих пор считают перегрузку операторов C ++ злом ...
Даниэль

Вам не нужна инициализация = new Integer(0), так как вы все равно инициализируете значения впоследствии. (Это может сделать причину менее очевидной.)
Paŭlo Ebermann

@ PaŭloEbermann: Хорошо, я редактировал код.
Даниэль

9

Рубин / С

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

Это работает правильно в C , считая от 9 до 1 в STDOUT. При запуске в Ruby он не завершается, потому что

0 не является ложным значением в Ruby.


У языков сразу ... впечатляет.
Пол Дрейпер

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

Оба цикла используют одну и ту же переменную цикла, поэтому в зависимости от входа внутренний цикл может не допустить завершения внешнего цикла.


Какой это язык?
RononDex

@ronondex Javascript
Томсминг

1
Ах да, это Javascript. Я помнил, чтобы включить подсветку синтаксиса, но должен был забыть добавить его в заголовок тоже :)
Алекси Torhamo

1
Я нахожу это очевидным. :-)
rafaelcastrocouto

@rafaelcastrocouto Да, это так, но это также очень легко пропустить, например, при перемещении цикла из одной функции в другую или просто беглый взгляд на код. Кроме того, обратите внимание, что это действительно работает правильно в некоторых языках, включая C, из-за переменных теней. :)
Алекси Торхамо

7

С

Это должно напечатать таблицу кодов для всех символов ASCII, от 0 до 255. A charдостаточно велик, чтобы перебирать их.

#include <stdio.h>

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

Все символы меньше 256. 255 ++ дает 0 из-за переполнения, поэтому условие i < 256всегда выполняется. Некоторые компиляторы предупреждают об этом, некоторые нет.


Чтобы сделать это, кажется, сделать что-то более полезное, возможно, использовать что-то вроде printf("%3d %2x: %c", i, i, i);(для таблицы кода) в вашем цикле.
Пауло Эберманн

@ PaŭloEbermann: отличная идея.
Rafał Cieślak

Я использую эту уловку в своем классе, с печатными неподписанными символами между 32 и 128. :)
cpri

7

питон

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

так должно быть exit()и нет exit. Насколько я понимаю, exit()это команда выхода из интерпретатора Python. В этом случае вызов к представлению функции, а не к функции, см .: выход-обсуждение . В качестве альтернативы breakбудет лучшим выбором.


Не могли бы вы объяснить, что на exitсамом деле? Кажется, это класс, но для чего он используется? Вы также можете перейти print mна print(m)так, чтобы это также работало с Python 3.
Martin Thoma

1
Такие вещи ... Например, когда мой elseif не работал, потому что это был elif .
Анонимный Пи

Спасибо @mooseобновленное заявление печати и сообщение спойлера
Willem

6

C ++

Как насчет классической C ++ - ловушки программиста?

int main()
{
   bool keepGoing = false;

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

   return 0;
}

Я не понимаю этого? Это об использовании. = вместо ==?
Mhmd

@ user689 точно. keepGoing = trueпредназначалось для сравнения значения keepGoing, вместо этого оно присваивает значение keepGoing; Кроме того, весь оператор keepGoing = trueоценивает true(что позволяет вам писать такие вещи, как a=b=c=d=0), приводя к бесконечному циклу.
CompuChip

3
Это еще одна причина использовать условия йода.
Райан

@RyanEdwardDougherty Ха-ха, я никогда не слышал, чтобы их звали. За утренний смех спасибо.
CompuChip

@RyanEdwardDougherty: Конечно == true(или в стиле Йоды true ==) все равно избыточно, и условие должно просто читаться while (keepGoing).
celtschk

6

Javascript

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

Переменные, используемые в 1-й и 3-й строке, отличаются от переменных, используемых во 2-й и 3-й строке.
Один использует в (U + 0061) , в то время как другие используют а (U + 0430)


Я не вижу здесь проблемы. Я запустил его, и он работал нормально. Что мне не хватает?
Эндрю Шеферд

это, скорее всего, будет работать везде, так как Unicode, вероятно, будет преобразован. Получил +1, так как он самый невидимый, какой только можно получить!
rafaelcastrocouto

Просто, чтобы полностью скрыть это (замените U на U + 0430). Если бы это был ваш код, удачи в поиске проблемы: var a;var points = 0;function fiftyfifty() {points++;if (Math.random() > 0.5)return true;}; á = fiftyfifty(); while (a === undefined) {á = fiftyfifty();} console.log("Points: " + points);я бы отказался, навсегда удалил это, почистил свой компьютер, возможно, вирусный сканер, просто чтобы быть уверенным, и переписать его полностью. РЕДАКТИРОВАТЬ: Потому var a = 0; a = 1;что не очень реалистично
YoYoYonnY

6

Ява:

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 ++» - довольно распространенная ошибка новичка, и найти ее на удивление сложно


5

C ++

Немного случайного?

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

Не вызывает функцию, randа вызывает рекурсивно Randomizer::randфункцию.


5
Лишние скобки в ответе, чёрт.
Дэвид Конрад

1
Это будет в конечном итоге segfault, хотя.
kirbyfan64sos

5

Haskell

Некоторый код на время вычисления заданного значения функции Аккермана. Для очень низких значений это обычно заканчивается. На моей машине очень низкие значения означают что-то вроде 3 5 или меньше с скомпилированным кодом и-O . В ghci низкие значения означают что-то вроде 3 3.

'Символ , кажется, запутались подсветка синтаксиса, не знаю , почему. В некоторых местах они необходимы, поэтому не могут удалить их все.

Edit- изменил язык.

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

Это вызывает livelock. Поток подсчета постоянно вызывает откат вычисления Аккермана, поскольку они касаются одного и того же TVar.


пометка его как lang-hs вместо lang-haskell, кажется, работает лучше (это одно из расширений в Google Prettifier )
Einacio

5

Java - нет циклов или рекурсии

Я только начал изучать регулярные выражения и написал свою первую программу для проверки соответствия моей строки регулярному выражению.

К сожалению, программа не дает никакого результата. Это держит терминал. Пожалуйста, помогите в поиске проблемы. Я не использовал циклы, рекурсия не задействована. Я полностью сбит с толку.

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

Что я сделал не так? Почему моя программа не заканчивается? Пожалуйста помоги!

Идеальная ссылка здесь .

Это глупый пример катастрофического возврата . Сложность O (2 n / 2 ). Хотя программа не может работать бесконечно, она, вероятно, переживет как живые, так и неживые объекты вокруг, а не вокруг .


5

С

Вам нужен только один из двух циклов, но какой вам нужен, зависит от вашего компилятора.

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

}

Простое переполнение границ, которое сбрасывает i до бесконечного значения. Компиляторы могут различаться в зависимости от того, размещают ли они i над или под a в стеке, поэтому я включил переполнения в обоих направлениях.


5

C / C ++

C ++ просто допускает легкие встроенные объявления переменных, используемые здесь, но так же легко сделать эту ошибку в простом старом 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;
}

Во внутреннем цикле 'j' сравнивается, но никогда не увеличивается. (На самом деле «i ++» должен быть «j ++»). Это не столько хитрая уловка, сколько реальная ошибка, которую я допустил в прошлом;) На что-то стоит обратить внимание.


2
Обычно на отладку у меня уходит не менее 5 минут. Я ненавижу это, когда я сделал это.
ace_HongKongIndependence

4

C #

Ниже приведен простой класс, выполняющий арифметическую операцию (суммирование) для большого входного массива с использованием фонового потока. Пример программы включен.

Однако, хотя это довольно просто, оно никогда не заканчивается. Обратите внимание, что здесь нет ловкости рук (двойники символов, скрытые / пропущенные точки с запятой, триграфы ;-) и т. Д.)

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

Это пример реальной неприятной ошибки, которая также может появиться в вашем коде. В соответствии с моделью памяти .NET и спецификацией C # цикл, такой как цикл in, WaitAndGetResultможет никогда не завершиться, если вы не укажете переменную как volatile, потому что она изменена другим потоком. Посмотреть этот вопрос StackOverflow для деталей. Ошибка зависит от реализации .NET, поэтому она может повлиять или не повлиять на вас. Но обычно запуск релизной сборки на процессоре x64, кажется, показывает проблему. (Я попробовал это с «csc.exe / o + / debug- infinite.cs» .)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.