Teka-teki yang menarik di C

Melihat melalui protokol wawancara untuk posisi pengembang, saya menemukan masalah berikut: "Tawarkan kode yang akan mencetak angka dalam urutan menurun dari n menjadi 0, tanpa menggunakan operator perbandingan (tersembunyi atau eksplisit) (implementasi fungsi cetak tidak masuk hitungan)". Terlepas dari kenyataan bahwa tugas ini tidak ada hubungannya dengan saya, tugas itu membuat saya dan saya memutuskan untuk memikirkan cara untuk menyelesaikannya (meskipun saya masih tidak tahu siapa dan kapan menyelesaikan tugas mana yang akan memerlukan metode optimasi kode ini).


Hal pertama yang terlintas dalam pikiran adalah mencoba menggunakan pola. Seperti itu


template<int n> void print() { printf("%d\n", n); print<n - 1>(); } template<> void print<0>() { printf("0\n"); } int main(int argc, char* argv[]) { print<N>(); return 0; } 

Masalahnya adalah bahwa pemrograman adalah disiplin teknik, bukan ilmu gaib, dan jika "sesuatu" harus terjadi dalam sistem, maka "itu" harus dijelaskan dan sumber daya harus dialokasikan untuk itu, dan dalam hal ini, karena pengembangan template terjadi pada tahap kompilasi, ada pembatasan pada bersarangnya konstruksi semacam ini (dan itu baik dan benar, dan terima kasih Tuhan,), dan kompilator mengeluarkan "kesalahan fatal C1202: tipe rekursif atau konteks ketergantungan fungsi terlalu kompleks" dengan ukuran N lebih besar 2000


Hal berikutnya yang muncul dalam pikiran adalah menggunakan metode klasik dengan pointer ke fungsi.


 typedef void(*PrintFunc)(int); void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); } void printNumber(int n) { printf("%d\n", n--); g_functors[!!n](n); } int main(int argc, char* argv[]) { printNumber(N); return 0; } 

Tetapi bahkan kemudian, pembatasan yang diberlakukan pada kita oleh hukum alam membuat diri mereka terasa, dan karena panggilan fungsi bersarang dibatasi oleh ukuran tumpukan, "Stack overflow" yang sah diperoleh dengan nilai N> 4630.


Di tempat ini, kekecewaan dan kemarahan benar-benar menguasai saya dan saya menyadari bahwa untuk solusi lengkap untuk masalah ini, Anda tidak boleh menghindari apa pun, termasuk trik paling kotor. Masalahnya adalah bahwa untuk nilai-nilai N tertentu kita perlu mentransfer kontrol ke bagian kode yang diperlukan. Dan ini tidak masalah ketika kita memiliki pernyataan bersyarat yang kita miliki, tetapi ketika mereka tidak ada di sana, kita harus menggunakan ilmu sihir. Pada zaman kuno, ini bisa diselesaikan dengan menggunakan metode goto, tetapi sejak itu pemburu penyihir dan pejuang naga lainnya telah sangat membatasi fungsinya (dan ini juga baik dan benar) dan kami ingin menulis sesuatu seperti ini


 g_functors[0] = [](int){print("0\n"); goto end; } g_functors[1] = [](int n){print("%d\n", n); goto begin; } begin: g_functors[!!n](n--); end: 

tapi kami tidak bisa.
Oleh karena itu, walaupun saya dilarang untuk terlibat dalam sihir hitam, dalam hal ini saya memutuskan untuk membuat pengecualian dengan menambahkan sedikit sihir pada contoh sebelumnya.


 void printZero(int); void printNumber(int n); PrintFunc g_functors[] = {printZero, printNumber}; void printZero(int) { printf("0\n"); throw 0; } void printNumber(int n) { printf("%d\n", n); } int main(int argc, char* argv[]) { int n = N; try{ begin: g_functors[!!n](n--); goto begin; } catch (...){} return 0; } 

Dan ini benar-benar memecahkan masalah (untuk setiap N).


PS: Saya akan senang mendengar tentang metode lain untuk menyelesaikan masalah ini

Source: https://habr.com/ru/post/id428343/


All Articles