Coderbyte adalah situs tantangan pengkodean online (saya menemukannya hanya 2 menit yang lalu).
Tantangan C ++ pertama yang disambut dengan Anda memiliki kerangka C ++ yang perlu Anda ubah:
#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; }
Jika Anda sedikit terbiasa dengan C ++, hal pertama * yang muncul di mata Anda adalah:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
Jadi, ok, panggilan kode gets
yang sudah usang sejak C ++ 11 dan dihapus sejak C ++ 14 yang buruk itu sendiri.
Tapi kemudian saya menyadari: gets
adalah tipe char*(char*)
. Jadi ia seharusnya tidak menerima FILE*
parameter dan hasilnya seharusnya tidak dapat digunakan sebagai pengganti int
parameter, tapi ... tidak hanya mengkompilasi tanpa peringatan atau kesalahan, tetapi itu berjalan dan benar-benar melewati nilai input yang benar FirstFactorial
.
Di luar situs khusus ini, kode tidak dikompilasi (seperti yang diharapkan), jadi apa yang terjadi di sini?
* Sebenarnya yang pertama adalah using namespace std
tetapi itu tidak relevan dengan masalah saya di sini.
sumber
stdin
di perpustakaan standar adalah aFILE*
, dan penunjuk ke tipe apa pun dikonversi menjadichar*
, yang merupakan tipe argumen darigets()
. Namun, Anda tidak boleh, pernah, pernah menulis kode seperti itu di luar kontes C yang membingungkan. Jika kompiler Anda bahkan menerimanya, tambahkan lebih banyak bendera peringatan, dan jika Anda mencoba untuk memperbaiki basis kode yang memiliki konstruksi di dalamnya, ubah peringatan menjadi kesalahan.gets(stdin )
(dengan ruang ekstra) menghasilkan kesalahan C ++ yang diharapkan.Jawaban:
Saya adalah pendiri Coderbyte dan juga orang yang menciptakan retasan ini
gets(stdin)
.Komentar pada posting ini benar bahwa itu adalah bentuk mencari-dan-ganti, jadi izinkan saya menjelaskan mengapa saya melakukan ini dengan sangat cepat.
Kembali pada hari ketika saya pertama kali membuat situs (sekitar 2012), itu hanya mendukung JavaScript. Tidak ada cara untuk "membaca input" di JavaScript yang berjalan di browser, dan jadi akan ada fungsi
foo(input)
dan saya menggunakanreadline()
fungsi dari Node.js untuk menyebutnya sepertifoo(readline())
. Kecuali saya masih anak-anak dan tidak tahu yang lebih baik, jadi saya benar-benar hanya digantireadline()
dengan input pada saat run-time. Jadifoo(readline())
menjadifoo(2)
ataufoo("hello")
yang berfungsi dengan baik untuk JavaScript.Sekitar 2013/2014 saya menambahkan lebih banyak bahasa dan menggunakan layanan pihak ketiga untuk mengevaluasi kode online, tetapi sangat sulit untuk melakukan stdin / stdout dengan layanan yang saya gunakan, jadi saya terjebak dengan pencarian dan penggantian konyol yang sama untuk bahasa seperti Python, Ruby, dan akhirnya C ++, C #, dll.
Maju cepat ke hari ini, saya menjalankan kode di wadah saya sendiri, tetapi tidak pernah memperbarui cara stdin / stdout bekerja karena orang sudah terbiasa dengan hack aneh (beberapa orang bahkan memposting di forum yang menjelaskan bagaimana cara mengatasinya).
Saya tahu ini bukan praktik terbaik dan tidak membantu bagi seseorang yang belajar bahasa baru untuk melihat retasan seperti ini, tetapi idenya adalah bagi programmer baru untuk tidak khawatir membaca input sama sekali dan hanya fokus pada penulisan algoritma untuk menyelesaikan masalah. Satu keluhan umum tentang pengkodean situs tantangan bertahun-tahun yang lalu adalah bahwa programmer baru akan menghabiskan banyak waktu hanya mencari tahu cara membaca dari
stdin
atau membaca baris dari file, jadi saya ingin coders baru untuk menghindari masalah ini pada Coderbyte.Saya akan segera memperbarui seluruh halaman editor bersama dengan kode default dan
stdin
membaca untuk bahasa. Semoga programmer C ++ akan menikmati menggunakan Coderbyte lebih lanjut :)sumber
TAKE_INPUT
, kemudian gunakan find-replace Anda untuk memasukkan#define TAKE_INPUT whatever_here
di bagian atas.Saya tertarik. Jadi, waktu untuk mengenakan kacamata investigasi dan karena saya tidak memiliki akses ke kompiler atau bendera kompilasi saya perlu mendapatkan inventif. Juga karena tidak ada tentang kode ini masuk akal itu bukan pertanyaan ide buruk setiap asumsi.
Pertama mari kita periksa jenis sebenarnya
gets
. Saya punya sedikit trik untuk itu:Dan itu terlihat ... normal:
gets
ditandai sebagai usang dan memiliki tanda tanganchar *(char *)
. Tapi bagaimana caraFirstFactorial(gets(stdin));
kompilasi?Mari kita coba yang lain:
Yang memberi kita:
Akhirnya kita mendapatkan sesuatu:
decltype(8)
. Jadi semuanyagets(stdin)
diganti secara tekstual dengan input (8
).Dan hal-hal semakin aneh. Kesalahan kompiler berlanjut:
Jadi sekarang kita mendapatkan kesalahan yang diharapkan untuk
cout << FirstFactorial(gets(stdin));
Saya memeriksa makro dan karena
#undef gets
sepertinya tidak melakukan apa-apa sepertinya itu bukan makro.Tapi
Itu mengkompilasi.
Tapi
Tidak dengan kesalahan yang diharapkan di
n2
telepon.Dan lagi, hampir semua modifikasi untuk
main
membuat gariscout << FirstFactorial(gets(stdin));
meludahkan kesalahan yang diharapkan.Apalagi yang
stdin
tampak kosong.Jadi saya hanya bisa menyimpulkan dan berspekulasi mereka memiliki program kecil yang mem-parsing sumber dan mencoba (buruk) untuk mengganti
gets(stdin)
dengan nilai input test case sebelum benar-benar memasukkannya ke dalam kompiler. Jika ada yang punya teori yang lebih baik atau benar-benar tahu apa yang mereka lakukan, silakan bagikan!Ini jelas merupakan praktik yang sangat buruk. Saat meneliti ini saya menemukan setidaknya ada pertanyaan di sini ( contoh ) tentang ini dan karena orang tidak tahu bahwa ada situs di luar sana yang melakukan ini, jawaban mereka adalah "jangan gunakan
gets
gunakan ... sebagai gantinya" yang memang saran yang bagus tetapi lebih membingungkan OP karena usaha membaca yang valid dari stdin akan gagal di situs ini.TLDR
gets(stdin)
tidak valid C ++. Ini tipuan yang digunakan situs ini (untuk alasan apa saya tidak tahu). Jika Anda ingin terus mengirimkan di situs (saya tidak mendukungnya atau tidak mendukungnya) Anda harus menggunakan konstruksi ini yang jika tidak tidak masuk akal, tetapi perlu diketahui bahwa itu rapuh. Hampir semua modifikasi untukmain
memuntahkan kesalahan. Di luar situs ini menggunakan metode membaca input normal.sumber
std::cout << "gets(stdin)";
dan hasilnya adalah8
(atau apa pun yang Anda ketik di bidang 'input'. Ini adalah penyalahgunaan bahasa yang memalukan."gets(stdin)"
. Itu string literal yang bahkan preprocessor tidak akan menyentuhSaya mencoba tambahan berikut
main
dalam editor Coderbyte:Di mana potongan misterius dan misterius
gets(stdin)
muncul di dalam string literal. Ini seharusnya tidak boleh diubah oleh apa pun, bahkan preprocessor, dan setiap programmer C ++ harus mengharapkan kode ini untuk mencetak string yang tepatgets(stdin)
ke output standar. Namun kita melihat output berikut, ketika dikompilasi dan dijalankan pada coderbyte:Di mana nilai
8
diambil langsung dari bidang 'input' yang mudah di bawah editor.Dari sini, jelaslah bahwa editor online ini melakukan operasi pencarian dan ganti buta pada kode sumber, penampilan pengganti
gets(stdin)
dengan 'input' pengguna. Saya pribadi menyebut ini penyalahgunaan bahasa yang lebih buruk daripada makro preprosesor yang ceroboh.Dalam konteks situs web tantangan pengkodean online, saya khawatir dengan hal ini karena mengajarkan praktik yang tidak konvensional, tidak standar, tidak berarti, dan setidaknya tidak aman seperti
gets(stdin)
, dan dengan cara yang tidak dapat diulang pada platform lain.Saya yakin itu tidak bisa ini sulit untuk hanya menggunakan
std::cin
dan hanya input stream untuk program.sumber
gets(stdin)
yang diganti? Maksud saya 'buta' dalam arti bahwa itu tampaknya tidak mengetahui sintaks atau tata bahasa bahasa.System.out.print(FirstFactorial(s.nextLine()9));
mencetak89
bahkan ketikas
tidak ditentukan.