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.
6 Mart 2017 Pazartesi
Ö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
Ö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
İşaretçi (Pointer) Kavramı
C dili, bir değişkenin adresinin bir başka değişkende saklanmasına izin verir. Bu değişkene işaretçi denir.
İşaretçi denmesinin sebebi ilgili değişkenin adresini işaret etmesinden yani göstermesinden kaynaklanır.
Diğer bir deyişle işaretçi, bir değişkenin adresini içeren başka bir değişkendir.
İşaretçiler, C’nin yönetilmesi en zor yetenekleri arasındadır.
Programların referansa göre çağırma yapmasını sağlarlar.
İşaretçiler sayesinde; Bağlı listeler (Linked List), Sıralar (Queue), Yığınlar (Stack) ve Ağaçlar (Tree) gibi büyüyüp küçülebilen dinamik veri yapılarının oluşturulması ve yönetilmesi sağlanır.
Bir işaretçi, diğer değişkenler gibi, sayısal bir değişkendir.
Bu sebeple kullanılmadan önce program içinde bildirilmelidir. İşaretçi tipindeki değişkenler aşağıdaki gibi tanımlanır:
tip_adı *isaretci_adı;
Burada tip_adı herhangi bir C veri türü olabilir. Değişkenin önündeki * karakteri yönlendirme (indirection) operatörü olarak adlandırılır ve bu değişkenin veri değil bir adres bilgisi tutacağını işaret eder.
Örnek:
char *kr; /* tek bir karakter için */
int *x; /* bir tamsayı için */
float *deger, sonuc; /* deger işaretçi tipinde, sonuc sıradan bir gerçel değişken */
Yukarıda bildirilen işaretçilerden; kr bir karakterin, x bir tamsayının ve deger bir gerçel sayının bellekte saklı olduğu yerlerin adreslerini tutar.
int *ptam, tam = 33;
.
.
.
ptam = &tam;
Bir işaretçiye, bir değişkenin adresini atamak için & (adres) operatörünü kullanırız.
ptam işaretçisi tam değişkeninin saklandığı adresi tutacaktır.
Gösterimde, ptam göstericisinin içeriği tam değişkeninin içeriği (33) değil adresidir (0x3fffd14). Ayrıca, ptam değişkeni, bellekte başka bir hücrede saklandığına ve bu hücrenin int değil int * tipinde bir bölge olduğuna dikkat ediniz.
Örnek: İşaretçi Gösterimi ve Değer Değiştirme
tam adlı değişkenin içeriğine ptam işaretçisi kullanılarak da erişilebilir.
Bunun için program içinde ptam değişkeninin önüne yönlendirme operatörü (*) koyulmuştur.
Yani *ptam, tam değişkeninin adresini değil içeriğini tutar. Buna göre:
*ptam = 44;
komutuyla, ptam'ın adresini tuttuğu hücreye 44 değeri atanır.
Özetle
*ptam ve tam, tam adlı değişkenin içeriği ile ilgilidir.
ptam ve &tam, tam adlı değişkenin adresi ile ilgilidir.
* yönlendirme ve & (adres) operatörüdür.
Bunun için program içinde ptam değişkeninin önüne yönlendirme operatörü (*) koyulmuştur.
Yani *ptam, tam değişkeninin adresini değil içeriğini tutar. Buna göre:
*ptam = 44;
komutuyla, ptam'ın adresini tuttuğu hücreye 44 değeri atanır.
Özetle
*ptam ve tam, tam adlı değişkenin içeriği ile ilgilidir.
ptam ve &tam, tam adlı değişkenin adresi ile ilgilidir.
* yönlendirme ve & (adres) operatörüdür.
Bellek ve Adresleme
Bilgisayarın ana belleği (RAM) sıralı kaydetme gözlerinden oluşmuştur.
Her göze bir adres atanmıştır.
Bu adreslerin değerleri 0 ila belleğin sahip olduğu üst değere bağlı olarak değişebilir.
Örneğin 1GB bir bellek,
1024*1024*1024 = 1073741824 adet gözden oluşur.
Bir programlama dillinde, belli bir tipte değişken tanımlanıp ve bir değer atandığında, o değişkene dört temel özellik eşlik eder:
değişkenin adı
değişkenin tipi
değişkenin sahip olduğu değer (içerik)
değişkenin bellekteki adresi
Örnek: Bellek ve Adresleme
Atama deyimlerine göre hücrelerin adreslere yerleşimi otomatik olarak gerçekleşir.
yas değişkeni 5400, 5401, 5402, 5403 adreslerini kapsadığından
boy değişkeni 5404 adresinden başlar ve sırasıyla 5405, 5406 ve 5407 adreslerini işgal eder.
kilo değişkeni bu nedenle 5408 adresinden başlar ve 5409, 5410, 5411 adreslerini kapsar.
cins değişkeni ise 5412 adresini tutar.
Örnekte belirtilen kod bloğundaki değişkenler bilgisayar tarafından belirli bir adreste saklanır. Bu yönteme implicit (örtük) adresleme denir.
İşaretçi değişken kullanılarak, işaretçilere verilerin bellekte saklandığı bellek hücrelerinin başlangıç adresleri atanır. Bu yönteme ise explicit (açık) adresleme denir.
Örnek:
int tam = 33;
Bu değişken için, int tipinde bellekte (genellikle herbiri 1 bayt olan 4 bayt büyüklüğünde) bir hücre ayrılır ve o hücreye 33 sayısı ikilik (binary) sayı sitemindeki karşılığı olan 4 baytlık (32 bitlik) karşılığı aşağıdaki gibi yazılır.
00000000 00000000 00000000 00100001
Örnek:
int tam = 33;
Bellek adresleri genellikle onaltılık (hexadecimal) sayı sisteminde ifade edilir.
0x3fffd14 sayısı onluk (decimal) sayı sisteminde 67108116 sayına karşılık gelir. Bunun anlamı, tam değişkeni, program çalıştığı sürece, bellekte 67108116. - 67108120. numaralı gözler arasındaki 4 baytlık hücreyi işgal edecek olmasıdır.
tam adlı değişkenin bellekteki gerçek konumu ve ikilik düzendeki içeriği aşağıdaki gibidir:
Değişkenin saklı olduğu adres, & karakteri ile tanımlı adres operatörü ile öğrenilebilir.
Bu operatör bir değişkenin önüne konursa, o değişkenin içeriği ile değil adresi ile ilgileniliyor anlamına gelir.
Birlikler (Union)
Birlikler de yapılar gibi sürekli belleğe yerleşen nesnelerdir.
Birlikler yapılara göre daha az kullanılırlar. Bir programda veya fonksiyonda değişkenlerin aynı bellek alanını paylaşması için ortaklık bildirimi union deyimi ile yapılır. Bu yer, birliğin en büyük alanı kadardır.
Bu da belleğin daha verimli kullanılmasına imkan verir.
Bu tipte bildirim yapılırken struct yerine union yazılır.
Örnek:
union test
{
int x;
char y[10];
} p
Bu tanıma göre x tamsayısı için bellekte 4 baytlık yer ayrılmaktadır.
Birlik içinde yer alan y değişkeni için 10 baytlık yer ayrılmıştır.
Bu durumda, birlik için en fazla 10 baytlık bir yer ayrılmıştır. Ayrılan bu alan, birliğin her bir alanı tarafından ortak kullanılır.
typedef Kullanımı
typedef deyimi C dilinde değişken tanımlama yaparken kullanılan int, float, char gibi değişken isimlerini değiştirmeye yarar.
Bu sayede kodlar programcının anadiline daha fazla yaklaşmış olur.
struct deyimi ile beraber kullanıldığında oluşturduğunuz yapıyı bir değişken türü olarak tanımlayıp o yapının çoğaltılmasını sağlar. Bu yapıdan değişken tanımlamak için tekrar struct deyiminin kullanılmasına gerek kalmaz.
Örnek: typedef Kullanımı
struct içerisinde struct Kullanımı
C programlama dili struct içerisindeki bir üyenin yine bir struct olmasına izin verir. Bunu yapmaktaki temel amaç:
Kaynak kodun tekrar kullanılabilirliğini arttırmak
Kaynak kodun okunabilirliğini arttırmak
Kaynak kodu sadeleştirmek
Örnek: struct içerisinde struct Kullanımı
Bu sayede kodlar programcının anadiline daha fazla yaklaşmış olur.
struct deyimi ile beraber kullanıldığında oluşturduğunuz yapıyı bir değişken türü olarak tanımlayıp o yapının çoğaltılmasını sağlar. Bu yapıdan değişken tanımlamak için tekrar struct deyiminin kullanılmasına gerek kalmaz.
Örnek: typedef Kullanımı
struct içerisinde struct Kullanımı
C programlama dili struct içerisindeki bir üyenin yine bir struct olmasına izin verir. Bunu yapmaktaki temel amaç:
Kaynak kodun tekrar kullanılabilirliğini arttırmak
Kaynak kodun okunabilirliğini arttırmak
Kaynak kodu sadeleştirmek
Örnek: struct içerisinde struct Kullanımı
Kaydol:
Kayıtlar (Atom)