Coderbyte es un sitio de desafío de codificación en línea (lo encontré hace solo 2 minutos).
El primer desafío de C ++ con el que te encuentras tiene un esqueleto de C ++ que debes modificar:
#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 está poco familiarizado con C ++, lo primero * que aparece en sus ojos es:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
Entonces, ok, el código llama, gets
que está en desuso desde C ++ 11 y se elimina desde C ++ 14, que es malo en sí mismo.
Pero luego me doy cuenta: gets
es de tipo char*(char*)
. Por lo tanto, no debería aceptar un FILE*
parámetro y el resultado no debería ser utilizable en lugar de un int
parámetro, sino que ... no solo se compila sin advertencias o errores, sino que se ejecuta y realmente le pasa el valor de entrada correcto FirstFactorial
.
Fuera de este sitio en particular, el código no se compila (como se esperaba), entonces, ¿qué está pasando aquí?
* En realidad, el primero es using namespace std
pero eso es irrelevante para mi problema aquí.
fuente
stdin
en cuenta que en la biblioteca estándar hay unFILE*
, y un puntero a cualquier tipo se conviertechar*
, que es el tipo de argumento degets()
. Sin embargo, nunca debes escribir ese tipo de código fuera de un concurso de C ofuscado. Si su compilador incluso lo acepta, agregue más indicadores de advertencia, y si está tratando de arreglar una base de código que tiene esa construcción, convierta las advertencias en errores.gets(stdin )
(con un espacio extra) produce el error esperado de C ++.Respuestas:
Soy el fundador de Coderbyte y también el tipo que creó este
gets(stdin)
truco.Los comentarios en esta publicación son correctos de que es una forma de buscar y reemplazar, así que permítanme explicar por qué hice esto realmente rápido.
En el día en que creé el sitio por primera vez (alrededor de 2012), solo admitía JavaScript. No había forma de "leer en la entrada" en JavaScript que se ejecuta en el navegador, por lo que habría una función
foo(input)
y utilicé lareadline()
función de Node.js para llamarla asífoo(readline())
. Excepto que era un niño y no lo sabía mejor, así que literalmente lo reemplacéreadline()
con la entrada en tiempo de ejecución. Así sefoo(readline())
convirtiófoo(2)
ofoo("hello")
que funcionó bien para JavaScript.Alrededor de 2013/2014 agregué más idiomas y utilicé un servicio de terceros para evaluar el código en línea, pero fue muy difícil hacer stdin / stdout con los servicios que estaba usando, así que me quedé con el mismo tonto de buscar y reemplazar idiomas. como Python, Ruby y eventualmente C ++, C #, etc.
Avance rápido hasta hoy, ejecuto el código en mis propios contenedores, pero nunca actualicé la forma en que funciona stdin / stdout porque la gente se ha acostumbrado al truco extraño (algunas personas incluso han publicado en foros explicando cómo solucionarlo).
Sé que no es la mejor práctica y no es útil para alguien que está aprendiendo un nuevo idioma ver hacks como este, pero la idea era que los nuevos programadores no se preocuparan por leer la entrada y solo se enfocaran en escribir el algoritmo para resolver el problema. problema. Una queja común acerca de la codificación de sitios de desafío hace años fue que los nuevos programadores pasarían mucho tiempo descubriendo cómo leer
stdin
o leer líneas de un archivo, por lo que quería nuevos codificadores para evitar este problema en Coderbyte.Pronto actualizaré toda la página del editor junto con el código predeterminado y la
stdin
lectura de idiomas. Esperemos que los programadores de C ++ disfruten más usando Coderbyte :)fuente
TAKE_INPUT
, luego use su find-replace para insertar#define TAKE_INPUT whatever_here
en la parte superior.Estoy intrigado. Entonces, es hora de poner las gafas de investigación y, dado que no tengo acceso al compilador o las banderas de compilación, necesito ser inventivo. Además, porque nada de este código tiene sentido, no es una mala idea cuestionar cada supuesto.
Primero, verifiquemos el tipo real de
gets
. Tengo un pequeño truco para eso:Y eso se ve ... normal:
gets
está marcado como obsoleto y tiene la firmachar *(char *)
. Pero entonces, ¿cómo estáFirstFactorial(gets(stdin));
compilando?Probemos algo más:
Lo que nos da:
Finalmente estamos consiguiendo algo:
decltype(8)
. Por lo tanto, todogets(stdin)
se reemplazó textualmente con la entrada (8
).Y las cosas se ponen más raras. El error del compilador continúa:
Entonces ahora tenemos el error esperado para
cout << FirstFactorial(gets(stdin));
Revisé una macro y, como
#undef gets
parece no hacer nada, parece que no es una macro.Pero
Se compila.
Pero
No con el error esperado en la
n2
línea.Y nuevamente, casi cualquier modificación
main
hace que la líneacout << FirstFactorial(gets(stdin));
escupe el error esperado.Además, la
stdin
realidad parece estar vacía.Por lo tanto, solo puedo concluir y especular que tienen un pequeño programa que analiza la fuente e intenta (mal) reemplazarlo
gets(stdin)
con el valor de entrada del caso de prueba antes de realmente introducirlo en el compilador. Si alguien tiene una teoría mejor o realmente sabe lo que está haciendo, ¡comparta!Obviamente, esta es una muy mala práctica. Mientras investigaba esto, descubrí que hay al menos una pregunta aquí ( ejemplo ) sobre esto y porque la gente no tiene idea de que hay un sitio que hace esto, su respuesta es "no use
gets
usar ... en cambio", que es es un buen consejo, pero solo confunde más al OP ya que cualquier intento de una lectura válida de stdin fallará en este sitio.TLDR
gets(stdin)
es inválido C ++. Es un truco que utiliza este sitio en particular (por qué razones no puedo entender). Si desea continuar enviando en el sitio (no lo estoy respaldando ni lo estoy respaldando), debe usar esta construcción que de otra manera no tendría sentido, pero tenga en cuenta que es frágil. Casi cualquier modificación amain
escupirá un error. Fuera de este sitio, utilice métodos de lectura de entrada normales.fuente
std::cout << "gets(stdin)";
y la salida es8
(o lo que se teclea en el campo 'entrada' Se trata de un abuso vergonzoso de la lengua.."gets(stdin)"
. Esa es una cadena literal que incluso el preprocesador no tocaríaIntenté la siguiente adición
main
en el editor de Coderbyte:Donde el fragmento misterioso y enigmático
gets(stdin)
aparece dentro de una cadena literal. Esto no debería ser transformado por nada, ni siquiera el preprocesador, y cualquier programador de C ++ debería esperar que este código imprima la cadena exactagets(stdin)
a la salida estándar. Y sin embargo, vemos el siguiente resultado, cuando se compila y se ejecuta en coderbyte:Donde el valor
8
se toma directamente del conveniente campo de 'entrada' debajo del editor.A partir de esto, está claro que este editor en línea está realizando operaciones ciegas de buscar y reemplazar en el código fuente, apariencias de sustitución
gets(stdin)
con la 'entrada' del usuario. Personalmente, llamaría a esto un mal uso del lenguaje que es peor que las macros de preprocesadores descuidados.En el contexto de un sitio web de desafío de codificación en línea, estoy preocupado por esto porque enseña poco convencional, no estándar, sin sentido y al menos inseguras prácticas gusta
gets(stdin)
, y de una manera que no puede ser repetido en otras plataformas.Estoy seguro de que no puede ser tan difícil de usar
std::cin
y simplemente transmitir la entrada a un programa.fuente
gets(stdin)
que se reemplaza eso? Quise decir "ciego" en el sentido de que parece no ser consciente de la sintaxis o gramática del lenguaje.System.out.print(FirstFactorial(s.nextLine()9));
imprime89
incluso cuandos
no está definida.