O Coderbyte é um site de desafio de codificação on-line (eu o encontrei há apenas 2 minutos).
O primeiro desafio de C ++ que você recebe é um esqueleto de C ++ que você precisa 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; }
Se você está pouco familiarizado com C ++, a primeira coisa * que aparece em seus olhos é:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
Então, ok, o código chama gets
obsoleto desde C ++ 11 e removido desde C ++ 14, o que é ruim por si só.
Mas então eu percebo: gets
é do tipo char*(char*)
. Portanto, ele não deve aceitar um FILE*
parâmetro e o resultado não deve ser utilizado no lugar de um int
parâmetro, mas ... não apenas compila sem avisos ou erros, mas executa e passa o valor de entrada correto para FirstFactorial
.
Fora deste site específico, o código não é compilado (como esperado), então o que está acontecendo aqui?
* Na verdade, o primeiro é, using namespace std
mas isso é irrelevante para o meu problema aqui.
fonte
stdin
na biblioteca padrão háFILE*
ae um ponteiro para qualquer tipo é convertido emchar*
, que é o tipo do argumento degets()
. No entanto, você nunca deve nunca escrever esse tipo de código fora de um concurso ofuscado em C. Se o seu compilador o aceitar, adicione mais sinalizadores de aviso e, se você estiver tentando corrigir uma base de código com essa construção, transforme os avisos em erros.gets(stdin )
(com um espaço extra) produz o erro C ++ esperado.Respostas:
Eu sou o fundador da Coderbyte e também o cara que criou esse
gets(stdin)
hack.Os comentários nesta postagem estão corretos, dizendo que é uma forma de encontrar e substituir, então deixe-me explicar por que fiz isso rapidamente.
No dia em que criei o site (por volta de 2012), ele era compatível apenas com JavaScript. Não havia como "ler a entrada" no JavaScript em execução no navegador e, portanto, haveria uma função
foo(input)
e eu usei areadline()
função do Node.js para chamá-lo dessa maneirafoo(readline())
. Exceto que eu era criança e não sabia melhor, então eu literalmente substituíreadline()
a entrada em tempo de execução. Assim,foo(readline())
tornou-sefoo(2)
oufoo("hello")
que funcionou bem para JavaScript.Por volta de 2013/2014, adicionei mais idiomas e usei serviços de terceiros para avaliar o código on-line, mas era muito difícil fazer stdin / stdout com os serviços que eu estava usando, então fiquei com o mesmo tolo encontrar e substituir para idiomas como Python, Ruby e, eventualmente, C ++, C #, etc.
Avançando hoje, executo o código em meus próprios contêineres, mas nunca atualizei o funcionamento do stdin / stdout porque as pessoas se acostumaram com o hack estranho (algumas pessoas até postaram em fóruns explicando como contorná-lo).
Sei que não é uma prática recomendada e não é útil para alguém que está aprendendo um novo idioma ver hacks como esse, mas a idéia era que os novos programadores não se preocupassem com a leitura de entrada e apenas se concentrassem em escrever o algoritmo para resolver o problema. problema. Uma queixa comum sobre sites de desafio de codificação anos atrás era que novos programadores passavam muito tempo apenas descobrindo como ler
stdin
ou ler linhas de um arquivo, então eu queria que novos codificadores evitassem esse problema no Coderbyte.Em breve, atualizarei a página inteira do editor, juntamente com o código padrão e a
stdin
leitura para idiomas. Espero que os programadores de C ++ gostem de usar mais o Coderbyte :)fonte
TAKE_INPUT
, em seguida, use seu find-replace para inserir#define TAKE_INPUT whatever_here
na parte superior.Estou intrigado. Portanto, é hora de colocar os óculos de investigação e, como não tenho acesso aos sinalizadores de compilação ou compilação, preciso ser criativo. Também porque nada sobre esse código faz sentido, não é uma má idéia questionar todas as suposições.
Primeiro, vamos verificar o tipo real de
gets
. Eu tenho um pequeno truque para isso:E isso parece ... normal:
gets
está marcado como descontinuado e tem a assinaturachar *(char *)
. Mas então como estáFirstFactorial(gets(stdin));
compilando?Vamos tentar outra coisa:
O que nos dá:
Finalmente estamos começando algo:
decltype(8)
. Portanto, o todogets(stdin)
foi substituído textualmente pela entrada (8
).E as coisas ficam mais estranhas. O erro do compilador continua:
Então agora obtemos o erro esperado para
cout << FirstFactorial(gets(stdin));
Eu verifiquei uma macro e, como
#undef gets
parece não fazer nada, parece que não é uma macro.Mas
Compila.
Mas
Não com o erro esperado na
n2
linha.E, novamente, quase qualquer modificação para
main
fazer a linhacout << FirstFactorial(gets(stdin));
cuspir o erro esperado.Além disso, o
stdin
fato parece estar vazio.Portanto, só posso concluir e especular que eles têm um pequeno programa que analisa a fonte e tenta (mal) substituir
gets(stdin)
pelo valor de entrada do caso de teste antes de realmente inseri-lo no compilador. Se alguém tiver uma teoria melhor ou realmente souber o que está fazendo, compartilhe!Obviamente, essa é uma prática muito ruim. Ao pesquisar isso, descobri que há pelo menos uma pergunta aqui ( exemplo ) sobre isso e porque as pessoas não têm idéia de que existe um site por aí que faça isso, sua resposta é "não use o
gets
uso ... em vez", o que é realmente um bom conselho, mas apenas confunde mais o OP, pois qualquer tentativa de leitura válida da stdin falhará neste site.TLDR
gets(stdin)
é C ++ inválido. É um truque que esse site em particular usa (por quais razões eu não consigo descobrir). Se você deseja continuar enviando no site (eu não estou endossando nem endossando), você deve usar essa construção que de outra forma não faria sentido, mas esteja ciente de que é quebradiça. Quase todas as modificaçõesmain
causam erros. Fora deste site, use métodos normais de leitura de entradas.fonte
std::cout << "gets(stdin)";
e a saída é8
(ou o que você digitar no campo 'input'. Este é um abuso vergonhoso da linguagem."gets(stdin)"
. Essa é uma string literal que nem o pré-processador tocariaEu tentei a seguinte adição
main
no editor Coderbyte:Onde o trecho misterioso e enigmático
gets(stdin)
aparece dentro de uma string literal. Isso não deve ser transformado por nada, nem mesmo pelo pré-processador, e qualquer programador C ++ deve esperar que esse código imprima a seqüência exatagets(stdin)
na saída padrão. E ainda vemos a seguinte saída, quando compilada e executada em coderbyte:Onde o valor
8
é retirado diretamente do conveniente campo 'input' sob o editor.A partir disso, fica claro que este editor on-line está executando operações de localização e substituição às cegas no código-fonte, aparências de substituição
gets(stdin)
pela 'entrada' do usuário. Pessoalmente, eu chamaria isso de uso indevido da linguagem, pior do que macros de pré-processador descuidado.No contexto de um site de desafio de codificação on-line, estou preocupado com isso porque ensina práticas não convencionais, não padronizadas, sem sentido e pelo menos inseguras , como
gets(stdin)
, e de uma maneira que não podem ser repetidas em outras plataformas.Tenho certeza de que não pode ser tão difícil de usar
std::cin
e apenas transmitir entrada para um programa.fonte
gets(stdin)
que é substituído? Eu quis dizer "cego" no sentido de que parece desconhecer a sintaxe ou gramática da linguagem.System.out.print(FirstFactorial(s.nextLine()9));
impressa89
mesmo quandos
está indefinida.