6 Mart 2017 Pazartesi

Örnek4: İşaretçiler Kullanılarak Takas (Swap)


Örnek3: İşaretçi Olan Fonksiyon Parametresi



x değişkeni f1(x) ve f2(&x) fonksiyonlarına, sırasıyla değer ve adres geçerek aktarılmıştır.
f1 içinde x (n = 66; işlemi ile) değişime uğramış, fakat çağrılma işleminin sonucunda, x'in değeri değişmemiştir.
Ancak f2 içinde x ( *n = 77 işlemi ile) değişimi sonucunda, x’in değeri çağrıldıktan sonrada korunmuştur.
Yani, adres geçerek yapılan aktarımda, f2'ye aktarılan değer değil adres olduğu için, yollanan x parametresi f2 içinde değişikliğe uğrayacak ve bu değişim çağrıldığı satırdan itibaren devam edecektir.

Fonksiyon Parametresi Olan İşaretçiler

C programlama dilinde fonksiyon parametreleri
Değer geçerek (pass by value)
Adres geçerek (pass by reference)
   olarak geçilebilirler.
Şu ana kadar gördüğümüz fonksiyon kullanımında geçirilen parametreler, fonksiyon içerisinde değiştirilse bile, fonksiyon çağırıldıktan sonra bu değişim çağrılan yerdeki değerini değiştirmez.
Fakat, bir parametre adres geçerek aktarılırsa, fonksiyon içindeki değişikler geçilen parametreyi etkiler.
Adres geçerek aktarım, gösterici kullanmayı zorunlu kılar.

Örnek3: İşaretçi Olan Fonksiyon Parametresi

main fonksiyonu içerisinde int türündeki x değişkenine 55 değerine atayan.
Aşağıdaki fonksiyonları yazın.
void f1(int  n);
void f2(int *n);
f1 fonksiyonu kendisine gelen n değişkenine 66 değerini atasın, f2 fonksiyonu kendisine gelen n işaretçisine 77 değerini atasın.
main içerisinde f1 ve f2 fonksiyonlarını çağırarak x’i parametre olarak geçirin.
f2 fonksiyonuna f2(&x); olarak parametre geçirilecektir.
Her fonksiyon çağırımı sonrasında main fonksiyonu içerisinde x değişkenini yazdırın.

Örnek2:Ortalama Bul


Örnek1:İşaretçi/Dizi Offset Yazdırma

Aşağıdaki ekran çıktısının C programlama dilinde kodunu yazalım.

Örnek1:İşaretçi/Dizi Offset Yazdırma






İşaretçiler ve Diziler


Diziler ve işaretçiler, C’de özel bir biçimde ilişkilidirler.
Birbirleri yerine hemen hemen her yerde kullanılabilirler.
Bir dizi ismi, sabit bir işaretçi olarak düşünülebilir.
Bu yüzden, bir dizinin herhangi bir elemanına işaretçi ile de erişilebilir.


int kutle[5], *p, *q;

p = kutle; -------------> 1. Elemanın adresi p işaretçisine atanıyor


p = &kutle[0];--------> 1. Elemanın adresi p işaretçisine atanıyor


q = &kutle[4];----------> 5. Elemanın adresi p işaretçisine atanıyor

Not: Dizi adı bir işaretçi olduğu için doğrudan aynı tipteki bir işaretçiye atanabilir.


Ayrıca, i bir tamsayı olmak üzere aşağıdaki iki ifade aynı anlamdadır.
kutle[i];
*(p + i);
Bunun sebebi, p işaretçisi kutle dizisinin başlangıç adresini tutmuş olmasıdır.
p+i işlemi ile i+1. elemanın adresi, ve *(p+i) ile de bu adresteki değer hesaplanır.
*(p+i);  ? p nin gösterdiği adresten i blok ötedeki sayıyı  hesapla


Örnek: *(p+3);

Bu deyimde 3, işaretçinin offsetidir.
İşaretçi, dizinin başlangıç adresini gösterirken, ve offset değeri dizi belirteciyle eştir. offset dizinin hangi elemanının kullanılacağını belirtir
Bu gösterime işaretçi/offset gösterimi denir.
Parantezler gereklidir çünkü * operatörünün önceliği + operatörünün önceliğinden yüksektir.
Parantezler olmadan yukarıdaki ifade, *p’ye 3 eklerdi. (yani, p’nin  dizinin başlangıcını gösterdiği düşünülürse, kutle[0]’a 3 eklenirdi.)

27 Şubat 2017 Pazartesi

İşaretçi Aritmetiği



İşaretçiler kullanılırken, bazen işaretçinin gösterdiği adres taban alınıp, o adresten önceki veya sonraki adreslere erişilmesi istenebilir.
Bu durum, işaretçiler üzerinde, aritmetik işlemcilerin kullanılmasını gerektirir.
İşaretçiler üzerinde yalnızca
toplama (+),
çıkarma (-),
bir arttırma (++) ,
bir eksiltme (--)
   operatörleri işlemleri yapılabilir

Aşağıdaki gibi üç tane gösterici bildirilmiş olsun:

char   *kar;    ?    10000 (0x2710)
int    *tam;    ?    20000 (0x4e20)
double *ger;    ?    30000 (0x7530)

Buna göre aşağıdaki atama işlemlerinin sonucu ne olmalıdır?
kar++;       
tam++;       
ger++;       

Bir işaretçiye ekleme yapıldığında, o anda tuttuğu adres ile eklenen sayı doğrudan toplanmaz.
Böyle olsaydı, bu atamaların sonuçları sırasıyla 10001, 20001 ve 30001 olurdu.
Gerçekte, işaretçiye bir eklemek, işaretçinin gösterdiği yerdeki veriden hemen sonraki verinin adresini hesaplamaktır
Buna göre atama işlemlerinin sonucu:
kar++;        ?    10001 (0x2711)
tam++;        ?    20004 (0x4e24)
ger++;        ?    30008 (0x7538)

Genel olarak, bir işaretçiye n sayısını eklemek veya çıkarmak, bellekte gösterdiği veriden sonra veya önce gelen n. elemanın adresini hesaplamaktır.
Buna göre aşağıdaki atamalar şöyle yorumlanır.
 kar++;      /* kar = kar +   sizeof(char)*/
 tam = tam + 5;/* tam = tam + 5*sizeof(int)*/
 ger = ger - 3; /*ger = ger - 3*sizeof(double)*/

Örnek: İşaretçi Aritmetiği