Tại sao nó không kết thúc? [đóng cửa]


95

Nhiệm vụ của bạn: Để viết một chương trình rõ ràng nên chấm dứt, nhưng nó không bao giờ (đến mức xảy ra sự cố máy tính). Làm cho nó trông giống như nó sẽ thực hiện một nhiệm vụ đơn giản: thêm số, in một cái gì đó, ... Nhưng nó chỉ bị cuốn vào một vòng lặp vô hạn.

Cố gắng làm cho chương trình của bạn rất rõ ràng và đơn giản, trong khi nó thực sự sẽ bị kẹt trong một vòng lặp không lường trước được. Cử tri: đánh giá các câu trả lời về mức độ "ngầm" của họ!

Đây là một cuộc thi phổ biến: Hãy sáng tạo!


6
Ai đó có thể vui lòng giải thích những gì tôi có thể làm để làm cho câu hỏi ít rộng hơn? Tôi là người mới ở đây. Cảm ơn bạn!
Số

6
Đây sẽ chỉ là một danh sách lớn các lỗi chính tả và lỗi người mới bắt đầu gây ra các vòng lặp.
Bill Woodger 17/03/2016

Câu hỏi thú vị, nhưng tôi chưa thấy câu trả lời thực sự sáng tạo nào. Tôi hứa sẽ bỏ phiếu cho bất cứ ai không sử dụng các vòng lặp hoặc đệ quy rõ ràng!
Tiếp

14
Tôi không biết nếu điều này được tính, nhưng Microsoft Office của tôi đang hoạt động chính xác như thế này vào lúc này.
Cấp sông St

1
Tôi đang bỏ phiếu để đóng câu hỏi này dưới dạng ngoài chủ đề vì các thử thách ngầm không còn thuộc chủ đề ở đây nữa. meta.codegolf.stackexchange.com/a/8326/20469
mèo

Câu trả lời:


185

Javascript

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

prompt () trả về một chuỗi và vòng lặp nối thêm ký tự '1', nó sẽ không bao giờ bằng 100.


13
Bạn đã cho tôi biết rằng một ví dụ được đánh giá cao hơn (thực tế) tất cả chỉ là lạm dụng cú pháp, nhưng đó là một ví dụ hay!
bwoebi 17/03/2016

4
Chrome trên Kubfox trở nên không phản hồi, treo mọi thứ và tôi phải thiết lập lại một cách khó khăn :)
Sergey Telshevsky

4
@Vlakarados: Python sẽ không thực hiện Javascript chuyển đổi kiểu ẩn. Trên Python, mã tương đương sử dụng raw_inputhoặc Python 3 inputtăng a TypeError.
dùng2357112

2
Không có kiểm tra thực tế là giá trị thực sự dưới 100 nên nó dừng bình thường khi bạn nhập "100": '- (
C.Champagne

1
@Sankalp, +toán tử ở đây là nối chuỗi, không phải là phép cộng.
Michael M.

87

C

Chỉ là một chương trình ví dụ cơ bản minh họa ba loại vòng lặp khác nhau trong 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;
}

Trong khi các vòng lặp không có "làm" trước khi mở ngoặc nhọn. Điều này thực sự tạo ra một vòng lặp do-while bên trong vòng lặp (x <10) được kết thúc bởi vòng lặp "null statement" sau đây. Vì x được tăng bên trong vòng lặp và sau đó giảm dần trong điều kiện của vòng lặp do-while, nên vòng lặp bên trong không bao giờ kết thúc, và vòng lặp bên ngoài cũng không. Vòng lặp "tuyên bố đơn" ở cuối không bao giờ đạt được.

Nếu bạn vẫn còn bối rối, hãy nhìn vào đây (được lưu trữ bên ngoài vì codegolf.SE không thích các khối mã trong spoilers).


8
Haha, tôi đã tìm ra cái này trước khi nhìn vào spoiler giải pháp. : P
Joe Z.

54
Tại sao bạn lại bỏ qua một cơ hội tuyệt vời như vậy để sử dụng toán tử "đi đến"? (x --> 0)
corsiKa

2
Tuyệt vời. Điều này là tuyệt vời xấu xa. Đã cho tôi bốn đọc qua để tìm thấy nó.
Patrick M

1
@JoeZ. Cách quá dễ dàng. Các giải pháp nâng cao nhất là tốt hơn. Cái đó tôi không tìm thấy.
Ẩn danh Pi

3
@Hat Guy, Bash có cú pháp for, do và while; do đó tôi có thể thấy mọi người bị loại bỏ bởi điều này, ngay cả khi họ quen thuộc với các ngôn ngữ không phải 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;
})();

Hoán đổi biến: JavaScript thực sự sẽ lấy định nghĩa thứ hai của tôi về var a = true;, khai báo nó ở đầu hàm như var a;và sửa đổi phép gán của tôi thành a = true;nghĩa asẽ không được xác định tại thời điểm nó đi vào vòng lặp while.


3
Bạn có thể thêm một lời giải thích tốt hơn về lý do tại sao điều này không bao giờ chấm dứt? Vui lòng đi sâu về "cẩu nâng" :)
Số

1
@ Number9 Tôi hy vọng điều đó có ích, google có nhiều ví dụ tốt hơn thế này;)
Newbrict

25
Holy shit điều này thậm chí còn tồi tệ hơn chèn dấu chấm phẩy. +1!
tomsmeding 17/03 '

2
Vấn đề duy nhất tôi thấy với chương trình này là nó không có vẻ như thực hiện một nhiệm vụ đơn giản ... có vẻ như về cơ bản nó không làm gì cả. Có thể thêm một alertsau vòng lặp.
PeterT

2
Bạn nên đổi a = 1sang a = true. Mã vẫn sẽ có vòng lặp vô hạn theo cách đó, nhưng sẽ rõ ràng hơn rằng lý do không phải là một sự giải quyết trong chuyển đổi JavaScript từ ints sang booleans.
Rory O'Kane

49

C #

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

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

Số bằng chữ trong dòng đầu tiên của hàm không phải là '201', mà là '20' với hậu tố 'L' ( kiểu dữ liệu dài ). Số sẽ tràn khá nhanh mà không cần nhấn 6432, nhưng chương trình sẽ tiếp tục trừ khi bật kiểm tra tràn trong các tùy chọn xây dựng.
Rõ ràng, Visual Studio 2013 (và có lẽ các phiên bản khác cũng vậy) đưa ra cảnh báo cho mã này, khuyên bạn nên sử dụng 'L' thay vì 'l'.


12
Oh, lđược cho là trông giống như a 1! Tôi thật ngu ngốc. : \
Joe Z.

6
Gợi ý cải tiến: thay thế số 1 trong phần đầu ra dự kiến ​​bằng ls (dễ dàng phát hiện ra nhân vật kỳ lạ khi bạn có số 1 thực để so sánh)
Allen Gould

3
Vâng, nó có vẻ là khá cụ thể môi trường. Phông chữ của Michael trông rất khác với phông chữ trên máy tính ở nhà của tôi ( imgur.com/PKIuJpr - Chrome, Windows 8) và mẹo này dường như hoạt động tốt hơn trên máy tính làm việc của tôi so với máy tính ở nhà của tôi, mặc dù chúng có khá giống nhau thông số kỹ thuật. Trình duyệt điện thoại của tôi dường như không hiển thị mã theo phông chữ cố định và mẹo này hoàn toàn không hoạt động trên đó.
BenM

1
FTR, đây là những gì nó trông giống như trên máy tính làm việc của tôi ( imgur.com/Opfs3BH - Firefox, Windows 7). Tôi nghĩ rằng người ta thậm chí có thể đánh lừa những người khá sắc sảo.
BenM 17/03 '

15
TẠI SAO NHÂN DÂN GIỮA CÁC TÍNH NĂNG CỦA CÁC ĐẶC ĐIỂM NÀO XEM CÙNG?
Ẩn danh Pi

39

C

Làm thế nào về độ chính xác?

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

Hãy tưởng tượng bạn phải lưu trữ một dãy số nguyên <0; 3> trong bộ nhớ máy tính. Chỉ có 4 số nguyên trong phạm vi này (0,1,2,3). Nó đủ để sử dụng 2 bit để lưu trữ trong bộ nhớ. Bây giờ hãy tưởng tượng bạn phải lưu trữ một loạt các số dấu phẩy động <0; 3>. Vấn đề là có vô số số dấu phẩy động trong phạm vi này. Làm thế nào để lưu trữ số lượng vô hạn? Nó là không thể. Chúng tôi chỉ có thể lưu trữ số lượng hữu hạn của số. Đây là lý do tại sao một số số như 0,1 thực sự khác nhau. Trong trường hợp 0,1, nó là 0.100000000000000006. Rất khuyến khích không sử dụng == hoặc! = Trong các điều kiện xa như bạn sử dụng số dấu phẩy động.


1
Cái này hoạt động ra sao?
Mhmd

5
Lỗi làm tròn số. 0,1 thực sự là 0,00000000000000006 vì 0,1 trong nhị phân giống như 1/3 trong số thập phân - đó là sự mở rộng nhị phân là vô hạn và định kỳ.
orion

3
Không thực sự là một lỗi làm tròn. Giá trị dấu phẩy động là biểu diễn gần đúng của một số. Thực hiện so sánh chính xác giữa các giá trị gần đúng sẽ không hoạt động.
AKHolland

4
Đây là lý do tại sao bạn (gần như) không bao giờ nên so sánh float / double cho bình đẳng.
Emanuel Landeholm

1
Tôi đã chờ đợi để xem cái này Đẹp.
David Conrad

33

HTML / JavaScript

Hãy tưởng tượng bạn có một hộp đầu vào trong trang của mình:

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

Và bây giờ bạn muốn nhập một cái gì đó trong đó ... Hãy thử trong Chrome: http://jsfiddle.net/jZp4X/ .

Hộp thoại trình duyệt tiêu chuẩn được gọi với alertchức năng là phương thức, do đó, khi nó được hiển thị, nó sẽ lấy nét ra khỏi hộp văn bản, nhưng khi nó bị loại bỏ, hộp văn bản sẽ lấy lại tiêu điểm.


5
trong firefox, đầu vào không có tự động lấy nét trên thân tỉnh táo, và từ lần thứ hai nó cung cấp cho tôi để không hiển thị nhiều thông báo và sau đó tôi có thể viết trong hộp văn bản bình thường
Einacio

6
Đẹp một. +1 không có vòng lặp hoặc đệ quy.
Tiếp

5
Không có vòng lặp trong Firefox hoặc Chrome. FF hiển thị cảnh báo một lần khi hộp thoại được nhấp, bạn loại bỏ nó và đó là kết thúc của nó. Có thể nhấp vào nó một lần nữa để lặp lại. Chrome cũng làm như vậy, nhưng để hộp tập trung và thậm chí bạn có thể nhập nó. Xin lỗi, có thể trên các phiên bản cũ hơn, đây là một vấn đề, nhưng không còn nữa.
RomanSt

6
IE11 hoạt động giống hệt như Chrome đối với tôi. Tôi nghĩ rằng bạn đã vô tình tìm thấy một ví dụ về một cái gì đó hoạt động một chiều trên mọi trình duyệt hiện đại trên Mac và một cách khác nhau trên mọi trình duyệt hiện đại trên Windows!
RomanSt

1
Hoạt động bình thường (không có vòng lặp) trên MSIE11
kinokijuf 22/03/2016

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ều kiện i >=0luôn luôn đúng vì size_t không được ký.


2
Đẹp, nhưng trình biên dịch thường đưa ra cảnh báo cho điều này;)
Synxis

2
@Synxis Có trình biên dịch làm. Nhưng chỉ khi bạn bật cảnh báo trình biên dịch. g++sẽ không cảnh báo bạn về điều này mà không có họ.
FDinoff

5
Bạn nên luôn luôn sử dụng -Wall --pedantic.
Martin Uting

3
@queueoverflow Cảnh báo không hiển thị chỉ với những cờ đó. Bạn cần -Wsign-comparecó thể được bật với -Wextra.
FDinoff

7
Một dấu gạch ngang trên -pedantic. #pedantic
David Conrad

29

bash

(Có một yêu cầu không có vòng lặp hoặc đệ quy)

#!/bin/bash

# Demo arrays

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

echo $foo

echo ${foo[0]}

foo[2] = `yes`

echo $foo

echo ${foo[2]}

Thay vì gán chuỗi 'có' cho foo [2], lệnh này gọi lệnh hệ thống yes, sẽ điền vào foo [2] với số lượng "yes \ n" không bao giờ kết thúc.


Cuối cùng bashhết bộ nhớ và gặp sự cố
Digital Trauma

4
Vâng, thực sự nó làm. Nhưng một sự cố đã được cho phép bởi câu hỏi :)
GreenAsJade 17/03/2016

Vâng, chỉ là một quan sát :). Nâng cao.
Chấn thương kỹ thuật số

Trên thực tế, tôi cho rằng các chương trình trong máy tính nhỏ này thực sự làm hỏng máy của bạn hoặc một số từ chối dịch vụ khác sẽ nhận được điểm thưởng)
GreenAsJade 21/03 '

Sửa chữa: yeschỉ là một chương trình coreutils. Không phải là một tòa nhà cao tầng.
mniip

28

C

Chữ "x" đã bị mất trong một tập tin. Một chương trình đã được viết để tìm thấy nó:

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

Nó được biên dịch và chạy và cuối cùng nó hét lên:

Hurray, letter lost in the file is finally found!

Trong nhiều năm, các bức thư đã được giải cứu theo cách này cho đến khi anh chàng mới đến và tối ưu hóa mã. Anh ta đã quen thuộc với các kiểu dữ liệu và biết rằng tốt hơn là sử dụng không dấu hơn là ký cho các giá trị không âm vì nó có phạm vi rộng hơn và bảo vệ chống tràn. Vì vậy, anh thay đổi int thành int unsign . Anh ta cũng biết rõ về ascii để biết rằng chúng luôn có giá trị không âm. Vì vậy, ông cũng thay đổi char thành char không dấu . Anh ta biên soạn mã và về nhà tự hào về công việc tốt mà anh ta đã làm. Chương trình trông như thế này:

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

Anh ta trở lại một sự tàn phá vào ngày hôm sau. Chữ "a" bị thiếu và mặc dù nó được cho là nằm trong "Sah_file" có chứa "abc", chương trình đang tìm kiếm nó mãi mãi chỉ in ra:

Searching file for missing letter a...

Họ đã sa thải anh chàng và quay trở lại phiên bản trước đó nhớ rằng người ta không bao giờ nên tối ưu hóa các kiểu dữ liệu trong mã làm việc.

Nhưng bài học mà họ nên học ở đây là gì?

Trước hết, nếu bạn xem bảng ascii bạn sẽ nhận thấy rằng không có EOF. Đó là bởi vì EOF không phải là một ký tự mà là một giá trị đặc biệt được trả về từ fgetc (), có thể trả về ký tự được mở rộng thành int hoặc -1 biểu thị phần cuối của tệp.
Miễn là chúng ta đang sử dụng char đã ký, mọi thứ đều hoạt động tốt - char bằng 50 được mở rộng bởi fgetc () thành int bằng 50. Sau đó, chúng tôi chuyển đổi nó trở lại thành char và vẫn có 50. Điều tương tự xảy ra với -1 hoặc bất kỳ đầu ra nào khác đến từ fgetc ().
Nhưng hãy nhìn những gì xảy ra khi chúng ta sử dụng char không dấu. Chúng tôi bắt đầu với một char trong fgetc () mở rộng nó thành int và sau đó muốn có một char không dấu. Vấn đề duy nhất là chúng ta không thể bảo toàn -1 trong char không dấu. Chương trình đang lưu trữ nó là 255 mà không còn bằng EOF.

Hãy cẩn thận
Nếu bạn xem phần 3.1.2.5 Các loại trong bản sao tài liệu ANSI C, bạn sẽ thấy rằng char có được ký hay không chỉ phụ thuộc vào việc thực hiện. Vì vậy, anh chàng có lẽ không nên bị sa thải khi anh ta tìm thấy một lỗi rất khó ẩn giấu trong mã. Nó có thể xuất hiện khi thay đổi trình biên dịch hoặc chuyển sang kiến ​​trúc khác. Tôi tự hỏi ai sẽ bị sa thải nếu lỗi xuất hiện trong trường hợp như vậy;)

Tái bút Chương trình được xây dựng xung quanh lỗi được đề cập trong Ngôn ngữ hội PC của Paul A. Carter


7
Tôi thích rằng có một câu chuyện với giải pháp.
jpmc26

Haha! Tôi đoán đó là người duy nhất. Cảm ơn đã đọc qua!
Legat

1
Em yêu anh. Hãy cho tôi biết những câu chuyện của bạn, vui lòng :(
YoYoYonnY

Điều này là hoàn toàn xuất sắc!
kirbyfan64sos

21

Regex

Với đầu vào thích hợp, regex sau đây có thể khiến phần lớn công cụ regex quay lại đi vào địa ngục backtracking:

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

Đầu vào đơn giản như "Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"hoặc "AVerySimpleInputWhichContainsAnInsignificantSentence."(cả hai chuỗi được trích dẫn cho rõ ràng) là đủ để giữ cho hầu hết các công cụ regex quay lui hoạt động trong một thời gian dài.

(\s*\w+)*cho phép mở rộng \w+\w+\w+... \w+, điều đó có nghĩa là công cụ regex về cơ bản sẽ thử tất cả các cách có thể để tách một chuỗi các ký tự từ . Đây là nguồn gốc của địa ngục quay lui.
Nó có thể dễ dàng được cố định bằng cách thay đổi \s*để \s+, sau đó (\s+\w+)*chỉ có thể được mở rộng để \s+\w+\s+\w+... \s+\w+.


3
Tôi ghét quay lại động cơ regex.
David Conrad

2
Tôi đã thử điều này với Perl trước, nhưng có vẻ như Perl có thể nhận thấy một vòng lặp ở đây. Tôi đã không thử AWK, vì không có biểu hiện thông thường nào có thể gây ra hành vi như vậy trong AWK. PHP tự động tạo biểu thức chính quy mất quá nhiều thời gian để khớp với thất bại (điều này thật ngớ ngẩn, nhưng đó là PHP cho bạn - nó tự động chèn các lỗi vào các chương trình). Tuy nhiên, nó thực sự hoạt động trong Python.
Konrad Borowski

1
@xfix: Về lý do tại sao Perl quản lý để tránh quay lại địa ngục, bài viết này giải thích lý do. Tuy nhiên, nó không đủ so với trường hợp như được hiển thị ở đây (cuộn xuống phần hiệu suất). PHP (thực ra là thư viện PCRE) có giới hạn quay lui và một chương trình thích hợp phải luôn kiểm tra giá trị trả về của hàm để quyết định xem việc thực thi có bị dừng hay chạy để hoàn thành.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 22/03/2016

1
Điều này thật NHANH CHÓNG.
alvonellos

20

JavaScript

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

050 là hằng số bát phân trong Javascript và nó có giá trị thập phân là 40.


73
Tôi thấy điều này rõ ràng. :-)
Justin

6
Tôi không biết javascript đã làm điều này. Nhưng sau khi đọc mã tôi đã nói: "050 phải là một cách nào đó để đại diện cho 40, có thể là cơ sở 8 hoặc một cái gì đó"
Cruncher

Điều này cần phải được ẩn tốt hơn.
Paŭlo Ebermann

Đó là điều hiển nhiên ..
Oliver Ni

18

Haskell

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

Vâng, hãy nghĩ về nó! Nó sẽ giống như head $ "Hello" ++ (repeat '!'), tức là chỉ nên quay lại 'H'.

Trong danh sách haskell là các cấu trúc đệ quy, với phần tử đầu tiên là trên cùng. Để thêm vào danh sách, bạn phải hủy đăng ký tất cả các yếu tố đó, đặt phụ lục của bạn và đặt các yếu tố nâng lên trở lại. Điều đó sẽ không làm việc trên một danh sách vô hạn. Tương tự như vậy, đảo ngược một danh sách vô hạn sẽ không mang lại cho bạn sự "Hello"trở lại một cách kỳ diệu . Nó sẽ chỉ treo mãi mãi.


1
Quá tệ, điều này không thực sự hoạt động: - /
John Dvorak

1
Làm thế nào nó không hoạt động?
danmcardle

@craenedgremlin khi tôi thử nghiệm điều này trên Fedora, hệ điều hành cuối cùng đã giết quá trình. (<5 phút) vì nó sử dụng hết bộ nhớ trên hệ thống.
FDinoff

Hấp dẫn! Tôi đã không nhận ra rằng điều này đã xảy ra. Tôi không mạo hiểm vào lãnh thổ của tất cả bộ nhớ thường xuyên.
danmcardle

4
Đó vẫn là một giải pháp hợp lệ: nó không thoát ra, nó chạy miễn là nó có thể cho đến khi hệ thống không thể hỗ trợ nó nữa ...
GreenAsJade

16

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

Chương trình dựa vào luồng đầu ra tiêu chuẩn bị kẹt từ dòng lệnh để bị kẹt. Thư mục WinSXS bên dưới cửa sổ có nhiều nghìn tệp có tên dài nên hầu như được đảm bảo để làm tắc nghẽn thiết bị xuất chuẩn và waitForkhông thể quay lại để chương trình bị bế tắc


1
Có lẽ tôi đang dày đặc, nhưng cuối cùng sẽ không trở lại? Nó chỉ có thể mất một lúc. Có lẽ tôi không hiểu ý bạn là gì khi "guốc [ging] stdout".
asteri 17/03 '

4
nếu luồng không làm trống các khối chương trình, gây cho tôi một số vấn đề đau đầu đó là lý do tại sao tôi sử dụng nó; thư mục dài chỉ đảm bảo bộ đệm chạy đầy đủ
masterX244 17/03/2016

À, gotcha. Đẹp! +1
asteri 17/03/2016

15

Để so sánh táo và cam ... trong C

Tôi ấn tượng rằng không có đoạn mã nào ở đây bằng cách sử dụng goto... (Bạn biết đấy: Goto là ác quỷ! )

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

Giấc ngủ chỉ để có thể đọc nó. Nhấn ^ C nếu bạn không có thời gian vô tận để chờ đợi điều gì đó không bao giờ xảy ra ;-)


9
Đồ khốn lén lút, goto vô tội trong chuyện này :)
orion

là ngẫu nhiên () vodoo được sử dụng?
masterX244 17/03/14

1
à, "2"! = 2; hiểu rồi
masterX244 17/03/2016

2
Chà "2" có thể không bao giờ là 2, nhưng nếu bạn sử dụng số lớn hơn (và bội số của ít nhất 4), điều đó có thể xảy ra;)
orion

1
@orion: Có bạn đúng, nó có thể. Và goto vẫn là ác, nhưng đúc kiểu xấu thậm chí còn ác hơn!
max.haredoom 17/03/2016

12

C, với trình biên dịch tối ưu hóa nhất định

Chương trình này tăng một biến số nguyên cho đến khi nó tràn ra.

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

Ký tràn số nguyên là hành vi không xác định. Thông thường trong thực tế, nó kết thúc tốt đẹp, khi tối ưu hóa được tắt. Với tối ưu hóa trên, trình biên dịch có thể và quyết định x + 1 > xluôn luôn đúng.


Có lẽ sử dụng int32_t; một int 64 bit sẽ thực sự rất dài, thực sự rất dài (585 năm nếu mỗi lần lặp lại mất một nano giây).
Paul Draper

11

C ++

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

Phong cách bình luận kỳ lạ là mẹo. Gợi ý: ba chữ.


Đây là một ví dụ quá cơ bản của một vòng lặp vô hạn.
Ismael Miguel

64
Những Trunk đó được sử dụng quá mức ở đây :(
TimWolla

75
Tôi gần như cảm thấy như những bức thư nên được đặt trong lỗ hổng tiêu chuẩn không còn buồn cười nữa.
undergroundmonorail

6
@TheDoctor: ?? / là một biểu tượng cho một ký tự dấu gạch chéo ngược, do đó dấu gạch chéo ngược chia dòng trong đó x được gán 0 cho đến cuối nhận xét, làm cho nó trở thành một phần của nhận xét.
CasaDeRobison

4
@undergroundmonorail Đăng
Justin

11

Java

Tôi đặc biệt thích tác dụng phụ này của việc tối ưu hóa hộp tự động:

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

Bởi vì autoboxing, Integerđối tượng cư xử gần như đồng bằng ints ở đây, với một ngoại lệ: Các i != maxtrong forvòng so sánh tài liệu tham khảo (identity) của Integercác đối tượng, không giá trị của họ (bình đẳng). Tuy nhiên, đối với các giá trị lên tới 100, "công việc" đáng ngạc nhiên này là do tối ưu hóa trong JVM: Java đưa ra Integercác đối tượng cho "các giá trị phổ biến nhất" và sử dụng lại chúng khi tự động đóng hộp. Vì vậy, đối với các giá trị lên tới 100, chúng ta có danh tính <==> bằng.


5
Cho rằng một số kẻ Java vẫn coi việc quá tải toán tử C ++ là xấu xa ...
Daniel

Bạn không cần khởi tạo = new Integer(0), vì dù sao bạn cũng đang khởi tạo các giá trị. (Điều này có thể làm cho lý do ít rõ ràng hơn.)
Paŭlo Ebermann

@ PaŭloEbermann: Điểm tốt, tôi đã chỉnh sửa mã.
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;
}

Điều này hoạt động chính xác trong C , đếm ngược từ 9 xuống 1 trong STDOUT. Khi chạy trong Ruby, nó không kết thúc, bởi vì

0 không phải là giá trị sai trong Ruby.


Làm ngôn ngữ cùng một lúc ... ấn tượng.
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]]);

Cả hai vòng đều sử dụng cùng một biến vòng lặp, do đó tùy thuộc vào đầu vào, vòng lặp bên trong có thể giữ cho vòng lặp bên ngoài không bao giờ kết thúc.


Ngôn ngữ này là gì?
RononDex 17/03/2016

@ronondex Javascript
thiệu

1
À, vâng, đó là Javascript. Tôi nhớ để bật cú pháp hilighting nhưng cũng phải quên đặt nó trong tiêu đề :)
Aleksi Torhamo 17/03/2016

1
Tôi thấy điều này rõ ràng. :-)
rafaelcastrocouto

@rafaelcastrocouto Vâng, đúng là như vậy, nhưng nó cũng rất dễ bị bỏ lỡ, ví dụ như khi di chuyển một vòng lặp từ chức năng này sang chức năng khác hoặc chỉ lướt qua mã. Ngoài ra, lưu ý rằng điều này thực sự hoạt động chính xác trong một số ngôn ngữ, bao gồm C, do bóng đổ biến. :)
Aleksi Torhamo

7

C

Điều này sẽ in một bảng mã cho tất cả các ký tự ASCII, từ 0 đến 255. A charđủ lớn để lặp lại chúng.

#include <stdio.h>

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

Tất cả các ký tự nhỏ hơn 256. 255 ++ cho 0 do tràn, do đó điều kiện i < 256luôn luôn giữ. Một số trình biên dịch cảnh báo về nó, một số thì không.


Để thực hiện dường như làm một cái gì đó hữu ích hơn, có thể sử dụng một cái gì đó như printf("%3d %2x: %c", i, i, i);(cho một bảng mã) trong vòng lặp của bạn.
Paŭlo Ebermann

@ PaŭloEbermann: Ý tưởng tuyệt vời.
Rafał Cieślak

Tôi sử dụng thủ thuật này trong lớp học của mình, với các ký tự không dấu có thể in được từ 32 đến 128. :)
cpri

7

Con trăn

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

nó nên exit()và không exit. Theo tôi hiểu, exit()là lệnh để thoát trình thông dịch python. Trong trường hợp này, cuộc gọi là biểu diễn của hàm chứ không phải cho hàm xem: exit-thảo luận . Hoặc breaksẽ là một lựa chọn tốt hơn.


Bạn có thể vui lòng giải thích những gì exitthực sự là? Nó có vẻ là một lớp, nhưng nó được sử dụng để làm gì? Bạn cũng có thể thay đổi print mđể print(m)nó cũng hoạt động với Python 3.
Martin Thoma

1
Những loại vật ... Giống như khi tôi elseif đã không làm việc bởi vì nó là elif .
Ẩn danh Pi

Cảm ơn @moosebản in đã cập nhật và thông báo spoiler
Willem

6

C ++

Làm thế nào về C ++ cổ điển - cái bẫy của lập trình viên?

int main()
{
   bool keepGoing = false;

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

   return 0;
}

Tôi không hiểu điều này? Có phải là về việc sử dụng. = thay vì ==?
Mhmd

@ user689 chính xác. keepGoing = truecó nghĩa là để so sánh giá trị của keepGoing, thay vào đó nó gán giá trị cho keepGoing; ngoài ra, toàn bộ câu lệnh keepGoing = trueước tính true(đó là những gì cho phép bạn viết những thứ như thế a=b=c=d=0) dẫn đến một vòng lặp vô hạn.
CompuChip

3
Đây là lý do hơn bao giờ hết để sử dụng điều kiện yoda.
Ryan

@RyanEdwardDougherty Haha như thế tôi chưa bao giờ nghe thấy họ được gọi. Cho buổi sáng cười cảm ơn.
CompuChip

@RyanEdwardDougherty: Tất nhiên == true(hoặc kiểu Yoda true ==) dù sao cũng không cần thiết, và điều kiện chỉ cần đọc while (keepGoing).
celtschk

6

Javascript

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

Các biến được sử dụng trong dòng thứ 1 và thứ 3 khác với các biến được sử dụng trong dòng thứ 2 và thứ 3.
Một cái sử dụng một (U + 0061) trong khi cái còn lại sử dụng а (U + 0430)


Tôi không thấy một vấn đề ở đây. Tôi chạy nó và nó hoạt động tốt. Tôi đang thiếu gì?
Andrew Shepherd

điều này rất có thể sẽ hoạt động ở mọi nơi vì unicode có thể sẽ được chuyển đổi. Có +1 vì nó là vô hình nhất mà bạn có thể nhận được!
rafaelcastrocouto

Chỉ cần ẩn hoàn toàn (thay thế bằng U + 0430) Nếu đây là mã của bạn, chúc may mắn tìm ra vấn đề: var a;var points = 0;function fiftyfifty() {points++;if (Math.random() > 0.5)return true;}; á = fiftyfifty(); while (a === undefined) {á = fiftyfifty();} console.log("Points: " + points);Tôi sẽ từ bỏ, xóa nó mãi mãi, làm sạch máy tính của tôi, có thể là quét virus chỉ để chắc chắn và viết lại hoàn toàn. EDIT: Bởi vì var a = 0; a = 1;không thực tế lắm
YoYoYonnY

6

Java:

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

"I = i ++" là một lỗi người mới bắt đầu khá phổ biến và có thể rất khó tìm


5

C ++

Một chút ngẫu nhiên?

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

Không gọi hàm randmà thay vào đó gọi Randomizer::randhàm đệ quy .


5
Dấu ngoặc đơn trong câu lệnh return, yuck.
David Conrad

1
Điều này cuối cùng sẽ segfault, mặc dù.
kirbyfan64sos

5

Haskell

Một số mã theo thời gian tính toán một giá trị nhất định của hàm Ackermann. Đối với các giá trị rất thấp, nó thường chấm dứt. Trên máy của tôi các giá trị rất thấp có nghĩa là một cái gì đó như 3 5 hoặc nhỏ hơn với mã được biên dịch và -O. Trong ghci giá trị thấp có nghĩa là một cái gì đó như 3 3.

Các 'biểu tượng dường như mớ hỗn độn lên làm nổi bật cú pháp, không chắc chắn lý do tại sao. Ở một số nơi chúng là cần thiết vì vậy không thể loại bỏ tất cả chúng.

Chỉnh sửa- thay đổi ngôn ngữ.

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

Điều này gây ra một con sống. Chuỗi đếm liên tục khiến tính toán Ackermann quay trở lại kể từ khi chúng chạm vào cùng một TVar.


đánh dấu nó là lang-hs thay vì lang-haskell dường như hoạt động tốt hơn (đó là một trong những tiện ích mở rộng trong trình mở rộng google )
Einacio

5

Java - Không có vòng lặp hoặc đệ quy

Tôi mới bắt đầu học các biểu thức chính quy và viết chương trình đầu tiên của mình để kiểm tra xem chuỗi của tôi có khớp với biểu thức chính quy không.

Thật không may, chương trình không tạo ra bất kỳ kết quả. Nó giữ thiết bị đầu cuối. Xin hãy giúp đỡ trong việc tìm ra vấn đề. Tôi đã không sử dụng các vòng lặp, không có đệ quy liên quan. Tôi hoàn toàn bối rối.

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

Tôi đã làm gì sai? Tại sao chương trình của tôi không kết thúc? Xin vui lòng giúp đỡ!

Liên kết Ideone ở đây .

Đây là một ví dụ ngu ngốc về việc quay lui thảm khốc . Độ phức tạp là O (2 n / 2 ). Trong khi chương trình có thể không chạy vô thời hạn, có lẽ nó muốn sống lâu hơn cả cuộc sống và không sống vật xung quanh và không quá xung quanh .


5

C

Bạn chỉ cần một trong hai vòng lặp, nhưng cái nào bạn cần phụ thuộc vào trình biên dịch của bạn.

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

}

Giới hạn đơn giản vượt quá giới hạn đặt lại i thành giá trị không kết thúc. Trình biên dịch có thể khác nhau về việc họ phân bổ i ở trên hay dưới một ngăn xếp, vì vậy tôi đã bao gồm các lỗi tràn theo cả hai hướng.


5

C / C ++

C ++ chỉ cho phép khai báo biến nội tuyến dễ dàng được sử dụng ở đây, nhưng nó cũng dễ gây ra lỗi này trong 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;
}

Trong vòng lặp bên trong, 'j' được so sánh nhưng không bao giờ tăng. ('I ++' thực sự phải là 'j ++'). Đây không phải là một mánh khóe lén lút mà là một lỗi thực tế tôi đã mắc phải trong quá khứ;) Một cái gì đó để đề phòng.


2
Điều này thường khiến tôi mất ít nhất 5 phút để gỡ lỗi. Tôi ghét nó khi tôi làm điều này.
ace_HongKongInependence 22/03 '

4

C #

Sau đây là một lớp đơn giản thực hiện một phép toán số học (tính tổng) trên một mảng đầu vào lớn bằng cách sử dụng một luồng nền. Một chương trình mẫu được bao gồm.

Tuy nhiên, mặc dù nó khá đơn giản, nó không bao giờ chấm dứt. Lưu ý rằng không có độ bóng của bàn tay (ngoại hình nhân vật, dấu chấm phẩy ẩn / thiếu, dấu ba chấm ;-), v.v.)

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

Đây là một ví dụ về một lỗi khó chịu trong thế giới thực cũng có thể xuất hiện trong mã của bạn. Theo mô hình bộ nhớ .NET và đặc tả C #, một vòng lặp như vòng lặp WaitAndGetResultcó thể không bao giờ kết thúc trừ khi bạn chỉ định biến là biến động, bởi vì nó được sửa đổi bởi một luồng khác. Xem câu hỏi StackOverflow này để biết chi tiết. Lỗi này phụ thuộc vào việc triển khai .NET, vì vậy nó có thể hoặc không ảnh hưởng đến bạn. Nhưng thông thường, việc chạy bản phát hành trên bộ xử lý x64 dường như hiển thị vấn đề. (Tôi đã thử nó với Csc.exe / o + / debug- infinite.cs .).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.