Coderbyte est un site de défi de codage en ligne (je l'ai trouvé il y a seulement 2 minutes).
Le premier défi C ++ qui vous est accueilli a un squelette C ++ que vous devez modifier:
#include <iostream> #include <string> using namespace std; int FirstFactorial(int num) { // Code goes here return num; } int main() { // Keep this function call here cout << FirstFactorial(gets(stdin)); return 0; }
Si vous êtes peu familier avec C ++, la première chose * qui vous vient aux yeux est:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
Donc, ok, le code appelle gets
qui est obsolète depuis C ++ 11 et supprimé depuis C ++ 14 ce qui est mauvais en soi.
Mais alors je me rends compte: gets
est de type char*(char*)
. Donc, il ne devrait pas accepter de FILE*
paramètre et le résultat ne devrait pas être utilisable à la place d'un int
paramètre, mais ... non seulement il se compile sans aucun avertissement ni erreur, mais il s'exécute et transmet en fait la valeur d'entrée correcte à FirstFactorial
.
En dehors de ce site particulier, le code ne se compile pas (comme prévu), alors que se passe-t-il ici?
* En fait, le premier est, using namespace std
mais ce n'est pas pertinent pour mon problème ici.
stdin
dans la bibliothèque standard se trouve unFILE*
, et un pointeur vers n'importe quel type est converti enchar*
, qui est le type de l'argument degets()
. Cependant, vous ne devriez jamais, jamais, jamais écrire ce genre de code en dehors d'un concours C obscurci. Si votre compilateur l'accepte même, ajoutez plus d'indicateurs d'avertissement, et si vous essayez de corriger une base de code contenant cette construction, transformez les avertissements en erreurs.gets(stdin )
(avec un espace supplémentaire) produit l'erreur C ++ attendue.Réponses:
Je suis le fondateur de Coderbyte et aussi le gars qui a créé ce
gets(stdin)
hack.Les commentaires sur cet article indiquent qu'il s'agit d'une forme de recherche et de remplacement, alors laissez-moi vous expliquer pourquoi j'ai fait cela très rapidement.
À l'époque où j'ai créé le site pour la première fois (vers 2012), il ne supportait que JavaScript. Il n'y avait aucun moyen de "lire en entrée" en JavaScript fonctionnant dans le navigateur, il y aurait donc une fonction
foo(input)
et j'ai utilisé lareadline()
fonction de Node.js pour l'appeler commefoo(readline())
. Sauf que j'étais un enfant et que je ne savais pas mieux, alors j'ai littéralement remplacéreadline()
par l'entrée au moment de l'exécution. Ainsifoo(readline())
est devenufoo(2)
oufoo("hello")
qui a bien fonctionné pour JavaScript.Vers 2013/2014, j'ai ajouté plus de langues et utilisé un service tiers pour évaluer le code en ligne, mais il était très difficile de faire stdin / stdout avec les services que j'utilisais, donc je suis resté avec le même idiot find-and-replace pour les langues comme Python, Ruby et éventuellement C ++, C #, etc.
Avance rapide jusqu'à aujourd'hui, j'exécute le code dans mes propres conteneurs, mais je n'ai jamais mis à jour le fonctionnement de stdin / stdout parce que les gens se sont habitués au piratage étrange (certaines personnes ont même posté sur des forums pour expliquer comment le contourner).
Je sais que ce n'est pas la meilleure pratique et qu'il n'est pas utile pour quelqu'un qui apprend une nouvelle langue de voir des hacks comme celui-ci, mais l'idée était que les nouveaux programmeurs ne se soucient pas du tout de la lecture des entrées et se concentrent simplement sur l'écriture de l'algorithme pour résoudre le problème. problème. Une plainte courante concernant le codage des sites de défi il y a des années était que les nouveaux programmeurs passaient beaucoup de temps à trouver comment lire
stdin
ou lire les lignes d'un fichier, je voulais donc que de nouveaux codeurs évitent ce problème sur Coderbyte.Je mettrai bientôt à jour la page entière de l'éditeur avec le code par défaut et la
stdin
lecture des langues. Espérons que les programmeurs C ++ apprécieront davantage l'utilisation de Coderbyte :)la source
TAKE_INPUT
, puis d'utiliser votre recherche-remplacement pour l'insérer#define TAKE_INPUT whatever_here
en haut.Je suis intrigué. Donc, il est temps de mettre les lunettes d'enquête et comme je n'ai pas accès au compilateur ou aux indicateurs de compilation, je dois devenir inventif. Aussi parce que rien dans ce code n'a de sens, ce n'est pas une mauvaise idée de remettre en question chaque hypothèse.
Commençons par vérifier le type réel de
gets
. J'ai un petit truc pour ça:Et cela semble ... normal:
gets
est marqué comme obsolète et possède la signaturechar *(char *)
. Mais alors comment est laFirstFactorial(gets(stdin));
compilation?Essayons autre chose:
Ce qui nous donne:
Enfin , nous obtenons quelque chose:
decltype(8)
. Donc, le tout agets(stdin)
été remplacé textuellement par l'entrée (8
).Et les choses deviennent plus étranges. L'erreur du compilateur continue:
Alors maintenant, nous obtenons l'erreur attendue pour
cout << FirstFactorial(gets(stdin));
J'ai vérifié une macro et depuis
#undef gets
semble ne rien faire, il semble que ce ne soit pas une macro.Mais
Il compile.
Mais
Pas avec l'erreur attendue à la
n2
ligne.Et encore une fois, presque toutes les modifications apportées à
main
la lignecout << FirstFactorial(gets(stdin));
crachent l'erreur attendue.De plus, le
stdin
semble être vide.Je ne peux donc que conclure et spéculer qu'ils ont un petit programme qui analyse la source et essaie (mal) de remplacer
gets(stdin)
par la valeur d'entrée du cas de test avant de l'introduire dans le compilateur. Si quelqu'un a une meilleure théorie ou sait ce qu'il fait, partagez-le!C'est évidemment une très mauvaise pratique. En recherchant cela, j'ai trouvé qu'il y avait au moins une question ici ( exemple ) à ce sujet et parce que les gens n'ont aucune idée qu'il existe un site qui le fait, leur réponse est "n'utilisez pas,
gets
utilisez ... à la place", ce qui est en effet un bon conseil mais ne fait que confondre davantage l'OP puisque toute tentative de lecture valide depuis stdin échouera sur ce site.TLDR
gets(stdin)
n'est pas valide en C ++. C'est un gadget que ce site utilise en particulier (pour quelles raisons je ne peux pas comprendre). Si vous souhaitez continuer à soumettre sur le site (je ne l'approuve ni ne l'approuve), vous devez utiliser cette construction qui autrement n'aurait pas de sens, mais sachez qu'elle est fragile. Presque toutes les modifications apportées àmain
vont cracher une erreur. En dehors de ce site, utilisez des méthodes de lecture d'entrée normales.la source
std::cout << "gets(stdin)";
et la sortie est8
(ou ce que vous tapez dans le champ 'input'. C'est un abus honteux de la langue."gets(stdin)"
. C'est une chaîne littérale que même le préprocesseur ne toucherait pasJ'ai essayé l'ajout suivant
main
dans l'éditeur Coderbyte:Où l'extrait mystérieux et énigmatique
gets(stdin)
apparaît dans une chaîne littérale. Cela ne devrait pas être transformé par quoi que ce soit, même pas le préprocesseur, et tout programmeur C ++ devrait s'attendre à ce que ce code imprime la chaîne exactegets(stdin)
sur la sortie standard. Et pourtant, nous voyons la sortie suivante, une fois compilée et exécutée sur coderbyte:Où la valeur
8
est tirée directement du champ «d'entrée» pratique sous l'éditeur.À partir de là, il est clair que cet éditeur en ligne effectue des opérations de recherche et de remplacement aveugles sur le code source, des apparences de substitution
gets(stdin)
avec l '«entrée» de l'utilisateur. Personnellement, j'appellerais cela une mauvaise utilisation du langage qui est pire que des macros de préprocesseur imprudentes.Dans le contexte d'un site Web de défi de codage en ligne, cela m'inquiète car il enseigne des pratiques non conventionnelles, non standard, dénuées de sens et au moins dangereuses comme
gets(stdin)
, et d'une manière qui ne peut pas être répétée sur d'autres plates-formes.Je suis sûr que ce ne peut pas être ce difficile à utiliser simplement
std::cin
et juste entrée flux à un programme.la source
gets(stdin)
qui est remplacé? Je voulais dire «aveugle» dans le sens où il semble ignorer la syntaxe ou la grammaire de la langue.System.out.print(FirstFactorial(s.nextLine()9));
s'imprime89
même si elles
n'est pas définie.