Pourquoi ça ne se termine pas? [fermé]

95

Votre tâche: écrire un programme qui doit évidemment se terminer, mais ce n’est jamais le cas (même dans le cas d’une panne d’ordinateur). Faites en sorte qu'il semble devoir effectuer une tâche simple: ajouter des chiffres, imprimer quelque chose, ... Mais cela reste pris dans une boucle infinie.

Essayez de rendre votre programme très clair et simple, tout en restant bloqué dans une boucle imprévue. Les électeurs: jugez les réponses à quel point elles sont "sournoises"!

Concours de popularité: soyez créatif!

Nombre9
la source
6
Quelqu'un pourrait-il expliquer ce que je peux faire pour rendre la question moins large? Je suis nouveau ici. Je vous remercie!
Numéro
6
Cela va juste être une grande liste de fautes de frappe et les erreurs du débutant qui causent des boucles.
Bill Woodger
Question intéressante, mais je n'ai pas encore vu de réponses vraiment créatives. Je promets des votes à quiconque n'utilisant pas de boucles ou de récursions évidentes!
ApproachingDarknessFish
14
Je ne sais pas si cela compte, mais mon système Microsoft Office se comporte exactement comme cela pour le moment.
Level River St
1
Je vote pour clore cette question hors sujet parce que les défis sournois ne sont plus au sujet ici. meta.codegolf.stackexchange.com/a/8326/20469
cat.

Réponses:

185

Javascript

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

prompt () renvoie une chaîne et la boucle ajoute le caractère '1', il ne sera jamais égal à 100.

Michael M.
la source
13
Vous m'avez eu avec celui-là… les exemples (en réalité) les plus votés ne font qu'abuser de la syntaxe… mais celui-là est sympa!
bwoebi
4
Chrome sur Kubuntu est devenu insensible, accrochez tout et je devais réinitialiser mon disque :)
Sergey Telshevsky
4
@Vlakarados: Python ne fera pas la conversion de type implicite que Javascript fait. Sur Python, le code équivalent utilisant raw_inputou Python 3 inputdéclenche a TypeError.
user2357112
2
Il n'y a pas de contrôle sur le fait que la valeur est en réalité inférieure à 100, donc elle s'arrête normalement lorsque vous entrez "100": '- (
C.Champagne
1
@Sankalp, l' +opérateur est ici la concaténation de chaîne, pas l'addition.
Michael M.
87

C

Juste un exemple de programme de base illustrant les trois types différents de boucles while en 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;
}

Les boucles While n'ont pas de "faire" avant l'ouverture de l'accolade. Cela crée en fait une boucle do-while à l'intérieur de la boucle (x <10) qui se termine par la "déclaration null" suivante. Puisque x est incrémenté à l'intérieur de la boucle, puis décrémenté dans la condition de la boucle do-while, la boucle interne ne se termine jamais, pas plus que la boucle externe. La boucle "instruction unique" à la fin n'est jamais atteinte.

Si vous êtes toujours confus, regardez ici (hébergé en externe car codegolf.SE n'aime pas les blocs de code dans les spoilers).

Fraxtil
la source
8
Haha, j'ai compris celui-ci avant de regarder le spoiler de solution. : P
Joe Z.
54
Pourquoi avez-vous laissé passer une si excellente occasion d'utiliser l'opérateur "Va à"? (x --> 0)
CorsiKa
2
Oh wow. C'est merveilleusement mauvais. Il m'a fallu quatre lectures pour le trouver.
Patrick M
1
@ JoeZ. Bien trop facile. La solution la plus votée était meilleure. Celui que je n'ai pas trouvé.
Anonyme Pi
3
@ Hat Guy, Bash a la syntaxe suivante: «fais et tout le temps» pour que je puisse voir les gens être choqués, même s'ils sont familiers avec les langages non 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;
})();

Levage variable: JavaScript saisira ma deuxième définition de var a = true;, le déclarera en haut de la fonction var a;et modifiera mon affectation afin que sa a = true;signification asoit indéfinie au moment où il entre dans la boucle while.

Newbrict
la source
3
Pourriez-vous ajouter une meilleure explication de la raison pour laquelle cela ne se termine jamais? S'il vous plaît aller en profondeur sur "levage variable" :)
Numéro
1
@ Number9 J'espère que ça aide, Google a de bien meilleurs exemples que cela;)
New York
25
Putain de merde, c'est encore pire que l'insertion d'un point-virgule. +1!
Tomsmeding
2
Le seul problème que je vois avec ce programme est qu’il n’a pas l’impression d’accomplir une tâche simple… mais qu’il ne devrait en principe rien faire. Peut-être ajouter un alertaprès la boucle.
PeterT
2
Vous devriez changer a = 1à a = true. Le code aura toujours la boucle infinie de cette façon, mais il sera plus clair que la raison n’est pas due à une certaine bizarrerie dans la conversion JavaScript d’ints en booléens.
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");
    }
}

Le nombre littéral dans la première ligne de la fonction n'est pas un '201', mais un '20' avec un suffixe 'L' minuscule ( long datatype). Le nombre débordera assez rapidement sans jamais atteindre 6432, mais le programme continuera à moins que la vérification du débordement ne soit activée dans les options de construction.
Sensiblement, Visual Studio 2013 (et probablement d’autres versions également) vous avertissent de ce code, vous recommandant d’utiliser "L" au lieu de "l".

BenM
la source
12
Oh, le lest censé ressembler à un 1! Je suis stupide. : \
Joe Z.
6
Suggestion d'amélioration: remplacez également les 1 dans la section de sortie attendue par ls (il est plus facile de repérer le caractère étrange lorsque vous avez de vrais 1 à comparer)
Allen Gould
3
Oui, cela semble être assez spécifique à l'environnement. La police de @ Michael a une apparence très différente de celle de mon ordinateur personnel ( imgur.com/PKIuJpr - Chrome, Windows 8), et l’astuce semble fonctionner mieux sur mon ordinateur de travail que sur mon ordinateur personnel, même s’ils sont assez similaires. Spécifications. Le navigateur de mon téléphone ne semble pas afficher le code dans une police à tonalité fixe, et l'astuce ne fonctionne pas du tout.
BenM
1
FTR, voici à quoi cela ressemble sur mon ordinateur de travail ( imgur.com/Opfs3BH - Firefox, Windows 7). Je pense qu'on pourrait même duper des gens très astucieux.
BenM
15
POURQUOI LES PERSONNES GARDENT-ELLES L'ABUS DE PERSONNAGES QUI REGARDENT LES MÊMES?
Anonyme Pi
39

C

Qu'en est-il de la précision?

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

Imaginez que vous deviez stocker une plage de nombres entiers <0; 3> dans la mémoire de l'ordinateur. Il n'y a que 4 nombres entiers dans cette plage (0,1,2,3). Il suffit d'utiliser 2 bits pour stocker cela en mémoire. Maintenant, imaginez que vous deviez stocker une plage de nombres à virgule flottante <0; 3>. Le problème est qu’il existe un nombre infini de nombres en virgule flottante dans cette plage. Comment stocker un nombre infini de nombres? C'est impossible. Nous ne pouvons stocker qu'un nombre fini de nombres. C'est pourquoi certains nombres comme 0,1 sont en réalité différents. Dans le cas de 0.1, il est 0.100000000000000006. Il est fortement recommandé de ne pas utiliser == ou! = Dans les conditions où vous utilisez des nombres à virgule flottante.

Scony
la source
1
Comment cela marche-t-il?
Mhmd
5
Erreurs d'arrondi. 0.1 correspond en réalité à 0.100000000000000006 car 0.1 en binaire équivaut à 1/3 en décimal - son expansion binaire est infinie et périodique.
orion
3
Pas vraiment une erreur d'arrondi. Les valeurs en virgule flottante sont des représentations approximatives d'un nombre. Effectuer des comparaisons exactes entre les valeurs approximatives ne va pas au travail.
AKHolland
4
C'est pourquoi vous ne devriez (presque) jamais comparer les float / doubles pour l'égalité.
Emanuel Landeholm
1
J'attendais de voir celui-ci. Agréable.
David Conrad
33

HTML / JavaScript

Imaginez que vous avez une zone de saisie dans votre page:

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

Et maintenant, vous voulez taper quelque chose dedans ... Essayez dans Chrome: http://jsfiddle.net/jZp4X/ .

La boîte de dialogue standard du navigateur appelée avec la alertfonction est modale. Ainsi, lorsqu'elle est affichée, le focus est retiré de la zone de texte, mais lorsqu'il est ignoré, la zone de texte reçoit le focus.

Vision
la source
5
dans firefox, l'entrée n'a pas d'autofocus en fermeture d'alerte, et dès la deuxième fois, elle me propose de ne plus afficher d'alertes et de pouvoir écrire dans la zone de texte normalement
Einacio
6
Joli. +1 pour pas de boucles ou de récursivité.
ApproachingDarknessFish
5
Pas de boucles dans Firefox ou Chrome. FF affiche l'alerte une fois lorsque la boîte de dialogue est cliquée, vous la fermez et c'est tout. Peut cliquer à nouveau pour répéter. Chrome fait la même chose, mais laisse la zone centrée et vous pouvez même la saisir. Désolé, peut-être que sur les anciennes versions, c'était un problème, mais plus maintenant.
RomanSt
6
IE11 fonctionne exactement comme Chrome pour moi. Je pense que vous avez trouvé par inadvertance un exemple de quelque chose qui fonctionne d'une manière sur tous les navigateurs modernes sur Mac, et d'une manière différente sur chaque navigateur moderne sur Windows!
RomanSt
1
Fonctionne normalement (pas de boucles) sur 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;
}

La condition i >=0est toujours vraie car size_t n'est pas signé.

FDinoff
la source
2
Bien
2
Les compilateurs @ Synxis Yes font. Mais seulement si vous activez les avertissements du compilateur. g++ne vous préviendrai pas sans eux.
FDinoff
5
Vous devriez toujours utiliser -Wall --pedanticquand même.
Martin Ueding
3
@queueoverflow L'avertissement ne s'affiche pas uniquement avec ces indicateurs. Vous avez besoin de -Wsign-comparece qui peut être activé avec -Wextra.
FDinoff
7
Un tiret sur-pédantique. #pedantic
David Conrad
29

frapper

(Il y avait une demande pour pas de boucles ou de récursivité)

#!/bin/bash

# Demo arrays

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

echo $foo

echo ${foo[0]}

foo[2] = `yes`

echo $foo

echo ${foo[2]}

Au lieu d'attribuer la chaîne 'oui' à foo [2], cela appelle la commande système yes, qui remplit foo [2] avec une quantité infinie de "oui \ n".

GreenAsJade
la source
A court bashde mémoire, elle tombe en panne
Digital Trauma
4
Oui, c'est le cas. Mais la question permettait en quelque sorte l'accident :)
GreenAsJade
Oui, juste une observation :). Upvote.
Trauma numérique
En fait, j'estime que les programmes de cette petite maquette qui plantent réellement votre machine, ou un autre déni de service, devraient recevoir des points supplémentaires)
GreenAsJade
Correction: ce yesn’est qu’un programme coreutils. Pas un appel systémique.
Mniip
28

C

La lettre "x" a été perdue dans un fichier. Un programme a été écrit pour le trouver:

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

Il a été compilé et à courir et il a finalement crié:

Hurray, letter lost in the file is finally found!

Pendant de nombreuses années, les lettres ont été sauvées de cette façon jusqu'à ce que le nouveau type optimise le code. Il connaissait bien les types de données et savait qu'il valait mieux utiliser des signatures non signées que signées pour les valeurs non négatives, car cette plage est plus étendue et offre une certaine protection contre les débordements. Alors il a changé int en unsigned int . Il connaissait également suffisamment l'ascii pour savoir qu'ils avaient toujours une valeur non négative. Donc, il a également changé de caractère en caractère non signé . Il compila le code et rentra chez lui fier du bon travail qu'il accomplissait. Le programme ressemblait à ceci:

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

Il est revenu à un désastre le lendemain. La lettre "a" était manquante et même si elle était supposée se trouver dans le "fichier_du_ désert" contenant "abc", le programme le cherchait pour toujours en imprimant:

Searching file for missing letter a...

Ils ont renvoyé le gars et sont revenus à la version précédente en se rappelant qu'il ne fallait jamais optimiser les types de données dans du code de travail.

Mais quelle est la leçon qu'ils auraient dû apprendre ici?

Tout d’abord, si vous regardez la table ascii, vous remarquerez qu’il n’ya pas de fichier EOF. En effet, EOF n'est pas un caractère mais une valeur spéciale renvoyée par fgetc (), qui peut renvoyer un caractère étendu en int ou -1 indiquant la fin du fichier.
Tant que nous utilisons un caractère signé, tout fonctionne correctement - un caractère égal à 50 est étendu par fgetc () dans un entier égal à 50 également. Ensuite, nous le transformons en caractère et avons toujours 50. Même chose pour -1 ou toute autre sortie provenant de fgetc ().
Mais regardez ce qui se passe lorsque nous utilisons des caractères non signés. Nous commençons par un caractère dans fgetc (), étendons-le à int puis souhaitons avoir un caractère non signé. Le seul problème est que nous ne pouvons pas conserver -1 dans un caractère non signé. Le programme la stocke sous la forme 255, qui n'est plus égale à EOF.

Caveat
Si vous consultez la section 3.1.2.5 Types de copie de la documentation ANSI C, vous verrez que le caractère signé ou non dépend de la mise en œuvre. Donc, le gars ne devrait probablement pas être licencié, car il a trouvé un bogue très délicat caché dans le code. Cela pourrait apparaître lors du changement de compilateur ou lors du passage à une architecture différente. Je me demande qui serait viré si le bogue venait à apparaître dans un tel cas;)

PS Le programme a été construit autour du bogue mentionné dans PC Assembly Language par Paul A. Carter

Legat
la source
7
J'aime le fait qu'il y ait une histoire avec la solution.
Jpmc26
Haha! Je suppose que c'est le seul. Merci d'avoir lu!
Legat
1
Je t'aime. Nourrissez-moi de vos histoires pls :(
YoYoYonnY
C'est absolument génial!
kirbyfan64sos
21

Regex

Avec les entrées appropriées, les expressions rationnelles suivantes peuvent entraîner l'encrassement de la plupart des moteurs de expressions rationnelles:

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

Une simple entrée telle que "Programming Puzzles and Code Golf Stack Exchange - Mozilla Firefox"ou "AVerySimpleInputWhichContainsAnInsignificantSentence."(les deux chaînes sont citées pour plus de clarté) suffit pour que la plupart des moteurs de regex en marche arrière puissent fonctionner pendant longtemps.

Étant donné que (\s*\w+)*permet l'expansion \w+\w+\w+... \w+, ce qui signifie que le moteur des expressions rationnelles va fondamentalement essayer toutes les manières possibles de scinder une chaîne de caractères . C'est la source de l'enfer de retour en arrière.
Il peut facilement être résolu en changeant \s*à \s+, alors (\s+\w+)*ne peut être étendu à \s+\w+\s+\w+... \s+\w+.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
la source
3
Je déteste revenir sur les moteurs de regex.
David Conrad
2
J'ai d'abord essayé avec Perl, mais il semble que Perl puisse remarquer une boucle ici. Je n'ai pas essayé AWK, car aucune expression régulière ne peut provoquer un tel comportement dans AWK. PHP crée automatiquement une expression régulière qui prend trop de temps à faire échouer (ce qui est idiot, mais c'est PHP pour vous - il insère automatiquement des bogues dans les programmes). Cependant, cela fonctionne réellement en Python.
Konrad Borowski
1
@xfix: Pourquoi Perl a-t-il réussi à éviter de revenir en arrière? Cet article explique la raison. Cependant, cela ne suffit pas, comme illustré ci-dessous (faites défiler jusqu'à la section performances). PHP (en réalité, la bibliothèque PCRE) a une limite de retour en arrière et un programme approprié doit toujours vérifier la valeur de retour de la fonction pour décider si l'exécution a été interrompue ou si elle a été complétée.
nh̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
C'est tellement SLICK.
Alvonellos
20

JavaScript

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

050 est une constante octale en Javascript et sa valeur décimale est 40.

Wuiyang
la source
73
Je trouve cela évident. :-)
Justin
6
Je ne savais pas que javascript faisait ça. Mais après avoir lu le code, j'ai dit: "050 doit être un moyen de représenter 40, probablement en base 8 ou quelque chose comme ça"
Cruncher
Cela doit être mieux caché.
Paŭlo Ebermann
C'est évident ..
Oliver Ni
18

Haskell

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

Eh bien, pense à ça! Ce serait la même chose head $ "Hello" ++ (repeat '!'), c.-à-d. Devrait tout simplement revenir 'H'.

Dans haskell, les listes sont des structures récursives, le premier élément étant le plus important. Pour ajouter une liste à une liste, vous devez dérouler tous ces éléments, placer votre annexe et remettre les éléments soulevés. Cela ne fonctionnerait pas sur une liste infinie. De même, inverser une liste infinie ne vous rendra pas comme par magie "Hello". Il va juste pendre pour toujours.

mniip
la source
1
Dommage que cela ne fonctionne pas réellement: - /
John Dvorak
1
Comment ça marche pas?
danmcardle
@ crazedgremlin, lorsque j'ai testé cela sur Fedora, le système d'exploitation a finalement mis fin au processus. (<5 minutes) car il a utilisé toute la mémoire du système.
FDinoff
Intéressant! Je n'avais pas réalisé que c'était arrivé. Je ne m'aventure pas souvent dans un territoire engloutissant de mémoire.
danmcardle
4
C'est toujours une solution valable: il ne sort pas, il fonctionne aussi longtemps qu'il le peut jusqu'à ce que le système ne le supporte plus ...
GreenAsJade
16

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

Le programme s'appuie sur un flux de sortie standard coincé de la ligne de commande pour rester bloqué. Le répertoire WinSXS sous Windows contient plusieurs milliers de fichiers avec des noms longs, de sorte qu'il est presque garanti que le colmatage stdout et waitForque le programme ne peut pas être retourné afin que le programme soit bloqué.

masterX244
la source
1
Peut-être que je suis dense, mais ce retour ne sera-t-il pas finalement? Cela pourrait prendre un moment. Peut-être que je ne comprends pas ce que vous entendez par "boucher [ging] stdout".
asteri
4
si le flux n’est pas vidé, les blocs du programme me causent déjà des maux de tête et c’est pourquoi je l’utilise; le répertoire long garantit uniquement que la mémoire tampon est saturée
masterX244
Ah, euh. Agréable! +1
asteri
15

Comparer des pommes et des oranges ... en C

Je suis impressionné par le fait qu'il n'y a pas de code ici qui utilise un goto... (Vous savez: Goto is evil! )

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

Le sommeil est juste pour pouvoir le lire. Appuyez sur ^ C si vous ne disposez pas de beaucoup de temps pour attendre quelque chose qui ne se produit jamais ;-)

max.haredoom
la source
9
Salaud bâtard, vas-y, c'est innocent :)
orion
est le random () le vodoo utilisé?
masterX244
1
ahh, "2"! = 2;
Je l'
2
Eh bien, "2" ne peut probablement pas être égal à 2, mais si vous utilisiez un nombre plus important (et un multiple d'au moins 4), cela pourrait arriver;)
orion
1
@orion: Oui, vous avez raison, cela pourrait être. Et goto est toujours pervers, mais les mauvais castings sont encore plus pervers!
max.haredoom
12

C, avec certains compilateurs optimiseurs

Ce programme incrémente une variable entière jusqu'à ce qu'elle déborde.

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

Le dépassement d'entier signé est un comportement indéfini. Habituellement, dans la pratique, cela se termine lorsque les optimisations sont désactivées. Lorsque les optimisations sont activées, les compilateurs peuvent et doivent décider que cela x + 1 > xest toujours vrai.

utilisateur253751
la source
Peut-être utiliser int32_t; un int de 64 bits prendrait vraiment, vraiment, vraiment très long (585 ans si chaque itération prend une nanoseconde).
Paul Draper
11

C ++

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

Le style de commentaire étrange est le truc. Indice: trigraphes.

Poignée de porte
la source
C'est un exemple trop basique d'une boucle infinie.
Ismael Miguel
64
Ces trigraphes sont tellement surutilisés ici :(
TimWolla
75
J'ai presque l'impression que les trigrammes doivent être placés dans des meurtrières standard qui ne sont plus drôles.
undergroundmonorail
6
@TheDoctor: ?? / est un trigraphe pour un caractère de barre oblique inversée, de sorte que la barre oblique inverse épisse la ligne où x est affecté de 0 à la fin du commentaire, ce qui en fait une partie du commentaire.
CasaDeRobison
4
@undergroundmonorail Publié
Justin
11

Java

J'aime particulièrement cet effet secondaire de l'optimisation automatique:

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

En raison de la sélection automatique, les Integerobjets se comportent presque comme des mots simples int, à une exception près: i != maxla forboucle dans la boucle compare les références (identité) des Integerobjets et non leur valeur (égalité). Pour des valeurs allant jusqu'à 100, ceci "fonctionne" de manière surprenante, du fait d'une optimisation dans la machine virtuelle Java: Java préaffecte des Integerobjets pour les "valeurs les plus courantes" et les réutilise lors de la sélection automatique. Donc, pour des valeurs allant jusqu'à 100, nous avons l'identité <==>.

Daniel
la source
5
Étant donné que certains développeurs Java considèrent toujours la surcharge d'opérateurs C ++ comme un mal ...
Daniel
Vous n'avez pas besoin de l'initialisation = new Integer(0), car vous initialisez les valeurs par la suite. (Cela pourrait rendre la raison moins évidente.)
Paŭlo Ebermann
@ PaŭloEbermann: Bon point, j'ai édité le code.
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;
}

Cela fonctionne correctement en C , le décompte de 9 à 1 dans STDOUT. Lorsqu'il est exécuté en Ruby, il ne se termine pas, car

0 n'est pas une valeur fausse en Ruby.

histocrate
la source
Faites les langues à la fois ... impressionnant.
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]]);

Les deux boucles utilisent la même variable de boucle. Ainsi, en fonction de l'entrée, la boucle interne peut empêcher la boucle externe de se terminer.

Aleksi Torhamo
la source
Quelle langue est-ce?
RononDex
@ronondex Javascript
tomsmeding
1
Ah oui, c'est Javascript. Je me suis souvenu d'activer la syntaxe, mais j'ai dû oublier de la mettre aussi dans le titre :)
Aleksi Torhamo
1
Je trouve cela évident. :-)
rafaelcastrocouto
@rafaelcastrocouto Oui, c'est vrai, mais c'est aussi très facile à rater, par exemple lorsque vous déplacez une boucle d'une fonction à une autre ou que vous parcourez le code. En outre, notez que cela fonctionne réellement dans certaines langues, y compris C, en raison de l'observation variable. :)
Aleksi Torhamo
7

C

Cela devrait imprimer une table de codes pour tous les caractères ASCII, de 0 à 255. La valeur de A charest suffisante pour les parcourir.

#include <stdio.h>

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

Tous les caractères sont inférieurs à 256. 255 ++ donne 0 en raison d'un débordement. La condition est donc i < 256toujours remplie . Certains compilateurs en avertissent, d'autres non.

Rafał Cieślak
la source
Faire semblant de faire quelque chose de plus utile, peut-être utiliser quelque chose comme printf("%3d %2x: %c", i, i, i);(pour une table de code) dans votre boucle.
Paŭlo Ebermann
@ PaŭloEbermann: Excellente idée.
Rafał Cieślak
J'utilise cette astuce dans ma classe, avec des caractères imprimables non signés compris entre 32 et 128. :)
cpri
7

Python

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

cela devrait être exit()et non exit. Si je comprends bien, exit()est la commande pour quitter l’interpréteur python. Dans ce cas, l'appel est à la représentation de la fonction et non à la fonction, voir: discussion de sortie . Sinon, ce breakserait un meilleur choix.

Willem
la source
Pourriez-vous s'il vous plaît expliquer ce exitqui est réellement? Cela semble être un cours, mais à quoi sert-il? Vous pouvez aussi changer print mpour print(m)que cela fonctionne aussi avec Python 3.
Martin Thoma
1
Ce genre de choses ... Comme quand mon elseif ne fonctionnait pas parce que c'était elif .
Anonyme Pi
Merci @moosedéclaration mise à jour et le message spoiler
Willem
6

C ++

Qu'en est-il du piège classique du programmeur C ++?

int main()
{
   bool keepGoing = false;

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

   return 0;
}
CompuChip
la source
Je ne comprends pas ça? Est-il question d'utiliser. = au lieu de ==?
Mhmd
@ user689 exactement. keepGoing = trueétait destiné à comparer la valeur de keepGoing, au lieu de cela il attribue la valeur à keepGoing; de plus, l'instruction entière est keepGoing = trueévaluée true(ce qui vous permet d'écrire des choses comme a=b=c=d=0) menant à une boucle infinie.
CompuChip
3
C'est de plus en plus une raison d'utiliser les conditions yoda.
Ryan
@RyanEdwardDougherty Haha comme ça, je ne les ai jamais entendus s'appeler. Pour le matin rire merci.
CompuChip
@RyanEdwardDougherty: Bien sûr == true(ou à la manière de Yoda true ==) est quand même redondant, et la condition devrait simplement se lire while (keepGoing).
celtschk
6

Javascript

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

Les variables utilisées en 1ère et 3ème ligne sont différentes de celles utilisées en 2ème et 3ème ligne.
L' un utilise un (U + 0061) tandis que l'autre utilise un (U + 0430)

Clyde Lobo
la source
Je ne vois pas de problème ici. Je l'ai couru et cela a bien fonctionné. Qu'est-ce que je rate?
Andrew Shepherd
cela fonctionnera probablement partout car l’unicode sera probablement converti. Vous avez un +1 car c'est le plus invisible possible!
Rafaelcastrocouto
Juste pour le cacher complètement (remplacez par U + 0430) Si c’était votre code, bonne chance pour trouver le problème: var a;var points = 0;function fiftyfifty() {points++;if (Math.random() > 0.5)return true;}; á = fiftyfifty(); while (a === undefined) {á = fiftyfifty();} console.log("Points: " + points);j’abandonnerais, effacerais cela pour toujours, nettoyerais mon ordinateur, peut-être un scanner de virus juste pour être sûr et réécrirais complètement. EDIT: Parce que ce var a = 0; a = 1;n'est pas très réaliste
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!");
   }
}

Le "i = i ++" est une erreur assez courante pour les débutants et peut être étonnamment difficile à trouver

Richo
la source
5

C ++

Un peu de hasard?

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

N'appelle pas la fonction randmais appelle récursivement la Randomizer::randfonction.

calimbak
la source
5
Des parenthèses supplémentaires dans l'instruction de retour, beurk.
David Conrad
1
Cela finira par segfault, cependant.
kirbyfan64sos
5

Haskell

Certains codes permettent de chronométrer le calcul d’une valeur donnée de la fonction Ackermann. Pour des valeurs très faibles, il se termine généralement. Sur ma machine, des valeurs très basses signifient quelque chose comme 35 ou moins avec un code compilé et -O. En ghci, les valeurs basses signifient quelque chose comme 3 3.

Le 'symbole semble gâcher la mise en évidence de la syntaxe, sans savoir pourquoi. Dans certains endroits, ils sont nécessaires, ils ne peuvent donc pas tous être supprimés.

Modifier la langue modifiée.

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

Cela provoque un livelock. Le fil de comptage provoque à plusieurs reprises le calcul Ackermann à revenir car ils touchent le même TVar.

monocell
la source
en le marquant comme lang-hs au lieu de lang-haskell semble mieux fonctionner (c'est une des extensions du prétellificateur Google )
Einacio
5

Java - Pas de boucles ni de récursivité

Je viens juste de commencer à apprendre les expressions régulières et j'ai écrit mon premier programme pour vérifier si ma chaîne correspond à une expression régulière.

Malheureusement, le programme ne produit aucun résultat. Il supporte le terminal. S'il vous plaît aider à trouver le problème. Je n'ai pas utilisé de boucles, il n'y a pas de récursivité. Je suis complètement dérouté.

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

Qu'est ce que j'ai mal fait? Pourquoi mon programme ne se termine-t-il pas? S'il vous plaît aider!

Lien Ideone ici .

C'est un exemple stupide de retour en arrière catastrophique . La complexité est O (2 n / 2 ). Alors que le programme pourrait ne pas fonctionner indéfiniment, ce serait probablement survivre à la fois vivant et non vivant des objets autour et pas si autour .

devnull
la source
5

C

Vous ne devriez avoir besoin que d’une des deux boucles, mais celle dont vous avez besoin dépend de votre compilateur.

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

}

Un simple dépassement des limites qui réinitialise i sur une valeur non terminale. Les compilateurs peuvent différer selon qu'ils allouent i au-dessus ou au-dessous de a sur la pile. J'ai donc inclus les dépassements dans les deux sens.

alexis
la source
5

C / C ++

C ++ n'autorise que les déclarations de variables en ligne simples utilisées ici, mais il est tout aussi facile de faire cette erreur en clair vieux 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;
}

Dans la boucle interne, "j" est comparé mais jamais incrémenté. (Le 'i ++' devrait être réellement 'j ++'). Ce n'est pas vraiment un tour sournois, mais plutôt une erreur réelle que j'ai commise dans le passé;) Quelque chose à surveiller.

Dave Ceddia
la source
2
Cela me prend habituellement au moins 5 minutes pour déboguer. Je déteste quand j'ai fait ça.
ace_HongKongIndependence
4

C #

Ce qui suit est une classe simple effectuant une opération arithmétique (somme) sur un grand tableau en entrée utilisant un thread en arrière-plan. Un exemple de programme est inclus.

Cependant, même si c'est assez simple, cela ne se termine jamais. Notez qu'il n'y a pas de tour de passe-passe (sosies de caractères, points-virgules cachés / manquants, trigraphes ;-), etc.)

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

Ceci est un exemple de bogue méchant du monde réel pouvant également apparaître dans votre code. Selon le modèle de mémoire .NET et la spécification C #, une boucle telle que celle dans WaitAndGetResultpeut ne jamais se terminer si vous ne spécifiez pas la variable comme volatile, car elle est modifiée par un autre thread. Voir cette question StackOverflow pour plus de détails. Le bogue dépend de l'implémentation .NET, il peut donc vous affecter ou non. Mais généralement, l'exécution d'une version compilée sur un processeur x64 semble afficher le problème. (Je l'ai essayé avec “csc.exe / o + / debug- infinite.cs” .)

Mormegil
la source