Kendi çalışmalarınızda (kendi başınıza veya bir sınıf için) nihayet, gerçekten işaretçileri anladığınız zaman bir "ah ha" anınız oldu mu? Yeni başlayan programcılar için özellikle etkili görünen bir açıklamanız var mı?
Örneğin, yeni başlayanlar C'de işaretçilerle ilk karşılaştıklarında, sadece
&s ve
*s derlenene kadar (kendim bir kez yaptığım gibi). Belki de işaretçileri sizin ya da öğrenciniz için “tık” haline getiren bir resim ya da gerçekten iyi motive olmuş bir örnektir. Bu neydi ve işe yaramıyor gibi görünmeden önce ne denediniz? Herhangi bir konu önkoşulu var mıydı (ör. Yapılar veya diziler)?
Başka bir deyişle,
&s ve
*, bunları ne zaman güvenle kullanabilirsiniz? Sözdizimini ve terminolojiyi veya kullanım örneklerini öğrenmek yeterli değildir, bir noktada fikrin içselleştirilmesi gerekir.
Güncelleme: Şimdiye kadarki cevapları çok seviyorum; lütfen gelmeye devam et. Burada çok büyük perspektifler var, ama birçoğunun kendimiz için iyi açıklamalar/sloganlar olduğunu düşünüyorum after kavramı içselleştirdik. Size şafak vakti geldiğinde ayrıntılı bağlamları ve koşulları arıyorum.
Örneğin:
C'de sadece işaretçileri sözdizimsel olarak anladım. İki arkadaşımın başka bir arkadaşa işaretçileri açıkladığını duydum, bu da neden bir işaretçi ile
structgeçtiğini sordu. İlk arkadaş, nasıl referans alınması ve değiştirilmesi gerektiğinden bahsetti, ancak bana vurduğu diğer arkadaştan kısa bir yorum yapıldı: "Aynı zamanda daha verimli." 16 bayt yerine 4 bayt geçmek, ihtiyacım olan son kavramsal değişiklikti.
Genellikle yaptığım şey, adresleri oluşturabildiğim, farklı bellek boşluklarını vurgulayabildiğim ve hücre değerlerine yazabildiğim (ya da dahası, ikili sunumları) ve bellekteki işaretçileri değerlerine bağlayabilmem için belleği bir "ızgara" olarak temsil etmektir. işaret etmek. (Ve yine de bunun bir basitleştirme olduğunu belirtin).
Genellikle öğrencilerimin çoğu için bir "ohhhh" anıdır.
Daha sonra nasıl kullanılacağını ve & * 'yı unutmayı bırakmalarına gelince, bu çok basit: matematik veya fizik hesaplamaları ile aynı şekilde sunun. Km cinsinden bir mesafeyi saat cinsinden bölerseniz, km/s cinsinden bir hız elde edersiniz. İçinde ne olmalı dışarıda. Basit.
Bunlarla açıkladığınızı görsel olarak temsil eden birkaç temel örnek yapmak onları anladıklarını düşündükleri şeyde rahatlatacak veya "ah, bunu anlamıyorum" deme fırsatı verecektir.
Basit türler için işaretçileri kapsar ve adresleme ile veri türünün boyutu arasındaki farkı, sonra yapıları, sonra dizileri ve birden çok düzeyi anladıklarından emin olun.
Ardından işaretçi aritmetiğini başlatın.
Genellikle özyinelemeyi görsel bir sunum kullanarak benzer şekilde açıklarım. Tek bir karakter yazan önceden hazırlanmış bir işlevi kullanarak alfabeyi yazdırmasını sağlayın ve ardından yalnızca iki satırı değiştirerek ters sırada yazdırmasını isteyin.
Genellikle "ne ...?" ve sayısal değerleri yazdırmak ve adımları girintilemek için printf'nize başka bir parametre eklediğinizde rahat bir nefes alır.
Aslında bir üniversitede bazı öğrencilere play-doh macunu kullanarak işaretçileri ve bellek erişimlerini açıklayan bir video gösterdim. Programlamayı kavramakla ilgilenen çok genç öğrenciler (ama genellikle onları çok erken işaretçiler kullanarak bir dile yönlendirmeyeceğim) dışında, bu tekniği kendim hiç kullanmadım, ancak inanılmaz derecede akıllı ve iyi yapıldı. Temel olarak, bellek alanlarını temsil eden diğer daha büyük play-doh toplarına bağlayabileceğiniz ve bunları (bağlantılı veri yapısında olduğu gibi) bağlamak veya birleştirmek için (bitişik olarak olduğu gibi) birleştirebileceğiniz küçük play-doh topları kullanmak bellek alanı). İşaretlenen bellek alanları için farklı renkler kullanmak ve işaretçiler de yardımcı olur. Ama yine de Grid olarak Bellek olayının daha iyi çalıştığını düşünüyorum, çünkü göstergenin "harita/ızgarada" olduğu gibi gerçekten "adresleme" meselesi olduğunu açıkça gösterebilirsiniz. Oysa Play-doh modu onları hala bir şeylerin gerçekten hafızada birbirine "dokunduğunu" düşünerek karıştırıyor.
Su Bardağı şey doğrudan bir meslektaş tarafından da kullanıldı, ancak onunla gelip gelmediğini bilmiyorum. Bu ilginç bir yaklaşımdı, ancak birçok öğrencinin açıklamadan şaşkın kaldığını gördüm. DevSolo'nun Kahve Fincanı tekniği . Ancak öğrencilerin kapları, veri yapılarını, işaretçileri ve dizileri karıştırmasını sağladığınız için aslında yanıltıcı bir durum olduğunu düşünüyorum. Sanırım başlangıçta dizileri açıklamak ilginç bir yaklaşım olabilir, ama buna çok uzun sürmezdim.
Bir zamanlar söylediğimden daha bilge biri:
Rahibe Wu Jincang, Altıncı Patriach Huineng'e "Uzun yıllardır Mahaparinirvana sutrasını inceledim, ancak tam olarak anlamadığım birçok alan var. Lütfen beni aydınlatın."
Patrik, "Okuma yazma bilmiyorum. Lütfen bana karakterleri okuyun ve belki de anlamını açıklayabileceğim."
Rahibe, "Karakterleri bile tanıyamazsın. O zaman anlamını nasıl anlayabilirsin?" Dedi.
"Gerçeğin kelimelerle ilgisi yoktur. Gerçeğin gökyüzündeki parlak aya benzetilebilir. Kelimeler, bu durumda, bir parmağa benzetilebilir. Parmak ayın konumuna işaret edebilir. Ancak, parmak Aya bakmak için parmağın ötesine bakmak gerekiyor, değil mi? "
Diyagramların çok yardımcı olduğunu gördüm. Misal:
Bu tür bir diyagram, işaretçilerin kendi değişkenleri olduğunu görmeme yardımcı oldu, ancak başka bir nesnenin, yani dizi veya dizenin konumu olan bir değer içeriyordu. Ayrıca, kalemle yapıldığında, programımı kağıt üzerinde veya bir kara tahta/beyaz tahtada izlemek için kullanabilirim.
İşaretçileri ilk kez "öğrendiğimde" ona doğru bir şekilde ittim. Üniversitem, müfredatı Java'nın etrafında ortalamak için kaydolmadan çok önce karar vermişti, bu yüzden Veri Yapıları profesörüm C hakkında bir ders verdiğinde ve bir şeylere giriyormuş gibi hissettiğim işaretçilerle bir XOR Listesi uygulamasını istedi. yol kafamın üstünde.
Tanımı anladım:
İşaretçi, bir değişkenin adresini içeren bir değişkendir
Ama hala kavramın büyük bir bölümünü anlamadım. Geriye dönüp baktığımda, üç şeye odaklandığını düşünüyorum:
Tam olarak is bir bellek yeri nedir? (O zaman bir Bilgisayar Organizasyonu dersi almadım)
Garip sözdizimi (Yani um ... neden tam olarak "int * ip" gibi tanımlanmış ama sonradan "ip" olarak adlandırıyorum?)
Sadece değişkeni kullanmak yerine bir değişkenin adresini saklamak tam olarak ne kadar faydalıdır?
K&R kitabını satın alıp işaretçiler için gerçekten kavradığım her problemi tamamlayana kadar değildi. Bilgisayar Organizasyonu sınıfını uzun süredir tamamlamamın yanı sıra (C öğrenmeden önce gerekli olduğunu düşünüyorum), bir kısmı da işaretçilerin işlevler, diziler, yapılar için kullanılabileceğini fark ettim ... yararlı şeyler yapmak ve sadece sıradan değişkenlerin adresleri için depolama olarak değil.
Ama benim “aha” anım, K&R'nin basit bir işaretçi tanımlamanın garip sözdizimini açıklamasının yoluydu. Kitap boyunca notlar aldım (anladığım kadar ilerlemek için kitabın işaret ettiği noktaları kendi sözlerime yeniden yazdığım) ve bununla ilgili olan şu:
İşaretçi, bir değişkene adres içeren bir değişkendir. Bir işaretçi tanımlanır ve '*' operatörü ile işaret ettiği bellek konumunda depolanan değeri verir; ifade anımsatıcıdır.
Ex.: int a; /* Variable 'a' is an integer */ int *ip; /* Variable ip is a pointer and dereferencing it gives an integer. In other words, the expression *ip is an int, so ip is a pointer to an int */
Kafamda kökleşmiş bir şey olana kadar işaretçilerin daha gelişmiş kavramlarını tam olarak kavrayamadığımı hep hissettim. Bu atamadan sonra (bu arada çok iyi yapmadım;)) neden "* ip" i tanımladığımdan hemen sonra "* ip" bulunmadığı için beni sürekli rahatsız etmişti. Bunun üstesinden gelmek, işlev işaretçileri gibi işaretçileri içeren daha gelişmiş kavramlar ve bunun gibi daha karmaşık tanımlar için gereklidir:
char (*(x())[])()
Sonuç olarak, işaretçiler kavramının şunları gerektirdiğini düşünüyorum:
Bilgisayarda belleğin nasıl düzenlendiğine (ve belleğin ne olduğuna) ilişkin temel bir anlayış.
İşaretçilerin ne kadar güçlü olabileceği hakkında bilgi (gerçek dünya kullanımı, sadece öğrenme uğruna öğrendikleri başka bir soyut kavram değil).
Halk dilinde "bir işaretçinin tanımı" olarak bilinen hiyerogliflerin deşifresinin yapılması
Sonuç olarak, işaretçiler hakkında bilgi edinirken en az 3 "aha" anı olması gerektiğini düşünüyorum. Hâlâ bir öğrenciyim, bu yüzden hala (nispeten) kavramı öğrenen birisinin bakış açısını takdir edeceğinizi düşündüm.
İşaretçi, masaüstünüzdeki uygulama kısayollarına benzer. Kısayolu silin ve hedef hala var. Kısayolu başlatın, hedef başlar.
Her zaman masaüstümde bir txt dosyası ve dosyaya iki kısayol oluşturarak bunun çalışmasını açıklarım. Kısayolları kopyalayıp sildikten sonra, insanların 'referanslar'ın arkasındaki fikri anladıklarını görebilirsiniz.
Grup, kısayolların arkasındaki temel öğeyi anladıktan sonra, istediğiniz şekilde işaretçileri açıklamaya başlayabilirsiniz. Muhtemelen kolayca anlayacaklar.
8-10 yıl önce bir kolejde bir "C" dersi verdim. Bu her zaman keşfedilecek eğlenceli bir konuydu. En iyi işe yarayan şey budur ve bu bir iş arkadaşını birkaç kez tartıştıktan sonra bir kahve fincanı ve elinizi kullanmaktı.
Bir kahve fincanı benzetmesini (veya diziler için bunların sırasını) bir değişken olarak kullandım (bir şey tutabilir). Daha sonra bir şey tutabilen ya da işaret parmağımı bir kahve kupasını "gösterecek" şekilde uzatarak elimi kullandım.
Yakın bir el boştu, kafamı işaret eden bir parmak (sahte bir silah gibi) sarkan bir işaretçiydi.
Sonra birkaç gösteri ve hata ayıklayıcı gezileri ile, çoğu ile tıkladı.
"İşaretçileri nasıl kavradınız" sorusunu duyduğumda gerçekten endişeleniyorum. Her zaman kavramın inanılmaz derecede basit olduğunu ve programcılara büyük güç sağlayan dillerin mantıklı bir evrimi olduğunu düşündüm.
Beni endişelendiren şey işaretçiler kavramını anlamakta hiç zorlanmadığım. Burada tekrar "nihayet ne zaman anladın" diye düşündüğünüzde, düşünmeye başlarsınız:
Aslında anladım mı? Belki hiç yapmadım?
Belki de kavramın zor görünmesinin nedeni, henüz onlarla karşılaşmamış herkese işaretçilerin çok zor olduğunu ve burada öğrenebileceğiniz yüz yol olduğunu söylemeye devam etmemizdir.
Sadece bu fikri dışarı atmak, elbette kişisel olarak iyi bir diyagramı seviyorum ve Steve Gibson her zaman her şeyi açıklamak için harika bir iş çıkarır !
C'deki işaretçilerle hiçbir zaman çok fazla sorun yaşamadım, ancak bunun nedeni öncelikle montajcıyı öğrenmek zorunda olduğumdur. Aslında artık adresleri kendim yönetmemek bir rahatlama oldu. Bu yüzden belki de (bunun öğrettiğiniz bir şey olduğunu varsayarak) cevabı öğrencilere çalışmak için taklit edilmiş bir Meclis dili vermektir. Onlar will "Merhaba dünya" dan daha sofistike bir şey yazma sürecinde anlıyorlar.
İşaretçi, değeri başka bir değişkenin bellek adresi olan bir değişkendir.
İşaretçileri gerçekten nasıl öğrendim? Basit bir derleyici birinci sınıf yazarak üniversite yıl.
İşaretçileri layman terimleriyle nasıl açıklayabilirim? Dizin kartlarında saklanan bir kütüphane kataloğunun (tarihli?) Benzetmesini seviyorum. Her kart ("işaretçi") bir kitabın ("veri") bulunduğu yerle ilgili bilgiler içerir, ancak aslında kitabın kendisini içermez. Kartı değiştirirseniz ("işaretçi aritmetiği") tek yaptığı, işaret ettiği kitabı değiştirmek ve kitabın kendisi üzerinde hiçbir etkisi yoktur - sadece adresi bozmamaya dikkat edin, yoksa var olmayan bir kitaba işaret edebilirsiniz. hatta yanlış kütüphaneyi bile. Ancak, karttaki "adresi" takip edip kitaplığın uygun kısmına giderseniz ("işaretçiyi serbest bırak"), kitabın kendisini görebilir/değiştirebilirsiniz.
Sorunun gözden geçirilmiş gereksinimini desteklemek için düzenlendi
"Post-pointer" anlayış yolum (doğru hatırlıyorsam) böyle gitti. Ben hala bir BBC Micro ile mucking beri montaj programlama bazı basit bir deneyim oldu bu yüzden bir grup kutu olarak bellek kavramı vardı (bunun için aşağıya bakınız). Bu, dizilerin kullanımı ile güçlendirildi. Ancak, C dünyasına giriyordum ve iplerle uğraşmak zorunda kaldım ve bu işaretçiler anlamına geliyordu. BASIC'te bu önemsizdi, montajcıda onlarla çalışmak zorunda kalmadım ve şimdi klasik C'de tüm işaretçiler ve şeyler. Ah, ama şu şekilde (boş sonlandırılmış) dizelerle dizilere geri dönebilirim:
char s[] = "Hello, world!"; printf("%s",s);
Her şey yolunda ve iyi, bu sadece bir dizi karakter (benim küçük dünyamda karakter başına 8 bit) sonunda nerede olduğunu göstermek için sıfır karakterle. Printf sadece bu diziyi alır ve üzerine basar. Ama bu dizeyi bir işleve geçirmek istersem ne olur?
void print_str(char* p) { printf("%s",p); }
Kılavuz ne diyor, ama hepsi ne * ile ilgili? Hmm, char * "bir char işaretçisi" anlamına gelir. Tamam ... beni kaybetti. Sonra karakter * s'yi p [0] 'a eşdeğer hale getirdi. Tamam, bunu kullanabilirim, ama hala işaretçilerin ne olduğunu dalmadım. Yani, bunlardan biriyle bazı verileri nasıl ayarlayabilirim? Tekrar el kitabına ...
char* p = "Hello World!";
Yukarıdakileri yazarken kendime "karaktere bir işaretçi bildirin ve bu karakter dizisine eşit olarak ayarlayın" diyorum. Her nasılsa bu işaretçi bir dizi ihtiyacını ortadan kaldırır. Sanırım derleyici bir değişiklik için benim için bir şeyler yapıyor. Peki bu işaretçiyle diziyi nasıl değiştirebilirim? Dizi sürümünü kullanabileceğimi biliyorum
s[2] = 'L';
ama "pointer speak" den eşdeğer nedir? Yine bu el kitabında ...
*(p+2) = 'L';
Sanırım * basitçe "bellek adresinin içeriği" ve
(p+2) dır-dir
s[2]. Yani p işaretçisi ... sadece ... bir ... adres ... bong!
Aydınlanma sesi var. Aniden işaretçiler dalladım (uzun zaman önceydi, biz eski zamanlayıcılar daha sonraya kadar "grok" olmadı). Sadece dolaylıydı.
Orijinal:
Tamam, benim 2c değer:
Hafızanın bir grup kutu olduğunu hayal edin. Her kutunun yanında bir numara vardır (adres). Her kutuda bir sayı (içerik) bulunur. Bu kutularla 2 şekilde çalışabilirsiniz: Değişkenler (N kutusunun içeriğini istiyorum), işaretçiler (N (kutusundaki) kutusunun içeriğini istiyorum ). İşaretçiler basitçe dolaylıdır.
Ve bilmeniz gereken her şeyi kapsayan büyük cevap için - bunu okuyun .
İşaretçilerin öğreneceği birisinin normal değişkenlerin ne olduğunu ve C'de nasıl çalıştığını bildiğini varsayacağım. Şimdi, bazı nitelikleri olan işaretçileri tanımlamaya çalışalım.
Aynı zamanda değişkenlerdir, fakat farklı niteliktedirler. Değişken alanında iki katman olduğunu varsayın. Farklı tipteki normal değişkenler üst tabakada ve alt tabakadaki işaretçilerdedir. Bu rakam gibi
'İşaretçi' adından da anlaşılacağı gibi, işaretçiler bir şeye POINT olabilir. Parmağımızın bir nesneye işaret edebileceği gibi. İşaret ettikleri şeyler neler? Bunlar normal değişkenlerdir. Kısacası, "İşaretçiler normal değişkenleri gösterir".
Peki, bir işaretçi nasıl ilan edilir? Neredeyse normal değişkenler gibi. Addan önce yıldız işareti (
*). Sevmek-
int *pointer;
Peki, bir işaretçi bir değişkenle nasıl ilişkilendirilir? Kullanmak
& operatörü bu ifadeye benzer değişkenden önce-
pointer = &variable;
Bir değişkene işaret ederek işaretçi nasıl kullanılır? Bu, adın önünde yıldız işareti (
*). Sonra şimdi işaret ettiği değişkenin yerine kullanılabilir.
*pointer = var1 + var2;
onun yerine
variable = var1 + var2;
Şimdi, bazı kodlarla işaretçilerle oynayın. Şimdi sadece işaretçilerin bu özelliklerine alışın. Bu noktaya kadar, işaretçilerin ne yaptığından bahsediyoruz. Bir kez bunu yaptıktan sonra, işaretçilerin bazı değişkenlere nasıl işaret ettiğini ve normal aritmetik işlemler uygulanırsa nasıl tepki verdiklerini incelemeye başlayın. Sonra işaretçiler ve diziler ve işaretçilerden işaretçiler arasındaki ilişkiyi araştırın.
İşaretçiler hakkında önereceğim tek şey bu.
Küçük tahta bloklar al.
bir ucuna metal kancalar, diğer ucuna metal gözler ekleyin.
artık oynayabileceğiniz şeyler için bağlantılı bir liste yapabilirsiniz.
Bu fiziksel pervane ile açıklamayı deneyin. Sık sık birinci sınıf öğrencilerine işaretçiler öğretirken bunu olmasını isterdim.
Küçük metal kanca işaretçi, şeyin işaret ettiği tahta bloğudur.
Ben bloklarla oynadıktan sonra almak için kimse DEFY.
Tüm tüyleri çıkardığımda ve işaretçiyi büyülü bir varlıktan (11 yıl önce uzun zaman önce) başka bir değişken olarak ele almaya başladığımda hayatımı kolaylaştırdım .. sadece 3 şeyi biliyorum:
Gerisi sözdizimsel şeker ve sağduyu. Sadece asmak için işaretçiler kullanarak bazı basit C programları (bağlantılı bir liste kitaplığı uygulamak gibi) yazın.
Gerçekten yığılmış açıklama oldu:
Arazi parçaları üzerine inşa edilmiş farklı evleri olan bir şehir ızgarasını düşünün. Elinde bir parça kağıt var. Yazdığınız kağıt üzerinde:
David'in evi,
112 Yani sokak.
Kağıt parçası (pointer değişkeni) David'in evine puan adresini içerir. Bir arkadaşınıza David'in havalı evine bakmasını söylemek istediğinizde, kağıt pice'i eve referans olarak kullanmak, postadaki gerçek iki katlı binayı göndermekten çok daha kolaydır.
Gerçek işaretçilerde olduğu gibi, kağıt parçanızdaki adresi takip ettiğinizde biraz sorun yaşayabilirsiniz. David taşınmış olabilir ve oraya vardığınızda yerde büyük bir delik bulursunuz. Bu durumda, David taşındığında veya en azından yenisiyle değiştirdiğinde kağıt üzerindeki adresi silmek daha iyi olurdu. Ayrıca adrese gidip arkadaşınızın David'in oturma odası olduğunu düşündüğünüzü girdiğinizi de görebilirsiniz, ancak bu sefer tam bir yabancı yüzme havuzuna girersiniz. Başka biri, adresinizdeki alanı tamamen farklı bir şey için kullandı.
Eğer işaretçileri açıklamak istiyorsanız, önce hafızayı açıklamanız gerekir. Bunu genellikle satır ve sütun içeren grafik kağıdı/kare kağıt kullanarak yaparım. "Öğrenci" hafızayı anlarsa, bir adresin ne olduğunu anlayabilir. Eğer adresin varsa işaretçiler var.
Bu soyutlama ile oynayabilirsiniz. Örneğin. bir karenin adresini (numarasını) başka bir kareye yazın. Şimdi işaretçi karesinden hedef kareye bir ok çizin. Şimdi işaretçiyi üzerine yazın (örn. Artırın) ve oku ayarlayın. Başka bir kareye bir adres yazın ve öğrencinin oku çizmesine izin verin ...
Sonraki adım: Belirli karelere (işaretçi gibi) bir ad verin. Şimdi kayıt silme işlemini açıklayabilirsiniz. Bu kadar.
İşaretçilerim-aha-anımın etrafındaki koşulları tam olarak hatırlayamıyorum, ancak c-tarzı bir dizi hakkındaki anlayışımdaki belleği geriye dönük olarak yeniden ekledim. (yani
arr[3]
*(arr+3) ile aynıdır)
Bazı nedenlerden dolayı, işaretçi durumuna geldiğimde işaretçileri diziler olarak görmek son derece yararlı buluyorum.
Temelde @Gary Rowe doğru modeli tanıttı. Bellek, adresleri (sayıları) olan bir kutu kümesi olarak. Her kutu bir değer (sayı) depolar.
İşaretçi fikri, bir kutudaki değeri başka bir kutunun adresi olarak yorumlamaktır. Bu değer başvur için belirli bir kutuya kullanılır, bu nedenle başvur olarak adlandırılır. Böylece dereferencing atıfta bulunulan kutuyu açma işlemidir.
v bir değişken (kutu) ise, ifade
v
vdeğeri anlamına gelir, yani bana kutuda ne olduğunu ver
*v,
vdeğerinin dereference'ı ifade eder, yani bana
vdeğerinin atıfta bulunduğu kutuda ne olduğunu ver
&vreferans
vanlamına gelir, yani bana kutudaki adresi ver
Ben tamamen farklı bir şey işaretçiler tanıtmak amacı sunucu olmadığını düşünüyorum. Çocukken kavramak benim için zor bir kavramdı. Her zaman hiç anlamadığım, çok fazla özel karakter gerektiren karanlık bir sihir gibi görünüyordu. İlk anladığımda, işaretçi aritmetiği olmayan bir dilde çift dolaylı kullanarak küçük bir oyun yazdığım zamandı. Bu beni aydınlattı.
İşaretçiler bir yorum meselesidir. Bence bunu açıklamak işleri kolaylaştırıyor. İşaretçi aritmetikleri, 10 değişkenlik bir belleğe sahip basit bir örnek gösterildiğinde son derece basit ve sezgisel işlemlerdir.
Belki de sadece benim, ama benzetmelerle iyi çalışıyorum. Diyelim ki bir arkadaşınız (işlev/sınıf) "Foo", başka birisine (farklı işlev/sınıf), "Bar" a sahip olmak isteyen bir sebepten dolayı sizinle iletişime geçin. "Foo" sizi "Bar" ı görmeye götürebilir, ama bu uygun değil, bütün bu varlıkları (örnekleri) hareket ettiriyor. Ancak, "Foo" telefon numaranızı (işaretçi) "Bar" gönderebilir. Bu şekilde, nerede olursanız olun, "Foo" sizi bulmak zorunda kalmadan sizinle nasıl iletişim kuracağını bilir.
Ve diyelim ki "Bar" sizinle tanışmak isteyen bir "Tan" tanıştı. Ancak telefon numaranızı koruyorsunuz ve herkesin sahip olmasını istemiyorsunuz, "Baz" daha sonra çağrıyı size iletebilen (başka bir işaretçi) "Bar" ı (işaretçi olarak telefon) arayabilir. Ve böylece ve benzeri "Baz" ın arkadaş ve arkadaşlarının zinciri.
Montaj dili ve/veya bilgisayar mimarisini incelediyseniz işaretçiler yol daha anlamlı olur. Bir C sınıfı öğretirsem, bellek modelini ve işlemcinin gerçekte yürüttüğü talimatları açıklamak için birkaç hafta mimariyle başlayacağımı düşünüyorum.
Benim "aha!" an bu öğreticide geldi:
Kesin olmak gerekirse, bu bölümde geldi: Bölüm 3: İşaretçiler ve Dizeler
Daha kesin olmak gerekirse, bu cümle ile geldi:
Puts () öğesine iletilen parametre bir işaretçidir, bir işaretçinin değeridir (C'deki tüm parametreler değere göre geçtiği için) ve işaretçinin değeri işaret ettiği adres veya basitçe bir adresdir .
Bunu okuduğumda, bulutlar ayrıldı ve melekler trompet hayranlarını havaya uçurdu.
Gördüğünüz gibi, bundan önce okuduğum her C öğreticisi veya kitabı, C'nin değere veya referansa göre hain bir yalandan geçebileceğini iddia etmişti. Gerçek şu ki, C her zaman değere göre geçer, ancak bazen iletilen değer bir adres olur. Yöntem içinde, bu adresin bir kopyası, tıpkı aktarılan bir int'in kopyası gibi yapılır. Bir kopyası değil işaretçinin işaret ettiği değer. Böylece yöntemin içindeki işaretçiyi kullanarak orijinal değere erişebilir ve değeri değiştirebilirsiniz.
Asla bir C programcısı olmadım, ancak bir .NET programcısı oldum ve nesneler ve nesne başvuruları aynı şekilde çalışıyor; nesneye yapılan başvuru değere göre iletilir (ve böylece kopyalanır), ancak nesnenin kendisi kopyalanmaz. Bunu anlamayan birçok programcı üzerinde çalıştım çünkü daha önce işaretçiler öğrenmediler.
İşaretçi, yararlı bir şeyin nerede olduğunu söyleyen yapışkan bir nottur. Bir şeyin yerini içerir ve size o şeyin ne kadar büyük olduğunu söyler (yine de C cinsinden). Yani çift işaretçi, "Buzdolabında altı paket var" yazan yapışkan bir not gibidir. Aslında Coke veya Budweiser olup olmadığını anlamak için altı paketi almalısınız.
Bu site, işaretçiler ve bellek yönetimi öğrenmek için harika eğiticilere sahiptir.
Size sitede verilen işaretçiler temelleri, işaretçiler ve bellek üzerinden yürümek öneririz. İşaretçi kavramlarını daha da güçlendirmek için bağlantıda verilen bağlantılı listelere de bakabilirsiniz.
Kod verildiğinde:
int v=42; // basit bir değişkeni bildirme ve başlatma
int *p = &v; // v değişkenine p noktası oluşturma
Yukarıdaki kod hakkında aşağıdaki söylenebilir:
int * p // "int işaretçi p" ... int türündeki değişkene bir işaretçi bu şekilde bildirilir
*p // "p ile işaret edildi" ... p'nin işaret ettiği veri, v ile aynı.
&v // "v değişkeninin adresi" ... bu, p için değişmez değeri temsil eder
İşaretçileri açıklamanın anahtarı, açıkladığınız insanların zaten bellek kavramını anladığından emin olmaktır. Gerçekten düşük seviyeyi anlamışlarsa güzel olurken, belleğin büyük bir dizi olarak var olduğuna inanıyor ve dizideki herhangi bir konuma dizin konumuna göre erişebileceğinizi anlamak yeterli.
Bir sonraki adım, tüm belleği kopyalamak yerine indeks konumunu geçirme kavramına sahip olmak çoğu insan için mantıklıdır. Ve bu, çoğu insanın işaretçilerin neden faydalı olduğunu anlamasına izin vermek için yeterlidir.
işaretçileri anlamanın son adımı, tüm verilerin depolandığı dizin konumunu saklama yöntemi için bir bellek dizini konumunu parametre olarak nasıl aktarabileceğinizi açıklamaktır. Bunun bazı insanların başa çıkması için çok ileri bir adım olabileceğini buldum.
Birisi bu temel adımları kavradığında, gerçek veri nesnesini bulmak için adreslere kaç kez bakmanız gerektiğini takip ettiğiniz sürece, işaretçileri süresiz olarak zincirleyebildiğinizi kavramak için düz ileridir.
Birisi işaretçileri kavradığında, hızlı bir şekilde kavramaları gereken bir sonraki şey, yığın belleği ve yığın belleği arasındaki fark ve yöntemin dışına iletildiğinde belleği biriktirmek için neden tehlikeli olduğudur.
İşin püf noktası, bir şeyin yeri ve şeyin kendisinin aynı olmadığını, tıpkı bir borunun resmi gibi bir boru değildir olduğunu açıklamaktır. Bir şeyi taşıdığınızda, konumu değişir. Konumu kalır ve başka bir şey oraya konabilir.
Dizileri en azından yüzeysel bir düzeyde zaten bildiğinizi varsayarsak, işaretçiler için en iyi açıklamam şudur:
Bilgisayarınızdaki tüm belleği (veya daha kesin olmasını istiyorsanız işleminizdeki adres alanını) dev bir bayt dizisi olarak hayal edin. İşaretçi bu dizinin yalnızca bir dizinidir. Bu nedenle işaretçiler sadece özel bir tamsayıdır.
C ve Assembly kodlayıcılarının işaretçileri tamsayı olarak ele alarak yapabileceği tüm püf noktaları ve ayrımın sadece Meclis dil düzeyinde nasıl bir kongre olduğunu öğrenmek, bu anlayışın benim için sağlamlaşmasına yardımcı oldu.
Üniversitedeyken profesörüm, bir noktayı kendi başına ayrı bir değişken olarak gösteren bir bellek konumuna (bir dizi olarak temsil edilir) bir okla (gerçekten bir dizi gibi temsil edilir) tasvir eden gerçekten düzgün PowerPoint slaytları vardı ve Bağlantılı Listeler yaparken, adım adım, ok değiştiğinde, işaretçi kayıttan kaldırıldığında vb ..., bir kaç dakika içinde anlayamadığımız bir yol yoktu. Kavramın kendisi gerçekten kolaydır, ancak doğru yapmak veya pratik programlarda uygulamak daha fazla uygulama gerektirir.
Bunu yapmadan önce, programlamada "her şeyin bellek kullanır" ve bellekte (statik) değişken tahsisini açıklarım. Ayrıca bir bellek adresinin ne olduğunu ve bellek alanı, bellek adresi ve değişkenler arasındaki ilişkiyi açıklayacağım.
Son olarak, tamsayı veri türü ve değişkenleri, dize veri türü ve değişkenleri olduğunu açıklarım ... vb. boş olarak adlandırılır.
Ve son olarak, işaretçilerin kullanımı yoluyla dinamik olarak tahsis edilen değişkenler.
Tamamen kütüphanede bulunan birkaç programlama/bilgisayarla ilgili kitaptan biri olduğu için okuduğum "C yapbozları" veya benzeri bir kitabı hatırlıyorum, C anlayışım ilkeldi. Size bir C ekspresyonu attı ve gittikçe daha karmaşık hale gelmesini istedi.