Merhaba, tekrar hoş geldiniz.
Bu derste, işaretçilerin kullanım alanlarından bahsetmek istiyorum,
onları ne zaman kullanacağız, nasıl kullanacağız, onları nasıl oluşturacağımızı biliyoruz.
onları ilan edin ve tanımlayın.
Adres operatörünü kullanarak mevcut bir değişkenin adresini onlara nasıl atayacağımızı biliyoruz.
Ve bunları nasıl referans dışı bırakacağımızı, işaretçinin
işaret ettiği değeri nasıl elde edeceğimizi biliyoruz.
Şimdi bunları gerçekten nasıl kullanmaya başlayacağız.
Yani c, işaretçiler üzerinde gerçekleştirebileceğiniz bazı temel işlemler sunar.
Daha önce öğrendiğimiz bir işaretçiye
bir adres atayabilirsiniz.
Bu, değişkenin bir adrese sahip olduğu mevcut bir değişkendir.
Ve sadece adres operatörünü kullanarak bu değişkenin adresine bakarsınız
ve buna bir noktamız olur. Mevcut bir işaretçiyi başka bir işaretçiye de atayabiliriz.
Bir işaretçiye adres atamanın 2 yolu vardır.
Yani tek başına bir dizi adı olabilir.
Henüz dizilerden bahsetmedik, ancak bir işaretçiye bir yükseltme atadığınızda
yapmanız gereken tek şey adı belirtmektir. Operatörün adresini kullanmak zorunda bile değilsiniz.
Şimdiye kadar sadece mevcut bir değişkeni kullanmaya ve değişkenin
adresini iletmeye odaklandık.
Ancak bunu yapabileceğiniz 3 yoldan bahsediliyor.
Bir işaretçinin referansını da kaldırabilirsiniz. Bunu daha yeni öğrendik, yıldız işaretini dolaylama operatörü
olarak kullanıyorsunuz.
Bu size işaretçide depolanan değeri verecektir. İşaretçi, işaretçinin değeri,
yani işaretçinin gösterdiği adres, sadece
bunu kullanın. Ayrıca bir işaretçi adresi de alabilirsiniz.
Bu, işaretçiyi oluşturduğunuzda işaretçinin kendisinin
saklandığı gerçek adresidir.
Bu işaretçi üzerinde adres operatörünü de kullanabilirsiniz.
Ayrıca işaretçi aritmetiği de gerçekleştirebilirsiniz. Bu konuda ayrı bir dersimiz olacak.
Burada artı ve eksi operatörlerini kullanarak bir işaretçiye
tamsayı ekleyebilir ya da bir işaretçiden tamsayı çıkarabilirsiniz.
Bu da özel gösterimlere sahip olmanızı ve özellikle diziler
kullanıyorsanız bellekte daha hızlı gezinmenizi sağlar.
Genelde yaptığınız şey, artı operatörünü kullanarak bir
işaretçiye bir tamsayı eklediğinizde,
bu işaretçinin adresini
şu kadar bayt yukarı ayarlamaktır.
Bir işaretçiden bir
sayı çıkarırsanız, bu adresi belirli
sayıda bayt eksi olarak ayarlayacaktır.
Ayrıca bir azaltarak artırabilirsiniz ve dizilerde
kullandığımızda bunun çok yaygın olduğunu göreceksiniz.
Yani bir dizinin içindeyken bir sonraki elemana geçmek istediğinizde indeksi kullanmak yerine bir
işaretçi kullanabilir ve onu bir artırabilirsiniz.
İndeks kullanmak yerine bir önceki elemana geçmek istiyorsanız,
indeksi bir azaltabilirsiniz.
Yani işaretçi aritmetiği, sadece işaretçilerden bahsedeceğiz, ancak
bu işaretçilerle yapabileceğiniz bir şeydir.
Ve yine, bellekte hızlı hareket etmenizi, daha verimli
olmanızı sağlayan özel bir notasyondur.
Ayrıca 2 pointer arasındaki farkı da bulabilirsiniz.
Yani 2 işaretçiniz varsa ve elemanlar aynı dizideyse, belki de birbirlerinden ne
kadar uzak olduklarını bulmak isteyebilirsiniz,
elemanlar, onları eksiltebilirsiniz.
Bu, 2 sayılık
atış ile. Yani eğer dizin 5 ise ve dizin 5'te bir işaretçi
noktanız varsa, dizin 15'e işaret eden başka bir işaretçi noktanız varsa,
bunları çıkarabilirsiniz ve bu size kaç
eleman uzakta olduklarını
verir, çünkü onaltılık adres eksi diğer onaltılık adres olacaktır, dizinin
sürekli bellekte olduğunu varsayarsak, ne kadar
uzakta olduklarını gösterecektir.
İlişkisel operatörleri 2 işaretçinin değerlerini karşılaştırmak için kullanabilirsiniz.
İşaretçiler aynı tipte olmalıdır. Yani her ikisi de tamsayıları gösteriyorsa, her ikisinin de
aynı türde olması gerekir.
Bu sadece adreslerin büyük ya da küçük olup olmadığını söyleyecektir.
Yine, dizinin hangi bölümünde olduğunuzu belirleyebilirsiniz.
Ayrıca 2 çeşit çıkarma işlemi vardır.
Az önce bir işaretçiyi alıp başka bir
işaretçiden çıkarabileceğiniz ve bir işaretçi elde edeceğiniz çıkarma
işleminden bahsettim
ya da bir işaretçiyi bir tamsayıdan çıkarabilirsiniz,
bu da size bir işaretçi verecektir.
Yani bir tamsayı elde etmek için bir işaretçiyi diğerinden çıkarın veya bir
işaretçi elde etmek için bir işaretçiden bir tamsayı çıkarın. Bunlar iki vaka.
Bu yüzden aklımızda tutarak birkaç örnek daha inceleyeceğiz.
İşaretçilerin artırılması veya azaltılmasını kullanırken ve dizinin sınırların dışına
çıkmasına neden olurken dikkatli olun. İşaretçi aritmetiği ile yaptığınız bu işlemlerin
çoğu diziler üzerinde çalışırken gerçekleşir.
Çünkü yine, hızlı hareket etmenizi sağlar, basit bir sözdizimidir.
Ancak dizilerde sınır dışı hatası olduğunu unutmayın.
Yani çok fazla artırırsanız, dizide sınırların
dışına çıkarsınız. Çok fazla azaltırsanız, sınırların
altında kalırsınız, negatif bir sayıya gidersiniz.
Bilgisayarın kendisi bir işaretçinin hala bir dizi elemanını gösterip göstermediğini takip etmeyecektir.
Bu yüzden diziler üzerinde aritmetik noktasını kullanırken dikkatli olmalısınız.
İfadelerde kullanılan işaretçileri istiyorsanız, bunu da yapabilirsiniz.
Bundan biraz önce bahsetmiştik ve işaretçinin referansını kaldırdık ve ona
15 ekledik. Sanırım 20 tane var.
Böylece pi işaretçisinin değeri aritmetik ifadelerde kullanılabilir.
Dolayısıyla, bir değişken tamsayıya işaretçi tipinde tanımlanmışsa, tamsayı
aritmetiği kuralları kullanılarak değerlendirilir.
Ve bunu dereferans ile gösterdik. Yani bir değişkeniniz ve
bir işaretçiniz varsa, bunu null olarak başlatın, ardından işaretçinizi değişkenin
adresi olarak işaretleyin. O zaman sadece yıldız sayısı artı 25'e eşittir diyebilirsiniz.
Star pnumber'ın işaret ettiği değeri aldığını unutmayın.
Yani bunun yaptığı şey, pnumber değerinin pnumber artı 25
değerine eşit olduğunu söylemektir.
Yani değer 35'e eşit olacaktır.
Bu, işaret ettiği şeyi değiştirmiyor çünkü asterisk kullanıyoruz, bu yüzden işaret ettiğimiz
adresi değiştirmiyor, adresin kendisini değiştirmiyor
çünkü operatörün adresine sahip değiliz.
İşaret ettiği değeri değiştiriyoruz.
Bu nedenle, sayı değişkeninin değerini 25 artırarak, yıldız, pnumber adlı
değişkenin işaret ettiği içeriği sorduğunuzu gösterir.
Bir işaretçi x değişkenine işaret ediyorsa, bu işaretçi
x ile aynı veri türüne bir işaretçi olarak tanımlanmıştır.
Dolayısıyla, bir float işaretçisi oluşturduğunuzda, hangisini
bildirdiğinize bağlı olarak yalnızca
float veya int olan bir veri türünün adresine sahip olabilirsiniz.
Dolayısıyla, bir ifadede dolaylama işlecinin
kullanımı, aynı ifadede x'in kullanımıyla aynıdır.
Söylediği tek şey, bir float veya int kullanıyorsanız ve dolaylama operatörünü
kullanırsanız, onu dereference edersiniz, içinde bir float olsaydı
ne yapabiliyorsanız onu yapabilirsiniz, neyi işaret ediyorsa.
Bir int türüne işaretçi olarak tanımlanan bir değişken, in türündeki herhangi bir
değişkenin adresini saklayabilir, bunu biliyoruz.
Yani burada int değeri 999'a eşittir, pnumber bir int'e işaretçi olduğu
sürece bu int'i pnumber'a atayabiliriz ve sonra ona ekleme
yapabiliriz.
Deyim yeni değişken değeriyle çalışacak
ve yeni içerik değeri 1024 olacaktır.
Pnumber, değerin adresi olan
value'ya işaret eder. Dolayısıyla, işaretçinin işaret ettiği değeri
değiştirirseniz, bu değişken değerinin değerini de değiştirmiş olursunuz.
Bu nedenle, bunun işaretçinin bir noktasındaki bir değişkeni değiştirme kavramı olduğunu
ve bunu birden fazla değişkende değiştirdiğinizi unutmayın.
Bir işaretçi, uygun tipteki herhangi bir değişkenin adresini içerebilir.
Böylece, ints, doubles veya floats varsa, birçok farklı değişkenin değerlerini değiştirmek için
bir işaretçi değişken kullanabilirsiniz. İşaretçi tipiyle uyumlu tipte oldukları sürece,
bu değeri değiştirebilirsiniz. pnumber bir float'a işaret ediyorsa
ve değer bir tamsayı ise pnumbers değerini değiştiremezsiniz.
Bunu yapamazsın. Derleme hatası alırsınız.
Burada başka bir örnek var. Burada size bazı değişkenlerin adreslerini
nasıl alacağınızı göstereceğiz. İşte bu main'de, gerçek ifadeler
üzerinde bazı işaretçi
aritmetiği yapıyoruz.
Yani dizi üzerinde hiçbir şey yapmıyoruz, bu yüzden işaretçileri artırmıyoruz veya
azaltmıyoruz. Yani değerleri azaltıyoruz. Yani num1 ve num2 olmak üzere
2 long tipimiz var ve sonra long tipinde bir işaretçimiz var, onu null olarak başlatıyoruz.
num1'in adresini pnum işaretçimize atıyoruz.
Ve sonra pnum değerini L'ye atıyoruz,
yani num1 artık 2l olacak.
Eğer num2'yi artırırsak, num2'ye henüz bir şey yapılmamış
olur.
Yani pnum'ın değeri 2l'dir, bu da num1'in değerinin 2l olduğu anlamına gelir.
L sadece uzun olduğunu belirtmek için kullanılan bir son ektir.
Şimdi 0l olan uzun num2 değerini artırırsak,
1l olacaktır.
Eğer num2 artı eşittir yıldız pnum dersek,
pnum 2l'dir, bu yüzden 1l artı 2l olacaktır,
num2 şimdi 3l'ye eşit olacaktır.
Ve sonra num2'nin adresini pnum'a atarsak, pnum
artık num2'nin adresine eşit olacaktır.
Yani işaret ettiğimiz pnum değerini
artırırsak, şimdi 4l değerine sahip olacağız.
Buna soğuk blokların içinde bakacağız, ama ben size
bunun üzerinden yürüyorum. Num1, 2l'ye eşit olacaktır.
Num2, pnum'a işaret ettiğine eşit
olacaktır.
Pnum 3l, yani sanırım 3l olacak.
Pnum 3l olacak ve sonra pneum artı num2
6l olacak.
Bakalım haklı mıyım, bunu kod blokları halinde inceleyelim.
İşte burada kod blokları halindeyiz, bunu elle yapmaya çalıştık, ancak şimdi
haklı olup olmadığımızı görmek istiyoruz. Hata ayıklayıcıyı kullanalım.
Bunu buraya koyacağız ve program boyunca değerlerin nasıl değiştiğini göreceğiz.
Şimdi bunu oluşturalım ve hatalarını ayıklayalım.
Bu işlem başlayacak ve 10. satırda duracak.
Ve eğer izleme penceremizi açarsak, ki bunu windows
watches, watches'de debug'a giderek yapabiliriz, değerleri gittikleri
gibi görebiliriz. Yani şu anda num1 sıfır,
num2 sıfır, pnum ise null değerini gösteriyor.
Bu yüzden 0x0'dır, çünkü null'un
pnumber'da 0'ı temsil ettiğini biliyoruz.
Ve bunu if deyimlerinde karşılaştırdığımızda kullanabiliriz.
Yani 10. satırı çalıştırdıktan sonra, pnum artık num1 adresine sahip olmalıdır.
O yüzden bir adım atalım.
Şimdi pnum'ın 0x60ff08 gerçek adresi var.
Satır 11'i çalıştırdıktan sonra, pnum değerinin 2l'ye eşit olduğunu söyleyeceğiz ve bunun için izleme
penceresinde hiçbir şey görmeyeceğiz. Ama devam edelim ve çalıştıralım, pnum
hala aynı adrese sahip.
Num1 şimdi değişti çünkü pnum num1'in adresine
sahipti ve biz onu değiştirdik.
Şimdi num1 2 oldu. Şimdi 12. satırda num2'yi artıracağız.
Yani num2 sadece 1l olacak.
Bir olacak. pnum adresi hala aynıdır.
Şimdi num2'ye pnum ne ise onu ekleyeceğiz.
Pnum
hatırlama num1'e işaret ediyor, bu nedenle num2 3 olmalıdır.
Sonra 14'e gideriz, num2 3'tür, num1 hala 2'dir.
Şimdi 15. satırda, pnum'a num2 şeklinde
yeni bir adres atayacağız. Yani bundan sonra
artık 0x60ff08 olmayacağız.
Biz 060ff04 olacağız.
Şimdi pnum'ın işaret ettiği değeri 2'ye çıkarırsak
ve 2 sayısı 3 ise, 2 sayısı artık 4 olmalıdır.
Ve 4 olduğunu görüyoruz.
Şimdi tüm bu değerleri yazdıracağız ve num1 değerinin 2 olması gerektiğini
göreceksiniz.
num2'nin değeri 4 olmalıdır.
Pnum num2'ye işaret ediyor, bu yüzden hala 4 olmalıdır.
Ve sonra 4 olan pnum artı 4 olan num2'nin değerinin 8 olması
gerektiğini söyleyeceğiz.
Yani aslında 6'da yanılmış olabilirim.
Yani artık bunu saat penceresinde göremeyeceğiz. Şimdi sadece oynatalım ve çıktıyı
printf ifadeleri olarak görelim. 2448'i görmeliyiz.
Şimdi bunu hata ayıklamasız modda
çalıştıralım ve 2 4 4 8'i görelim.
İşte böyle. Umarım mantıklı gelmiştir.
Geri dönelim ve tartışmamıza devam edelim.
Peki ya girdi aldığımızda, işaretçileri bu şekilde nasıl kullanabiliriz?
Şimdiye kadar değer girişi için scanf kullandığımızda, inter veya float veri türüne sahip olduğumuzda
ampersand operatörünü kullanmamız gerekiyordu. Buna sahip olduğumuz tek zaman, bir karakter dizisine
sahip olduğumuz zamandır ve bunun nedeni, a karakterinin aslında hakkında
konuşacağımız bir karakter işaretçisi olmasıdır.
Ancak değerleri girmek için scanf kullanırsak ve bunları karakter dizileri olmayan normal
veri türlerinde kullanırsak, her zaman bu ekleme veya alt operatörünü kullanmak zorunda kalırız.
Bunun nedeni scanf'in ikinci argümanının bir işaretçi olmasıdır.
Bu yüzden ona bir adres göndermeliyiz. İşaretçiler yalnızca adres değerlerine sahiptir.
Dolayısıyla, zaten bir adres içeren bir işaretçiniz olduğunda, işaretçi adını scanf için bir argüman olarak kullanabilirsiniz.
Artık gerçekten bir işaretçi oluşturduysanız ve işareti operatörünü kullanmak zorunda
değilsiniz, çünkü scanf'in ikinci argümanı bir işaretçidir ve bu nedenle sadece işaretçi
adını söyleyebilirsiniz.
Eskiden bir değeri value içinde saklamak istediğimizde
scanf'in ikinci argümanında
ampersand değerini söylerdik.
Ancak oluşturduğumuz bir işaretçimiz varsa ve bu örnekte
olduğu gibi zaten bir adresi gösteriyorsa,
scanf'i kullandığımızda tek söylememiz gereken değerin adı, işaretçinin
adıdır.
İşte bir tamsayıya sahip olduğumuz bir durum, ancak bir tamsayıya
işaretçimiz olduğu için ampersand kullanmamız gerekmiyor.
Sadece yüzde d, p değeri diyoruz.
Dolayısıyla, bir işaretçiniz varsa, karakter dizilerinin
yanı sıra scanf'e normal değişken adlarını aktarabileceğiniz başka zamanlar
da vardır.
Ayrıca daha sonra girdiklerini yazdırabilirsiniz ve bu değerin
aslında girdikleri değerle değiştirileceğini fark edeceksiniz
çünkü bu adrese işaret ediyoruz.
Null için test.
Hafızanıza kazımanız gereken bir kural var. Bu çok çok önemli.
Dereferanslama hakkında konuştuk, ancak kasıtsız bir işaretçiyi, hiçbir şeyi
işaret etmeyen bir işaretçiyi veya kendisi için ayrılmış belleği
olmayan bir işaretçiyi dereferanslarsanız ne olur?
Peki ya şöyle bir şey yaparsak. Bir işaretçi bildiririz, ancak
aslında onu hiç başlatmamışızdır ve sonra ona atama yapmaya çalışırız.
Ona atıfta bulunuyoruz ve atıyoruz, bu büyük bir hata.
Yani ikinci satır temel olarak 5 değerini pt'nin işaret
ettiği konumda saklamak istediğiniz anlamına gelir,
ancak pt hiçbir şeyi işaret etmez çünkü henüz başlatılmamıştır.
Yani pt artık rastgele bir değere sahip olacaktır.
Dolayısıyla 5'in nereye yerleştirileceğini bilmek mümkün değildir, bellekte herhangi bir yere yerleştirilebilir.
Bu zararsız olabilir. Programınızdaki mevcut verileri
veya mevcut durum değişkenlerini olduğundan fazla gösterebilir.
Programın çökmesine neden olabilir. Bu çok sorunlu.
Yani bir işaretçi oluşturduğunuzda ve işaretçinin kendisini saklamak için bellek ayırdığınızda,
verileri saklamak için bellek ayırmaz.
Yani instar pt diyerek, işaretçi
için bellek ayırdı, ancak işaretçinin
değeri olan adres için herhangi bir
bellek ayırmadı. İşaretçilerin adresler içerdiğini unutmayın.
İşaretçiyi oluşturdu ancak işaret ettiği şey için herhangi bir bellek oluşturmadı.
Bu yüzden referansını kaldıramazsınız.
Bu yüzden verileri depolamak için bellek ayırmaz.
Bir işaretçiyi kullanmadan önce, ona daha önce ayrılmış bir bellek konumu atanmalıdır
ya da bahsedeceğimiz malloc kullanarak dinamik bellek tahsisi kullanmalısınız.
Bu nedenle, ya mevcut bir değişkenin adresini işaretçiye atarsınız ya
da dinamik bellek tahsisi olan malloc'u kullanırsınız.
Ancak, bir işaretçi kullandığınızda, onu oluşturduysanız ve null ise, önceden
null olup olmadığını kontrol etmeniz gerektiğini unutmayın,
bundan birazdan bahsedeceğiz. Ancak bir işaretçi ilklendirilmemişse,
bu şekilde ilklendirilmiş başka bir değişkene işaret
etmediği ya da bellek ayrılmadığı sürece ona hiçbir şey atamayın.
İşte bu noktada null devreye giriyor.
Aslında bir dereferans hatası olmadığından
emin olmak için null testi yapabilirsiniz. Programınızın çökmediğinden emin olun.
Dolayısıyla, null'un temelde hiçbir şeye işaret etmediğini
zaten biliyoruz ve tüm değişkenlerimizi, işaretçilerimizi null'a
başlatmalıyız.
Bu yüzden her zaman böyle bir şey yapmalıyız.
Null, c'de sıradan sayılarla sıfıra eşdeğer işaretçiyi temsil
eden özel bir semboldür.
Aşağıdaki de sıfır kullanarak bir işaretçiyi null değerine ayarlar.
Bu nedenle, onu geçmek veya null'a atamak istemiyorsak, sadece 0 diyebiliriz ve
bu hiçbir şeye işaret etmemekle eşdeğerdir.
Dolayısıyla, null değeri 0'a eşdeğer olduğu için, p
değerinin null olup olmadığını test etmek istiyorsanız, açık testler kullanmak
gibi bir şey yapabilirsiniz. İşaretçi eşittir null diyebilirsiniz.
Ve eğer pointer null'a eşitse, yani sıfırsa, o zaman
gerçekten bir şey yapabilirsiniz.
Yani sıfır veya null değilse, bir true veya başka bir değer ise,
bu çökmelere karşı kontrol etmenin bir yoludur.
Bir şeyin referansını gerçekten kaldırmaya çalışmadan
önce, bu size bellek ayrılıp ayrılmadığını söyleyecektir.
Bu nedenle, bir işaretçinin referansını kaldırmadan önce null olup olmadığını kontrol etmek istersiniz.
Ve bunu genellikle fonksiyonlarda yaparsınız çünkü
fonksiyonlar parametre olarak işaretçi alır.
Ve eğer çağıran hatalı veri
geçiriyorsa veya bir işaretçi geçiriyorsa, ayrılmış herhangi bir bellek yoktur,
bu kodunuzu çökertebilir. Yapmak istediğiniz şey, arayanın geçerli bir adrese sahip
olduğundan emin olmaktır, böylece null olup olmadığını kontrol edebilirsiniz.
Temel olarak, bunun anlamı her zaman p değeri değil veya işaretçi değil
demek için bu if kontrollerine sahip olmaktır.
Ve eğer işaretçi değilse, o zaman referansını kaldırabilirsiniz.
İşaretçiler hakkında çok konuşuyoruz. Epeyce tartıştık.
Eminim biraz bunaltıcı olmaya başlamıştır. Bir ara verip önceki dersleri gözden geçirmek
ve bu kavramı kafanızda gerçekten senkronize etmeye çalışmak isteyebilirsiniz.
İşaretçiler sadece adresleri içerir.
Ancak 3 bölümden oluşuyor, bu yüzden sorunlu olabilir.
Ama pozitif kal. Beni dinlemeye devam edin, kafa karıştırıcı
olduğunu biliyorum.
Adreslerle çalışmaktan bahsetmiştik.
Değerlerle çalışmaktan bahsetmiştik. İşaretçinin kendisi ile çalışmaktan ve
işaretçiye işaret eden değişkenlerle çalışmaktan bahsettik.
Yani hatırlamanız gereken bir
sürü şey var ve bu çok bunaltıcı ve sinir bozucu olabiliyor.
Ve neler olup bittiğini anlamaya çalışmak her zaman zordur ve çok fazla pratik yapmak gerekecektir.
Bu kavramı ve şimdiye kadar konuştuğumuz her şeyi anlamanın en iyi
yolu pratik yapmak, bahsettiğim
tüm kavramları kullanan kısa programlar yazmaktır.
Dolayısıyla, bir işaretçi kullanarak değerleri
alan bir program yazın, bu belki de dolaylama operatörünü, dereferencing'i
kullanmak olabilir. İşaretçileri kullanarak değerleri değiştiren bir program yazın.
Yani bu dereferanslama olacaktır, işaretçileri kullanarak değerleri almak sadece
adres olacak olan işaretçinin adı olacaktır. Baskı adresleri, tüm bu sözdizimine baktık.
Bu konuda tekrar tekrar pratik yaparsanız, bu işte iyi olursunuz.
Kendinize olan güveninizi artırmalı ve bu kavramlara hakim olmak için ayrıntılı
olarak çalışmalısınız.
İşaretçiler hakkında konuşacak daha çok şeyimiz var, ancak şu an bir kenara çekilip şu ana kadar konuştuklarımızın
üzerinden geçmenin ve böylece kafanıza kazımanın tam zamanı olabilir.
Teşekkür ederim.