Bagaimana tidak menulis kode

gambar


Siap terjun ke dunia pemrograman yang berani? Ingin melihat bagaimana beberapa baris kode sederhana dapat berperilaku tak terduga?


Jika jawaban Anda adalah "Ya!" - selamat datang di kucing.


Anda akan menemukan beberapa tugas menghibur di C atau C ++.


Jawaban yang benar dengan penjelasan akan selalu disembunyikan di bawah spoiler.


Semoga beruntung


Tentang program terpendek


main; 

Apa yang terjadi jika Anda mengkompilasi program ini dengan kompiler bahasa C?


  1. Tidak dikompilasi.
  2. Tidak ditautkan.
  3. Disusun dan ditautkan.

Jawabannya adalah:

Ini adalah kode C yang valid.
Mengapa Di C, Anda bisa menghilangkan jenis fungsi yang dikembalikan dan ketika mendeklarasikan variabel, secara default akan menjadi int. Dan juga di C tidak ada perbedaan antara fungsi dan variabel global selama menghubungkan. Dalam hal ini, penghubung berpikir bahwa di bawah nama utama adalah fungsi.


Tentang garpu


 #include <iostream> #include <unistd.h> int main() { for(auto i = 0; i < 1000; i++) std::cout << "Hello world!\n"; fork(); } 

Berapa kali Hello World akan dicetak?


  1. 1000
  2. kurang
  3. lebih lanjut

Jawabannya adalah:

Operasi IO disangga untuk meningkatkan kinerja.
fork() panggil fork() akan menghasilkan proses baru, dengan ruang alamat duplikat copy-on-write.
Garis buffer akan dicetak dalam setiap proses.


Tentang indeks


 #include <iostream> int main() { int array[] = { 1, 2, 3 }; std::cout << (4, (1, 2)[array]) << std::endl; } 

Apa yang akan dicetak kode ini?


  1. 1
  2. 2
  3. 3
  4. 4
  5. Kesalahan kompilasi
  6. Tidak ditentukan oleh standar.

Jawabannya adalah:

Cetakan Porgram 3.
Kenapa begitu
Pertama, lihat indeks: array[index] == *(array + index) == *(index + array) == index[array]
Selanjutnya, kita berhadapan dengan operator koma biner. Itu membuang argumen kirinya dan mengembalikan nilai kanan.


Tentang regex


 #include <regex> #include <iostream> int main() { std::regex re { "(.*|.*)*O" }; std::string str { "0123456789" }; std::cout << std::regex_match(str, re); return 0; } 

Berapa waktu minimum musim reguler ini akan tangkap?


  1. ~ 1 ms.
  2. ~ 100 ms.
  3. ~ 1 detik
  4. ~ 1 mnt
  5. ~ 1 jam.
  6. ~ 1 tahun.
  7. kehidupan semesta yang lebih panjang.

Jawabannya adalah:

Haha Itu tidak bisa ditebak. Tergantung pada kompiler.
Di laptop saya, dentang menunjukkan hasil sekitar 100 ms.
GCC 57 detik! Satu menit! Benarkah ?!
Kenapa begitu
Ada 2 pendekatan untuk mengimplementasikan ekspresi reguler.
Salah satunya adalah mengubah ekspresi reguler menjadi mesin keadaan di O(n**2) , untuk ekspresi reguler panjang n karakter.
Kesulitan mencocokkan dengan string karakter m adalah O(m) . Ekspresi reguler seperti itu tidak mendukung pengulangan.
Yang kedua adalah sedikit pencarian serakah dengan pencarian mendalam. Mendukung backtracking.
Namun, kompleksitas operasi ekspresi reguler di STL tidak didefinisikan sama sekali. Bagus bahwa mereka berhasil dalam satu menit.


Tentang pindah dan lambda


 #include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(Foo&&) { std::cout << "Foo(Foo&&)\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } }; int main() { Foo f; auto a = [f = std::move(f)]() { return std::move(f); }; Foo f2(a()); return 0; } 

Baris apa yang terakhir dicetak oleh program?


  1. Foo()
  2. Foo(Foo&&)
  3. Foo(const Foo&)

Jawabannya adalah:

Foo(const Foo&) . Secara default, lambda kebal. const ditambahkan secara implisit ke semua nilai yang ditentukan dalam [] .
Ini memungkinkan lambdas berperilaku seperti fungsi normal. Untuk argumen yang sama, kembalikan nilai yang sama.
Apa yang terjadi dalam kasus ini? Saat kami mencoba memindahkan f dari suatu fungsi, kami mendapatkan const Foo&& .
Ini adalah hal yang sangat aneh, kompiler tidak tahu cara bekerja dengannya dan menyalin Foo . Anda dapat memperbaikinya dengan mendeklarasikan lambda yang dapat diubah:


 auto a = [f = std::move(f)]() mutable { return std::move(f); }; 

Atau buat konstruktor dari Foo(const Foo&&) .


Tentang x dan bilah


 #include <iostream> int x = 0; int bar(int(x)); int main() { std::cout << bar; } 

Apa yang terjadi jika Anda mencoba mengompilasi dan menjalankan ini?


  1. akan mencetak 0
  2. akan mencetak 1
  3. akan mencetak 0x0
  4. tidak dikompilasi
  5. tidak ditautkan

Jawabannya adalah:

Program akan mencetak 1 .
Kenapa begitu
int bar(int(x)); Apakah deklarasi fungsi, itu setara dengan int bar(int x); .
Jika Anda ingin tipe cast, Anda perlu menulis seperti int bar((int(x))); ini int bar((int(x))); .
Kemudian kami mencoba untuk menampilkan alamat fungsi, itu akan secara implisit dilemparkan ke bool, alamat fungsi tidak boleh nol, yaitu true
Fungsi bar() tidak digunakan. Karenanya, saat menautkan tidak akan ada simbol yang tidak direferensikan.


Tentang inline


 #include <iostream> inline size_t factorial(size_t n) { if (n == 0) return 1; return n * factorial(n - 1); } int main() { std::cout << factorial(5) << std::endl; } 

Program mengkompilasi dan menghubungkan tanpa kesalahan seperti ini g++ -c main.cpp -o main.o && g++ foo.cpp -o foo.o && g++ foo.o main.o -o test . Apa yang terjadi jika Anda menjalankannya?


  1. 120 akan dicetak.
  2. Apa pun bisa terjadi.

Jawabannya adalah:

Apa pun bisa terjadi. Ini adalah C ++.
Semua hasil tangkapan dalam kata inline. Ini hanya indikasi ke kompiler.
Itu hanya dapat mengkompilasi fungsi ini menjadi file objek (kemungkinan besar, itu akan melakukannya untuk fungsi rekursif).
Linker dapat membuang duplikat fungsi sebaris yang tidak dibangun ke dalam kode.
File hasil yang biasanya muncul di file pertama adalah yang ditemukan di file objek pertama.
Program ini akan mencetak 0 jika dalam foo.cpp:


 #include <cstddef> inline size_t factorial(size_t n) { if (n == 0) return 0; return 2 * n * factorial(n - 1); } int foo(size_t n) { return factorial(n); } 

Tentang desainer


 #include <iostream> struct Foo { Foo() { std::cout << "Foo()\n"; } Foo(const Foo&) { std::cout << "Foo(const Foo&)\n"; } Foo(int) { std::cout << "Foo(int)\n"; } Foo(int, int) { std::cout << "Foo(int, int)\n"; } Foo(const Foo&, int) { std::cout << "Foo(const Foo&, int)\n"; } Foo(int, const Foo&) { std::cout << "Foo(int, const Foo&)\n"; } }; void f(Foo) {} struct Bar { int i, j; Bar() { f(Foo(i, j)); f(Foo(i)); Foo(i, j); Foo(i); Foo(i, j); } }; int main() { Bar(); } 

Baris mana yang akan dicetak terakhir?


  1. Foo(int, int)
  2. Foo(const Foo&, int)
  3. Foo(int, const Foo&)
  4. Foo(int)

Jawabannya adalah:

Baris terakhir adalah Foo(const Foo&, int) .
Foo(i) adalah deklarasi variabel, ini setara dengan Foo i , yang berarti bahwa bidang kelas i akan menghilang dari ruang lingkup.


Kesimpulan


Semoga Anda tidak pernah melihat ini dalam kode nyata.

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


All Articles