您的任务:编写一个显然应该终止的程序,但永远不会(在计算机崩溃的情况下)终止。使它看起来像应该执行的简单任务:加号,打印内容,...但是它只是陷入无限循环中。
尝试使您的程序非常清晰和简单,而实际上它会陷入无法预料的循环中。选民:评判他们“多么卑鄙”的答案!
这是一场人气竞赛:有创意!
您的任务:编写一个显然应该终止的程序,但永远不会(在计算机崩溃的情况下)终止。使它看起来像应该执行的简单任务:加号,打印内容,...但是它只是陷入无限循环中。
尝试使您的程序非常清晰和简单,而实际上它会陷入无法预料的循环中。选民:评判他们“多么卑鄙”的答案!
这是一场人气竞赛:有创意!
Answers:
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中的三种不同的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循环。这实际上在(x <10)循环内创建了一个do-while循环,该循环由以下“空语句” while循环终止。由于x在循环内部递增,然后在do-while循环的条件下递减,因此内部循环永远不会终止,外部循环也不会终止。永远不会到达最后的“单语句”循环。
如果您仍然感到困惑,请看这里(外部托管,因为codegolf.SE不喜欢扰流板上的代码块)。
(x --> 0)
var a = true;
(function() {
while(!a){}
alert("infinite");
var a = true;
})();
变量提升:JavaScript实际上将获取我的第二个定义
var a = true;
,在函数顶部将其声明为var a;
,然后将我的赋值修改a = true;
为a
在进入while循环时未定义的含义。
alert
在循环之后添加一个。
a = 1
为a = true
。这样,代码仍将具有无限循环,但更清楚的是,原因不是JavaScript从int到boolean的转换中有一些古怪之处。
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
function 调用的标准浏览器对话框是模态的,因此在显示时,它将焦点从文本框中移出,但是在取消显示时,文本框将接收焦点。
#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
始终为true,因为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
,该命令以永无止境的“ yes \ n”填充foo [2]。
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。他也非常了解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");
}
}
第二天他又遭受了重创。字母“ a”丢失了,即使应该在包含“ abc”的“ desert_file”中,程序也一直在搜索它,仅打印出来:
Searching file for missing letter a...
他们解雇了那个家伙,回滚到以前的版本,以为永远不要在工作代码中优化数据类型。
但是他们在这里应该学到什么呢?
首先,如果您查看ascii表,您会发现没有EOF。这是因为EOF不是字符,而是从fgetc()返回的特殊值,该值可以返回扩展到int的字符或表示文件结尾的-1。
只要我们使用带符号的char,一切都可以正常工作-等于50的char也可以通过fgetc()扩展为等于50的int。然后我们将其转换回char并仍然有50。-1或任何其他来自fgetc()的输出也会发生同样的情况。
但是看看当我们使用无符号字符时会发生什么。我们从fgetc()中的char开始,将其扩展为int,然后想要一个未签名的char。唯一的问题是我们不能在无符号字符中保留-1。程序将其存储为255,不再等于EOF。
警告
如果您查看ANSI C文档副本中的 3.1.2.5类型一节,您会发现是否对char签名仅取决于实现。因此,可能他不应该被解雇,因为他发现代码中隐藏着一个非常棘手的错误。更改编译器或移至其他体系结构时可能会出现。我不知道如果在这种情况下出现错误,谁会被解雇;)
PS。程序是根据Paul A. Carter在PC汇编语言中提到的bug构建的。
通过适当的输入,以下正则表达式可以使大多数回溯正则表达式引擎进入回溯地狱:
^\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+
。
function thiswillLoop(){
var mynumber = 40;
while(mynumber == 40){
mynumber = 050;
}
return "test";
}
thiswillLoop();
050是Javascript中的一个八进制常量,它的十进制值为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
... 的代码(您知道: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位的int会花很长的时间(如果每次迭代花费一纳秒,则将花费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
在这里的行为几乎与plain s相同,但有一个例外:循环中的i != max
infor
比较对象的引用(标识)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中运行时,它不会终止,因为
0在Ruby中不是一个假值。
// 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]]);
两个循环都使用相同的循环变量,因此,取决于输入,内部循环可以防止外部循环完成。
这应该为所有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);
在循环中使用类似的东西(对于代码表)。
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 ++程序员陷阱如何?
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
(或Yoda风格true ==
)是多余的,条件应该简单地阅读while (keepGoing)
。
Java脚本
var а = 0;
a = 1;
while(а<10){
a++;
}
第一和第三行中使用的变量与第二和第三行中使用的变量不同。
一个使用一个(U + 0061),而另一种使用а(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
这将导致一个活锁。由于计数线程接触同一TVar,因此反复使Ackermann计算回滚。
我刚刚开始学习正则表达式,并编写了第一个程序来测试我的字符串是否与正则表达式匹配。
不幸的是,该程序没有产生任何结果。它支撑了终端。请帮助发现问题。我没有使用任何循环,没有涉及递归。我完全困惑。
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!");
}
}
Ideone链接在这里。
这是灾难性回溯的愚蠢示例。复杂度为O(2 n / 2)。尽管该程序可能不会无限期地运行,但它可能会超过周围和周围没有生命的物体。
您只需要两个循环之一,但是您需要哪个取决于您的编译器。
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重置为非终止值。编译器可以在它们是否分配不同我的上方或下方一个堆栈上,所以我已经包括在两个方向上溢出。
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 ++”)。这不是一个狡猾的trick俩,而是更多我过去犯过的实际错误;)有一些需要注意的地方。
以下是使用后台线程在大型输入数组上执行算术运算(求和)的简单类。其中包含一个示例程序。
但是,即使它非常简单,也永远不会终止。请注意,手没有技巧(字符相似,隐藏/缺少分号,三字组;-等)。
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,否则诸如in in之类的循环可能永远不会终止,因为它是由另一个线程修改的。有关详细信息,请参见此StackOverflow问题。该错误取决于.NET的实现,因此它可能会或可能不会影响您。但是通常,在x64处理器上运行发行版似乎会显示问题。(我使用“ csc.exe / o + / debug- infinite.cs”进行了尝试。)