Saya harus memulai dengan mengatakan bahwa C dan C ++ adalah bahasa pemrograman pertama yang saya pelajari. Saya mulai dengan C, kemudian melakukan C ++ di sekolah, banyak, dan kemudian kembali ke C untuk menjadi fasih di dalamnya.
Hal pertama yang membingungkan saya tentang petunjuk ketika belajar C adalah sederhana:
char ch;
char str[100];
scanf("%c %s", &ch, str);
Kebingungan ini sebagian besar berakar pada telah diperkenalkan untuk menggunakan referensi ke variabel untuk argumen OUT sebelum pointer diperkenalkan kepada saya. Saya ingat bahwa saya melewatkan menulis beberapa contoh pertama dalam C untuk Dummies karena mereka terlalu sederhana hanya untuk tidak pernah mendapatkan program pertama yang saya tulis untuk bekerja (kemungkinan besar karena ini).
Apa yang membingungkan tentang ini adalah apa yang &ch
sebenarnya dimaksudkan dan mengapa str
tidak membutuhkannya.
Setelah saya menjadi terbiasa dengan itu saya selanjutnya ingat menjadi bingung tentang alokasi dinamis. Saya menyadari pada suatu titik bahwa memiliki pointer ke data tidak terlalu berguna tanpa alokasi dinamis dari beberapa jenis, jadi saya menulis sesuatu seperti:
char * x = NULL;
if (y) {
char z[100];
x = z;
}
untuk mencoba mengalokasikan ruang secara dinamis. Itu tidak berhasil. Saya tidak yakin itu akan berhasil, tetapi saya tidak tahu bagaimana lagi cara kerjanya.
Saya kemudian belajar tentang malloc
dan new
, tetapi mereka benar-benar tampak seperti generator memori ajaib bagi saya. Saya tidak tahu bagaimana cara mereka bekerja.
Beberapa waktu kemudian saya diajari rekursi lagi (saya sudah mempelajarinya sendiri sebelumnya, tetapi sekarang di kelas) dan saya bertanya bagaimana cara kerjanya di bawah tenda - di mana variabel-variabel terpisah disimpan. Profesor saya berkata "di tumpukan" dan banyak hal menjadi jelas bagi saya. Saya telah mendengar istilah sebelumnya dan telah mengimplementasikan tumpukan perangkat lunak sebelumnya. Saya telah mendengar orang lain merujuk pada "tumpukan" jauh sebelumnya, tetapi telah melupakannya.
Sekitar waktu ini saya juga menyadari bahwa menggunakan array multidimensi dalam C bisa sangat membingungkan. Saya tahu bagaimana mereka bekerja, tetapi mereka sangat mudah terjerat sehingga saya memutuskan untuk mencoba menggunakannya kapan saja saya bisa. Saya pikir masalah di sini sebagian besar sintaksis (terutama melewati atau mengembalikannya dari fungsi).
Karena saya sedang menulis C ++ untuk sekolah untuk satu atau dua tahun ke depan saya mendapat banyak pengalaman menggunakan pointer untuk struktur data. Di sini saya punya satu set masalah baru - mencampur pointer. Saya akan memiliki beberapa level pointer (hal-hal seperti node ***ptr;
) membuat saya tersandung. Saya akan merujuk pointer berapa kali salah dan akhirnya mencari tahu berapa banyak*
saya butuhkan dengan coba-coba.
Pada titik tertentu saya belajar bagaimana tumpukan program bekerja (semacam, tapi cukup bagus sehingga tidak lagi membuat saya terjaga di malam hari). Saya ingat pernah membaca bahwa jika Anda melihat beberapa byte sebelum pointer yang malloc
pada sistem tertentu kembali, Anda dapat melihat berapa banyak data yang sebenarnya dialokasikan. Saya menyadari bahwa kode ini malloc
dapat meminta lebih banyak memori dari OS dan memori ini bukan bagian dari file yang dapat dieksekusi. Memiliki ide kerja yang layak tentang cara malloc
kerja adalah hal yang sangat berguna.
Segera setelah ini saya mengambil kelas perakitan, yang tidak mengajarkan saya banyak tentang petunjuk seperti kebanyakan programmer mungkin berpikir. Itu membuat saya berpikir lebih banyak tentang perakitan apa kode saya mungkin diterjemahkan ke dalam. Saya selalu mencoba menulis kode yang efisien, tetapi sekarang saya punya ide yang lebih baik.
Saya juga mengambil beberapa kelas di mana saya harus menulis beberapa lisp . Ketika menulis lisp saya tidak begitu peduli dengan efisiensi seperti saya di C. Saya punya sedikit ide tentang kode ini jika diterjemahkan, jika dikompilasi, tetapi saya tahu bahwa sepertinya menggunakan banyak simbol lokal bernama (variabel) yang dibuat banyak hal lebih mudah. Pada titik tertentu saya menulis beberapa kode rotasi pohon AVL dalam sedikit lisp, bahwa saya mengalami kesulitan menulis di C ++ karena masalah pointer. Saya menyadari bahwa keengganan saya untuk apa yang saya pikir kelebihan variabel lokal telah menghambat kemampuan saya untuk menulis itu dan beberapa program lain di C ++.
Saya juga mengikuti kelas kompiler. Sementara di kelas ini saya beralih ke materi lanjutan dan belajar tentang static single assignment (SSA) dan variabel mati, yang tidak begitu penting kecuali bahwa itu mengajari saya bahwa setiap kompiler yang layak akan melakukan pekerjaan yang layak untuk berurusan dengan variabel yang tidak lagi digunakan. Saya sudah tahu bahwa lebih banyak variabel (termasuk pointer) dengan jenis yang benar dan nama baik akan membantu saya menjaga hal-hal tetap di kepala saya, tetapi sekarang saya juga tahu bahwa menghindari mereka karena alasan efisiensi bahkan lebih bodoh daripada profesor berpikiran kurang optimasi mikro saya mengatakan kepada saya.
Jadi bagi saya, mengetahui sedikit tentang tata letak memori suatu program sangat membantu. Memikirkan apa arti kode saya, baik secara simbolis maupun pada perangkat keras, membantu saya keluar. Menggunakan pointer lokal yang memiliki tipe yang benar sangat membantu. Saya sering menulis kode yang terlihat seperti:
int foo(struct frog * f, int x, int y) {
struct leg * g = f->left_leg;
struct toe * t = g->big_toe;
process(t);
sehingga jika saya mengacaukan tipe pointer sangat jelas oleh kesalahan kompiler apa masalahnya. Jika saya melakukannya:
int foo(struct frog * f, int x, int y) {
process(f->left_leg->big_toe);
dan ada jenis pointer yang salah di sana, kesalahan kompiler akan jauh lebih sulit untuk dipecahkan. Saya akan tergoda untuk menggunakan perubahan coba-coba dalam frustrasi saya, dan mungkin membuat segalanya lebih buruk.