あなたの仕事:明らかに終了するはずのプログラムを書くが、それは決して(コンピューターのクラッシュの程度まで)しません。単純なタスクを実行するように見えるようにします:数字を追加したり、何かを印刷したりします...しかし、無限ループに陥ります。
プログラムは実際には予期せぬループに巻き込まれますが、プログラムを非常に明確かつシンプルにしてください。有権者:彼らがいかに「人手不足」であるかについての答えを判断してください!
これは人気コンテストです。クリエイティブになりましょう!
あなたの仕事:明らかに終了するはずのプログラムを書くが、それは決して(コンピューターのクラッシュの程度まで)しません。単純なタスクを実行するように見えるようにします:数字を追加したり、何かを印刷したりします...しかし、無限ループに陥ります。
プログラムは実際には予期せぬループに巻き込まれますが、プログラムを非常に明確かつシンプルにしてください。有権者:彼らがいかに「人手不足」であるかについての答えを判断してください!
これは人気コンテストです。クリエイティブになりましょう!
回答:
var x=prompt('Enter a value under 100');
while (x != 100) {
x=x+1;
}
console.log('End!');
prompt()は文字列を返し、ループは文字「1」を追加します。100に等しくなることはありません。
raw_input
またはPython 3 input
を使用した同等のコードはを発生させTypeError
ます。
+
ここの演算子は文字列の連結であり、加算ではありません。
Cの3種類のwhileループを示す基本的なプログラム例
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ループには、開き中括弧の前に「do」がありません。これは、実際には、次の「nullステートメント」whileループで終了する(x <10)ループ内にdo-whileループを作成します。xはループ内でインクリメントされ、do-whileループの条件でデクリメントされるため、内側のループは終了せず、外側のループも終了しません。最後の「単一ステートメント」ループに到達することはありません。
まだ混乱している場合は、こちらをご覧ください(codegolf.SEはスポイラーのコードブロックを好まないため、外部でホストされています)。
(x --> 0)
var a = true;
(function() {
while(!a){}
alert("infinite");
var a = true;
})();
可変ホイスト:JavaScriptは実際にの2番目の定義を取得し、
var a = true;
関数の先頭でasを宣言し、whileループに入った時点で意味var a;
への割り当てを変更します。a = true;
a
alert
ループの後に追加します。
a = 1
がありa = true
ます。コードにはそのように無限ループが残っていますが、理由は、intからbooleanへのJavaScript変換の奇妙なものではないことが明確になります。
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'ではなく、小文字の 'L'(ロングデータ型)サフィックスが付いた '20' です。数値は6432に達することなく非常にすばやくオーバーフローしますが、ビルドオプションでオーバーフローチェックがオンになっていない限り、プログラムは続行します。
おそらく、Visual Studio 2013(およびおそらく他のバージョンも)はこのコードに対して警告を表示し、「l」ではなく「L」を使用することを推奨します。
l
ように見えるはず1
です!私は愚かだ。:\
精度はどうですか?
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です。浮動小数点数を使用する限り、条件で==または!=を使用しないことを強くお勧めします。
ページに入力ボックスがあると想像してください。
<input onfocus="if (this.value === '') alert('Input is empty!');">
そして今、あなたはそれに何かを入力したい... Chromeで試してみてください:http://jsfiddle.net/jZp4X/。
alert
関数で呼び出される標準のブラウザダイアログボックスはモーダルです。したがって、表示されるとテキストボックスからフォーカスが外されますが、閉じられるとテキストボックスはフォーカスを受け取ります。
#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には符号がないため、条件は常に真です。
g++
それらがなくてもこれについては警告しません。
-Wall --pedantic
とにかく常に使用する必要があります。
-Wsign-compare
で有効にする必要があります-Wextra
。
バッシュ
(ループまたは再帰なしの要求がありました)
#!/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
にメモリを使い果たし、クラッシュする
yes
単なるcoreutilsプログラムです。システムコールではありません。
ファイル内の文字「x」が失われました。それを見つけるためのプログラムが作成されました。
#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に変更しました。彼はまた、常に非負の値を持っていることを知るのに十分なほどアスキーを知っていました。それで彼は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");
}
}
彼は翌日に大混乱に戻った。文字「a」が欠落しており、「abc」を含む「desert_file」にあるはずでしたが、プログラムは永久にそれを検索していました。
Searching file for missing letter a...
彼らは男を解任し、前のバージョンにロールバックしました。作業中のコードでデータ型を最適化してはならないことを覚えています。
しかし、彼らがここで学んだはずの教訓は何ですか?
まず、asciiテーブルを見ると、EOFがないことに気付くでしょう。これは、EOFは文字ではなく、fgetc()から返される特殊な値であり、intに拡張された文字またはファイルの終わりを示す-1を返すことができるためです。
signed charを使用している限り、すべてが正常に機能します。50に等しいcharは、fgetc()によって50に等しいintにも拡張されます。次に、それをcharに変換しなおし、50を保持します。-1またはfgetc()からのその他の出力についても同様です。
しかし、unsigned charを使用するとどうなるかを見てください。fgetc()のcharから始めてintに拡張し、次にunsigned charを取得します。唯一の問題は、unsigned charに-1を保持できないことです。プログラムはEOFと等しくない255として保存しています。
警告
ANSI Cドキュメントのコピーの セクション3.1.2.5の型を見ると、charが署名されているかどうかは実装のみに依存していることがわかります。そのため、コードに潜んでいる非常にトリッキーなバグを見つけたため、その男はおそらく解雇されるべきではありません。コンパイラを変更したり、別のアーキテクチャに移行したりするときに出てくる可能性があります。そのような場合にバグが出たら誰が解雇されるのだろうか;)
PS。プログラムは、Paul A. CarterによるPC Assembly Languageに記載されているバグを中心に構築されました。
適切な入力を使用すると、次の正規表現により、ほとんどのバックトラッキング正規表現エンジンがバックトラッキング地獄に入ります。
^\w+(\s*\w+)*$
"Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"
or などの単純な入力"AVerySimpleInputWhichContainsAnInsignificantSentence."
(両方の文字列を明確にするため引用符で囲んでいます)は、ほとんどのバックトラッキング正規表現エンジンを長時間実行し続けるのに十分です。
(\s*\w+)*
拡張を可能にするので\w+\w+\w+
... ...\w+
つまり、正規表現エンジンは基本的に単語文字列を分割するために考えられるすべての方法を試します。これがバックトラッキングヘルの原因です。
それは簡単に変更することで固定することができます\s*
し\s+
、その後、(\s+\w+)*
のみに拡張することができます\s+\w+\s+\w+
...\s+\w+
。
function thiswillLoop(){
var mynumber = 40;
while(mynumber == 40){
mynumber = 050;
}
return "test";
}
thiswillLoop();
050はJavascriptの8進定数であり、たまたま10進値の40を持っています。
head $ reverse $ (repeat '!') ++ "olleH"
考えてみてください!それは同じですhead $ "Hello" ++ (repeat '!')
、すなわちただ戻るべき'H'
です。
haskellでは、リストは再帰構造であり、最初の要素が最上位にあります。リストに追加するには、これらの要素をすべて展開し、付録を配置し、持ち上げた要素を元に戻す必要があります。無限のリストでは機能しません。同様に、無限のリストを反転しても、魔法のようにあなたの
"Hello"
背中を与えることはありません。いつまでもハングします。
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();
}
}
プログラムは、コマンドラインからの詰まった標準出力ストリームに依存してスタックします。WindowsのWinSXSディレクトリには長い名前のファイルが数千あるため、stdoutを詰まらせることがほぼ保証されており、
waitFor
戻ることができないためプログラムがデッドロックします。
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を押してください;-)
このプログラムは、オーバーフローするまで整数変数をインクリメントします。
#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ビット整数は、本当に、本当に、本当に長い時間がかかります(各反復にナノ秒かかる場合は585年)。
int main()
{
int x = 1;
//why doesn't this code terminate??/
x = 0;
while(x) {} //no-op/
return 0;
}
奇妙なコメントスタイルがトリックです。ヒント:トライグラフ。
オートボクシング最適化のこの副作用が特に気に入っています。
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
オブジェクトはint
ここではほとんどプレーンのように動作しますが、1つの例外i != max
がありfor
ます。ループ内では、オブジェクトの値(等式)ではなく、オブジェクトの参照(同一性)を比較しますInteger
。最大100の値の場合、JVMの最適化により、これは驚くほど「機能」します。JavaInteger
は、「最も一般的な値」にオブジェクトを事前に割り当て、オートボクシング時にそれらを再利用します。したがって、最大100の値に対して、同一性<==>が等しくなります。
= new Integer(0)
とにかく値を初期化するので、初期化は必要ありません。(これにより、理由がより明白でなくなる可能性があります。)
#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では正しく機能し、STDOUTでは9から1にカウントダウンします。Rubyで実行すると、終了しません。
Rubyでは0は偽の値ではありません。
// 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]]);
両方のループは同じループ変数を使用するため、入力に応じて、内側のループは外側のループが終了しないようにすることができます。
これにより、0〜255のすべてのASCII文字のコードテーブルが出力されます。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);
ます。たぶんあなたのループで(コードテーブル用)のようなものを使ってください。
a = True
m = 0
while a:
m = m + 1
print(m)
if m == 10:
exit
あるべきで
exit()
はないexit
。私が理解しているようにexit()
、Pythonインタープリターを終了するコマンドです。この場合、呼び出しは関数の表現に対するものであり、関数に対するものではありません:exit-discussionを参照してください。あるいはbreak
、より良い選択でしょう。
exit
実際に何であるか説明していただけますか?クラスのように見えますが、何のために使用されますか?また、変更される可能性print m
にprint(m)
、これはまた、Pythonの3で動作するように
@moose
更新された印刷ステートメントとネタバレメッセージに感謝します
古典的なC ++プログラマのtrapはどうですか?
int main()
{
bool keepGoing = false;
do {
std::cout << "Hello, world!\n";
} while( keepGoing = true );
return 0;
}
keepGoing = true
の値を比較するためのものでしたがkeepGoing
、代わりに値を割り当てますkeepGoing
; さらに、ステートメント全体がkeepGoing = true
評価されtrue
(これによりのような記述が可能になりますa=b=c=d=0
)、無限ループになります。
== true
(またはヨーダスタイルtrue ==
)はとにかく冗長であり、条件は単に読み取る必要がありますwhile (keepGoing)
。
Javascript
var а = 0;
a = 1;
while(а<10){
a++;
}
1行目と3行目で使用される変数は、2行目と3行目で使用される変数とは異なります。
1つは(U + 0061)を使用し、もう1つはа(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;
あまり現実的ではないため
少しランダム?
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
ます。
アッカーマン関数の特定の値の計算のタイミングをとるコード。非常に低い値の場合、通常は終了します。私のマシンでは、非常に低い値は、コンパイルされたコードとで3 5以下のようなものを意味し-O
ます。ghciでは、低い値は3 3のようなものを意味します。
'
記号は台無し構文の強調表示を、なぜわからないように思われます。いくつかの場所ではそれらが必要なので、それらのすべてを削除することはできません。
編集-変更された言語。
{-# 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
これにより、ライブロックが発生します。カウントスレッドは、Ackermannの計算が同じTVarに触れるため、繰り返しロールバックします。
正規表現を学び始めたばかりで、文字列が正規表現と一致するかどうかをテストする最初のプログラムを作成しました。
残念ながら、プログラムは結果を生成しません。端末を保持します。問題を見つけるのを手伝ってください。私はループを使用していません。再帰は含まれていません。私は完全に困惑しています。
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)です。このプログラムは無期限に実行されないかもしれませんが、おそらく生きているオブジェクトと生きていないオブジェクトの両方の周りで生き残ります。
必要なのは2つのループのうち1つだけですが、必要なループはコンパイラーによって異なります。
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を非終了値にリセットする単純な境界オーバーラン。コンパイラーは、スタック上のaの上または下にiを割り当てるかどうかが異なる可能性があるため、両方向のオーバーランを含めました。
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 ++」でなければなりません)。これはそれほど卑劣なトリックではありませんが、私が過去に犯した実際のエラーの多くです;)
以下は、バックグラウンドスレッドを使用して大きな入力配列に対して算術演算(合計)を実行する単純なクラスです。サンプルプログラムが含まれています。
ただし、非常に簡単ですが、終了することはありません。巧妙なものがないことに注意してください(キャラクターに似たもの、隠された/欠けているセミコロン、トライグラフ;-)など)
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#仕様に従って
WaitAndGetResult
、変数をvolatileとして指定しない限り、別のスレッドによって変更されるため、ループのようなループは終了しない可能性があります。詳細については、このStackOverflowの質問を参照してください。このバグは.NET実装に依存しているため、影響を受ける場合と影響しない場合があります。しかし、通常、x64プロセッサでリリースビルドを実行すると問題が表示されるようです。(「csc.exe / o + / debug- infinite.cs」で試しました。)