C ve C ++ 'nın öğrendiğim ilk programlama dilleri olduğunu söyleyerek başlamalıyım. C ile başladım, sonra okulda C ++ yaptım ve sonra akıcı olmak için C'ye geri döndüm.
C öğrenirken işaretçiler hakkında beni şaşırtan ilk şey basitti:
char ch;
char str[100];
scanf("%c %s", &ch, str);
Bu karışıklık çoğunlukla, işaretçiler bana düzgün bir şekilde tanıtılmadan önce OUT bağımsız değişkenleri için bir değişkene başvuru kullanılarak tanıtılmasından kaynaklanıyordu. Dummies için C'deki ilk birkaç örneği yazdığımın atlandığını hatırlıyorum çünkü sadece yazdığım ilk programı asla işe yaramayacak kadar basitti (büyük olasılıkla bu nedenle).
Bu konuda kafa karıştırıcı olan şey, &ch
aslında ne demek olduğu gibistr
ihtiyaç duyulmadığıydı.
Bunu öğrendikten sonra, dinamik ayırma konusunda kafanız karıştığını hatırlıyorum. Bir noktada verilere işaret eden bir tür dinamik ayırma olmadan son derece yararlı olmadığını fark ettim, bu yüzden şöyle bir şey yazdım:
char * x = NULL;
if (y) {
char z[100];
x = z;
}
dinamik olarak yer ayırmaya çalışmak. İşe yaramadı. İşe yarayacağından emin değildim, ama başka nasıl çalışabileceğini bilmiyordum.
Daha sonra öğrendim malloc
ve new
gerçekten büyülü hafıza jeneratörleri gibi görünüyordu. Nasıl çalışacakları hakkında hiçbir şey bilmiyordum.
Bir süre sonra tekrar tekrar öğretiliyordum (daha önce kendi başıma öğrenmiştim, ama şimdi sınıftaydım) ve kaputun altında nasıl çalıştığını sordum - ayrı değişkenler nerede saklandı. Profesörüm "yığın üzerinde" dedi ve bana birçok şey netleşti. Bu terimi daha önce duymuştum ve daha önce yazılım yığınları uygulamıştım. Başkalarının çok önce "yığın" a başvurduklarını duymuştum, ama unutmuştum.
Bu süre zarfında, C'de çok boyutlu diziler kullanmanın çok kafa karıştırıcı olabileceğini de fark ettim. Nasıl çalıştıklarını biliyordum, ama karışmak o kadar kolaydı ki yapabildiğim her zaman onları kullanmaya çalıştım. Buradaki konunun çoğunlukla sözdizimsel olduğunu düşünüyorum (özellikle bunları işlevlerden geçirme veya işlevlerden döndürme).
Önümüzdeki yıl veya iki yıl için okul için C ++ yazdığımdan beri veri yapıları için işaretçiler kullanma konusunda çok fazla deneyimim oldu. Burada yeni bir sorunum vardı - işaretçileri karıştırmak. Ben işaretçiler (şeyler gibi node ***ptr;
) birden fazla düzeyde bana gezi olurdu . Bir işaretçiyi yanlış sayıda dereference ve sonunda *
deneme yanılma yoluyla kaç tane gerekli bulmak için başvurmak .
Bir noktada bir programın yığınının nasıl çalıştığını öğrendim (bir çeşit, ama artık geceleri beni tutmayacak kadar iyi). malloc
Belli bir sistemde dönen işaretçiden önce birkaç bayt bakarsanız , ne kadar verinin tahsis edildiğini görebileceğinizi hatırlıyorum . Kodun malloc
işletim sisteminden daha fazla bellek isteyebileceğini fark ettim ve bu bellek çalıştırılabilir dosyalarımın bir parçası değildi. Nasıl malloc
çalıştığı konusunda iyi bir çalışma fikrine sahip olmak gerçekten yararlıdır.
Bundan kısa bir süre sonra, çoğu programcının muhtemelen düşündüğü kadar bana işaretçiler hakkında bilgi vermeyen bir montaj dersi aldım. Kodumun hangi meclise çevrilebileceği hakkında daha fazla düşünmemi sağladı. Her zaman verimli kod yazmaya çalışmıştım, ama şimdi nasıl yapılacağı konusunda daha iyi bir fikrim vardı.
Ayrıca biraz lisp yazmak zorunda kaldığım birkaç ders aldım . Lisp yazarken ben C olduğu gibi verimlilik ile ilgili değildi ben derlenmiş ise bu kod ne dönüştürülebilir çok az bir fikrim vardı, ama yapılan yerel adlandırılmış semboller (değişkenler) bir sürü kullanarak gibi görünüyordu biliyordum işler çok daha kolay. Bir noktada işaretçi sorunları nedeniyle C ++ ile yazmakta çok zorlandığımı biraz lisp içinde bazı AVL ağacı döndürme kodu yazdım. Yerel değişkenlerin fazlalığı olduğunu düşündüğüm şeyden kaçınmamın, bunu ve C ++ 'daki diğer birçok programı yazmamı engellediğini fark ettim.
Ayrıca derleyici dersi aldım. Bu sınıfta ileri materyale gelip statik tekli atama (SSA) ve ölü değişkenler hakkında bilgi edindim, bu da önemli değil, herhangi bir derleyicinin değişkenlerle uğraşmak için iyi bir iş yapacağını öğretmesi önemli değil. artık kullanılmıyor. Doğru türlere ve iyi isimlere sahip daha fazla değişkenin (işaretçiler dahil), işleri kafamda düz tutmama yardımcı olacağını zaten biliyordum, ancak şimdi verimlilik nedenleriyle bunlardan kaçınmanın daha az mikro optimizasyon fikirli profesörlerimden daha aptal olduğunu biliyordum. ben mi.
Bu yüzden benim için, bir programın bellek düzeni hakkında iyi bir şey bilmek çok yardımcı oldu. Kodumun hem sembolik olarak hem de donanımda ne anlama geldiğini düşünmek bana yardımcı oluyor. Doğru türde yerel işaretçiler kullanmak çok yardımcı olur. Sıklıkla benzeyen bir kod yazıyorum:
int foo(struct frog * f, int x, int y) {
struct leg * g = f->left_leg;
struct toe * t = g->big_toe;
process(t);
bir işaretçi türünü berbat edersem derleyici hatasıyla sorunun ne olduğu çok açık olur. Yapsaydım:
int foo(struct frog * f, int x, int y) {
process(f->left_leg->big_toe);
ve orada herhangi bir işaretçi türü yanlış var, derleyici hatası bulmak çok daha zor olurdu. Hayal kırıklığımdaki deneme yanılma değişikliklerine başvurmak ve muhtemelen işleri daha da kötüleştirmek cazip olurdu.