Google Drive Sizin Amsrad Dergisi Pdf Adresi
29 Ağustos 2015 Cumartesi
7 Ağustos 2015 Cuma
22 Haziran 2015 Pazartesi
Stack ve Heap nedir?
Stack, örneğin bir derleyicide yer alan program kodlarının parantezlemelerini depolayan bellek bölümüdür. Derleyici kodu derlerken açılan parantezleri ve onun akabinde kapatılan parantezleri stack'e atar(push) ve sırayla bunları kontrollü bir şekilde tepeden aşağıya doğru(LIFO methodu doğrultusunda) stack'ten çıkarır(pop). Eğer bir eksiklik yakalanırsa derleyici demek ki parantez eksiği var der ve ona göre hata verir. Stack'in kullanımı ile alakalı bir diğer örnek ise bir programın kodunda yer alan fonksiyonların çalışma işleyişidir. Örneğin C dilinde yazılmış bir program, çalışmaya main fonksiyonunda başlar ve main fonksiyonunda biter. Main fonksiyonu içerisinde kullanılan bir başka fonksiyon çağırılırken program, fonksiyon nerede tanımlanmışsa oraya dallanır. Stack ise bu örnekte geri dönüş adresini tutma işlevini yerine getirir. Yani programın dallandığı fonksiyonun işlenmesi bittikten sonra eski yere dönüş adresi stack'te depolanır.

Peki heap nedir? Bunu açıklamadan önce bir analojiye değinmemiz anlamamızı kolaylaştıracaktır. RAM belleği bir defter olarak düşünün. Bir yazı yazmaya başlarken defterin başından başlarız, değil mi? Program kodlarımız program çalıştırıldığında defterin(RAM'in) başından itibaren yazılmaya başlar. Stack ise defterin sonudur. Genelde defterin sonuna bazı notlar alır ve sayfa dolduktan sonra bir önceki sayfaya kayarız, değil mi? Stack de bunu yapar. Sondan başa doğru yerleştirir. Heap ise şudur: Diyelim ki masaüstündeki bir programın simgesine(kısayoluna) çift tıkladınız. Çift tıklama sonucu o programın makine kodu CPU'nun Kontrol Birimi(Control Unit'i) tarafından hard disk'ten RAM'e kopyalanır. Bu kopya veri, belleğin başından itibaren birer birer hücrelere yerleştirilir(defterin başından itibaren yazılır). Stack ise yukarıda bahsettiğimiz gibi çeşitli ilgili durumlarda verileri, belleğin en sonundaki hücrelere birer birer yerleştirir(defterin sonuna notlar alınır). Heap ise defterde yazının bittiği sayfa ile en arka sayfadaki notların bittiği yere kadarki olan kısma denir. Bir başka şekilde ifade edecek olursak heap, program kodları ile stack'in arasında kalan yere denir.
Stack ile heap arasındaki farka gelecek olursak bunların birinci farkı bellekte farklı yerleri ifade ediyor olmalarıdır. İkinci farkı ise şudur ki heap, stack'ten farklı bir kullanım amacına sahiptir. O da bir programın çalıştığı sıralar bellekten yer talep edildiği durumlarda talebin heap'ten isteniyor olmasıdır. Yani heap'e aslında dinamik bellektir diyebiliriz. Anlamadığınızı varsayarak yine bir örnek ile açıklamaya çalışayım: C'de listelerle alakalı bir program yazdığınızı düşünün. Ve programın algoritmasını kullanıcının girdiği sayı oranında liste düğümü olacak şekilde ayarladığınızı varsayın. Bu durumda program çalışırken kullanıcının girdiği sayı kadar malloc() fonksiyonu çalıştırılacak ve o kadar bellek alanı talebinde bulunulacaktır. İşte bu talepler sonucu cevap olarak dönen alan tahsisinin yapıldığı yer heap'tir. Heap'in zaman zaman dinamik bellek olarak adlandırılmasının nedeni de budur. Stack de istif bellek olarak adlandırılabilir.
Bu kavramların anlaşılması yazdığımız kodun arka planda neler yaptığı hakkında bize bilgiler verir. Stack ve Heap ‘i açıklarken belleğin nasıl yönetildiği, nasıl kullanıldığı hakkında fikir edinmiş olacağız.
Stack belleği uzun bir kutu şeklinde düşünebiliriz. Yeni bir nesne eklemek istediğimizde, bu nesne en üstte olacak şekilde sıralanır. En alttaki nesneye ulaşmak için en üstteki nesneleri tek tek çıkarmamız gerekir. Basittir.
Heap belleği ise geniş bir oda şeklinde düşünelim. Boş bulduğumuz her yere bir nesne yerleştirebiliriz ve istediğimiz bir nesneyi de istediğimiz anda alabiliriz. Tabiki geniş bir odada istediğimiz nesneyi aramak vakit alan bir işlemdir. Komplekstir.
Aradaki farklara maddeler halinde göz atacak olursak:
Stack
- LIFO prensibine göre çalışır. (Last In First Out). Yani son gelen ilk olarak çıkar. Bunu bir kutu gibi düşünmüştük. Kutuya bir kitap eklemek istediğimizde en üste ekleriz. Kutudan bir kitap çıkarmak istiyorsak en üstteki kitabı alıp çıkarırız. En alttaki kitabı çıkarmak için bütün kitapları tek tek çıkarmamız lazım.
- Her bir thread (iş parçacığı) için bir tane stack bellek oluşturulur.
- Maksimum boyutu thread oluşturulurken ayarlanır.
- Stack, daha hızlıdır. Çünkü çalışma prensibi çok basittir ve ulaşılmak istenen veriler ve boş alanlar ardarda sıralanmış olur.
- Bu kısımda oluşturulmuş veriler için pointer kullanımına gerek yoktur.
- Lokal değişkenler ve metotlar bu kısıma bağlıdır.
Heap
- İçindekiler karışık bir şekilde sıralanmıştır. Bunu da oda gibi düşünmüştük.
- Heap bellek, uygulama başlatıldığında başlar. Ortak olarak kullanılır. Stack gibi her bir thread için ayrı bir tane oluşturulmaz. Bir process için bir heap oluşturulur diyebiliriz.
- Stack belleğe göre daha yavaştır. Nedeni ise herhangi bir nesneye ulaşmak için kompleks bir arama yapmanız gerekir. Bir nesneyi boş bulduğumuz herhangi bir yere koyabiliriz. Karmaşıktır.
- “Memory Leaks” , “Fragmentation” bu kısımda ortaya çıkar.
- Yer sorunu olduğu zaman işletim sisteminden daha fazla yer isteyebilir. Yani genişleyebilir.
- · Instance değişkenleri ve objeler bu bölgeye bağlıdır.
C'de Dinamik Bellek Yönetimi - Malloc - Calloc - Realloc
Dinamik Bellek Yönetimi Fonksiyonları
Standart olarak
- Malloc
- Calloc
- Realloc
- Free
fonksiyonları en çok kullanılan dby(dinamik bellek yönetimi) fonksiyonlarıdır. Bunların dışında sistem bağımlı dby fonksiyonlarıda bulunmaktadır.
Malloc
En çok kullanılan dby fonksiyonudur.
Malloc fonksiyonu programın çalışma zamanı sırasında (Run-Time) belleğin güvenli bir bölgesinden istenilen uzunluk kadar yer tahsis etmektedir. Geriye bir değer döndürür ve bu değer ayırdığı bellek bölgesinin başlangıç adresine işaret etmektedir. Eğer bellekten tahsisat yapamazsa geriye 0 değerini döndürür.
char *p; p = malloc(5);
Bu ifade ile bellekte 5 byte boyutunda sürekli bir alan tahsis edilecektir ve tahsis edilen alanın başlangıç adresi p pointerına atanacaktır.
Bellekten yer ayırma işleminin başarısını kontrol etmek isterseniz aşağıdaki gibi bir yol izleyebilirsiniz.
char *p; p = malloc(5); if(p) printf("Tahsisat Basarili !\n"); else printf("Tahsisat Yapilamadi\n");
Burada 5 değeri yerine 99999999999999 değerini vererek yer ayrılmama durumunu da test edebilirsiniz.
Yukarıdaki örnekte pointerın tipi char olduğundan dolayı 5 elamanlı bir char bloğu ayrılmıştır fakat char yerine int kullanırsak biraz daha farklı bir senaryo olmakta :
int *p; p = malloc(20);
Burada int tipinden 5 elemanlık bir blok tahsis edilmektedir. Bunun sebebi int veri tipinin 32 bit sistemlerde 4 byte yer kaplamasıdır. Fakat 16 bit sistemlerde veya 64 bit sistemlerde 5 elemanlı bir blok yerine 10 elemanlık veya 2 elemanlık bloklar ayrılabilir. Bunu engellemek için sizeof fonksiyonunu kullanabiliriz. Aşağıdaki örnekte bellekten ayrılan yer bütün sistemlerde 5 elemanlık bir blok olacaktır.
int *p; p = malloc(sizeof(int)*5);
Malloc fonksiyonunun geriye bir adres döndürdüğünü söylemiştim. Bu noktada oluşturduğumuz pointerın tipi ile geriye döndürdüğümüz adresin tipinin aynı olmasına özen gösterin, yoksa derleyici uyarı verebiliyor. Eğer bilinçli bir tür dönüşümü yapmak isterseniz şu kodlar işinize yarayacaktır.
int *p; p = (int *)malloc(sizeof(int)*5);
Bu ifade ile hem kendinizi güvene almış olursunuz hem de kodun okunurluluğunu arttırmış olursunuz.
Malloc fonksiyonu tahsis ettiği bellekteki bölgelere herhangi bir ilkdeğer atama işlemi uygulamaz. Yani bellekteki değerleri ile beraber size tahsis eder, ilkdeğer atamak size kalmış bir iştir.
Calloc
Malloc fonksiyonuna oldukça benzer bir yapısı vardır. Calloc fonksiyonu içerisine 2 parametre alır, birinci parametresiyle ikinci parametresinin çarpımı kadar (byte) bellek bölgesi ayırır. 15 elemanlı int tipinden bir blok ayırmak için aşağıdaki kodlar yeterli olacaktır.
int *p; p = calloc(15,sizeof(int));
Calloc fonksiyonu aslında bellek tahsisatı yaparken Malloc fonksiyonunu kullanıyormuş bunu da küçük bir not olarak ekliyim.
Calloc, malloctan farklı olarak ayırdığı bellek bölgesini sıfırlamaktadır. Sıfırlama işlemini bizim için kendisi yapıyor. Aşağıdaki iki örneği inceleyiniz, ikiside bellekten 15 elemanlı bir int blok dizisi tahsis edip içini sıfırlıyor ve içeriğini ekrana basıyor.
#include <stdio.h> #include <stdlib.h> #include <conio.h> int main() { int *p,i; p = malloc(sizeof(int)*15); for(i=0;i<15;i++) { p[i]=0; printf("Ayrilan Bolgenin %d. Elemani ---> %d\n",i+1,p[i]); } getch(); }
#include <stdio.h> #include <stdlib.h> #include <conio.h> int main() { int *p,i; p = calloc(15,sizeof(int)); for(i=0;i<15;i++) { printf("Ayrilan Bolgenin %d. Elemani ---> %d\n",i+1,p[i]); } getch(); }
Realloc
Realloc fonksiyonu daha önce malloc veya calloc ile yapılmış tahsisatı genişletmek ya da daraltmakamacıyla kullanılır. İçerisine iki parametre alır, birincisi daha önce tahsis edilen bloğun başlangıç adresive ikincisi ise bloğun yeni uzunluğudur.
Realloc fonksiyonu yeni tahsisatı yaparken eğer belleğin daha önce tahsis edilmiş bloğunun yanında yer yoksa, bloğun tamamını içerikleriyle birlikte yeterli uzunluğu olan bir bölgeye taşır. Bu sebepten dolayı geriye döndürdüğü adres pointerı, daha önce malloc ya da calloc ile kullanılan adres pointerı ile aynı olmalıdır. Aşağıdaki örnekte önce 15 elemanlı bir int blok dizisi ayrılmış ve sonra realloc fonksiyonu ile 20 elemana genişletilmiştir.
int *p; p = calloc(15,sizeof(int)); p = realloc(p,sizeof(int)*5);
Eğer realloc bloğu genişletemezse geriye 0 değerini döndürecektir.
Bu arada realloc fonksiyonunu kullanmak için daha önce malloc ya da calloc fonksiyonunu kullanmış olmanız gerektiğini unutmayın.
Realloc fonksiyonu da malloc fonksiyonu gibi tahsis ettiği bloğa ilk değer vermez.
Yazının en başında verimli bellek yönetiminden bahsetmiştim. Bu fonksiyon ile ayırdığınız bellek bölgesini küçülttüğünüzde bloğunuz bellekte yer değiştirmiş olabilir, biraz mantıksız gelebilir ama olayın aslı çok mantıklıdır. Küçültülen bellek bölgesi, bellekte daha uygun bir yere taşındığında, meslea tam ona uygun bir uzunluktaki boşluğa taşındığında belleği tam olarak verimli kullanmış olmaz mısınız ?
Free
Free fonksiyonu verimli ve dinamik bellek kullanmayı sağlayan en önemli fonksiyonlardandır. Bu fonksiyon ile malloc ya da calloc ile daha önceden ayırdığınız bellek bölgelerini işletim sistemine iade edebilirsiniz. Parametre olarak içine daha önce ayırdığınız bellek bölgesinin başlangıç adresini göndermelisiniz.
int *p; p = malloc(sizeof(int)*25); free(p);
Eğer tahsis edilmiş bellek bölgesi free fonksiyonu ile geri iade edilmemişse, programın sonunda otomatik olarak boşaltılır.
Etiketler:
calloc,
dinamik bellek,
Malloc,
realloc,
yönetimi
24 Mayıs 2015 Pazar
C'de Sayı Türleri ve Otomatik Sayı Dönüşümleri
Tamsayı
türleri :
-----------------
signed
char - 1 byte
unsigned
char - 1 byte
signed
short short>=char
unsigned
short short>=char
signed
int int>=short
unsigned
int int>=short
signed
long long>=int
unsigned
long long>=int
2
Tamsayı sabiti int, unsigned int, long, unsigned long türlerinden
ilk
uygun tür olacak şekilde belleğe yerleştirilir.
Literal
Characters :
---------------------
2U
Tamsayı sabiti unsigned int, unsigned long türlerinden
ilk
uygun tür olacak şekilde belleğe yerleştirilir.
2L
Tamsayı sabiti long, unsigned logn türlerinden
ilk
uygun tür olacak şekilde belleğe yerleştirilir
2UL
unsigned long
Gerçek
sayı türleri (IEEE 754)
-------------------
float
double
long
double
2.3 double
2.3F float
2.3L long
double
2F float
2. double
2.0 double
*/
foo(12.3F);
printf("%d\n",
d);
/*
Otomatik
Sayı dönüşümleri (imlicit type convert)
-------------------------------------------
1.
int'e yükseltme
---------------------
a.
char , short türleri önce int türüne yükseltilir.
b.
short<int ise signed int
c.
sizeof(signed short) == sizeof(signed int) signed int
d.
sizeof(unsigned short) == sizeof(unsigned int) unsigned int
----------------------------------------
2.
long double <işlem> <!long double> = long double
3.
<double> <işlem> <!double> = double
4.
float <işlem> <tamsayı> = float
5.
unsigned long <işlem> <!unsigned long & tamsayı> =
unsigned long
6.
signed long <işlem> <tamsayı & !long> = signed long
7.
unsigned int <işlem> signed int = unsigned int
İstisna1
: sizeof(short) == sizeof(int)
<signed
short> <işlem> <signed int> = unsigned int
İstisna2
: sizeof(int) == sizeof(long)
<signed
int> <işlem> <signed long> = unsigned long
*/
char
ch = -1;
if
(ch > 100000U)
printf("Doğru\n");
else
printf("Yanlış\n");
int
x1 = -23;
unsigned
int y = 2;
printf("x1
= %u\n", x1);
printf("%lf",(float)(x1*y));
func();
extern
int g;
g
= 13;
return
0;
}
Etiketler:
C,
Double,
Gerçel Sayılar,
imlicit type convert,
Long,
Sayı,
Sayı Dönüşümleri,
Tamsayı
C'de ve C++ Bildirim Ve Tanımlama Farkı
C derleyicileri bildirimini görmediği fonksiyonların geriye int (imlicit int) döndürdüğünü kabul eder. Ve bildirim yapılmadan o fonksiyonu kullandırmaya izin verir. C dilinde bildirim esnasında parametrelerin bildirimi zorunlu değildir.
CPP'ta bildirim veya tanımlama görülmeden fonksiyon kullanılamaz. Bildirim esnasında parametrelerin bildirilmesi gerekir.
CPP'ta bildirim veya tanımlama görülmeden fonksiyon kullanılamaz. Bildirim esnasında parametrelerin bildirilmesi gerekir.
Etiketler:
bildirim,
C,
C++,
CPP,
declaration,
implementation,
tanımlama
C'de Bilinirlik Alanı (Scope) , Ömür (Storage Duration) Kavramı ve Değişken Tanımlayıcıları (-Taslak-)
Bilinirlik
alanı veya kapsam veya scope veya menzil ; bir nesnenin ismi
ile kullanılabildiği alandır.
1.
File scope (örnek: global değişkenler)
2.
function scope (örnek: goto label)
3.
function declaration scope (örnek: fonksiyon bildirimleri)
4.
block scope (örnek: parametre ve yerel değişkenler)
Dosya
faaliyet alanı: Bir tanımlama fonksiyonların dışında
yapıldığı zaman tanımlanan değişken dosya faaliyet alanına
sahiptir. Bunlar tanımlamanın yapıldığı noktadan dosyanın
sonuna kadar bütün fonksiyonlar tarafından tanınır ve
kullanılırlar. Global değişkenle, fonksiyon tanımlamaları
ve fonksiyon prototipleri dosya faaliyet alanına girer.
Blok
faaliyet alanı: Bir blok içerisindeki bütün bildiriler blok
faaliyet alnına sahiptir. Bunların faaliyet alanı blok sonunu
gösteren } işaretine kadardır. Bloklar iç içe yazıldığında
dıştaki blok içerisindeki değişkenler içteki blok içerisinde
de geçerlidir. Dıştaki ve içteki bloklar aynı isimde
değişkenlere sahip olabilirler, ancak iç bloktaki değişken dış
bloktakini maskeler.
Fonksiyon
faaliyet alanı: Fonksiyon faaliyet alanı da blok faaliyet alnı
gibi düşünülebilir. Fonksiyon parametre listesinde ve
gövdesinde tanımlanan değişkenler yalnızca o fonksiyon
içerirsinde geçerlidirler. Static anahtar kelimesi ile
tanımlanmış olan yerel değişkenler programın çalışmasından
sonuna kadar bellekte tutulurlar ancak blok faaliyet alanına
sahiptirler. Faaliyet alanları değişkenlerin ömürlerinin
etkilemez.
Bilinirlikte dar kapsamlı değişken geniş kapsamlı değişkeni maskeleyecektir. C ‘de İsim gizlemesi diye bir kavram vardır.
Fonksiyon tanımlaması yaparken (int x,int y) benzeri parantez içi ifadelerin fonksiyonun kapanış parantezine kadar aktif olduğu bilinmesi gerekmektedir.
Bir alanda hem üst bir kapsama sahip hem de yerel bir değişken varsa üstü kullanmanın bir yolu yoktur. Örnek vermek gerekirse
C’de ömür kavramı 3’e ayrılır;
Atama (ingilizce overwrite ) hayatta olan bir nesneye yapılır. ilk değer verme hayata gelirken aldığı değer olacaktır.
ÖNEMLİ: Stringler yani iki tırnak içinde olan ifadeler C'de static ömürlüdür. Mesela printf(“Hello World”) ifadesi içinde “Hello World” ifadesi static ömürlüdür ve program sonlanana kadar ömrünü sürdürür.
Çöp değer (garbage value) bellekte var olan silinmiş yani üzerine yazılabilir (eski değerlerdir). Otomatik ömürlü değişkenler çöp değerle başlar ve set edilmezse yanlış sonuçlar doğurur. Sonuç olarak otomatik ömürlü değişkenlere değer atamadan kullanmak hatalı olacaktır.
Kısaca otomatik ömürlü değişkenler garbage value ile başlar. Bu yüzden kullanmadan önce set etmek gerekir.
Geçici Nesne:
Çağrılan bir fonksiyon geri dönüş değerini geçici bir değişkene atar. Fonksiyonu çağrında bu değeri bu geçici değişkenden alarak işlem yapar. Ve orada geçici değişken sonlanmaktadır. Fakat fonksiyon çağrıldığında fonksiyon geçici değişkene bir şey göndermez ( bu C ‘de olası bir durumdur ) ise (Programcının hatalı kod yazımından dolayı) bu durumda geçici değişken dinamik ömürlü olduğundan dolayı garbage value değeri üzerinden işlem yapılır ve hatalı sonuçlar oluşabilir.

Bir alanda hem üst bir kapsama sahip hem de yerel bir değişken varsa üstü kullanmanın bir yolu yoktur. Örnek vermek gerekirse

C’de ömür kavramı 3’e ayrılır;
- Statik
- Otomatik
- Dinamik
- Statik Ömür : Hayatını programın başından sonuna kadar sürdürmektedir.
- Otomatik Ömür : Bir kodun yürütülmesi sırasında bellekte kalan kodun çalışması sonlandığında bellekten silinen bir ömür çeşitidir.
- Dinamik Ömür : Programın çalışıp bitmesiyle ilgili bir ömür anlayışı olmayan ne zaman istersek hayata geçen ne zaman istersek hayatı sonlanacaktır.
Atama (ingilizce overwrite ) hayatta olan bir nesneye yapılır. ilk değer verme hayata gelirken aldığı değer olacaktır.
- Global değişkenler Static Ömürlüdür.
- Fonksiyon içinde ve parametre olarak tanımlananlar Otomatik Ömürlüdür.
- Static Ömürlü olan değişkenler ilk değer verilmezse 0 değeri otomatik olarak verilir.
ÖNEMLİ: Stringler yani iki tırnak içinde olan ifadeler C'de static ömürlüdür. Mesela printf(“Hello World”) ifadesi içinde “Hello World” ifadesi static ömürlüdür ve program sonlanana kadar ömrünü sürdürür.
- Program main ile başlar ve main bittiğinde program sonlanır. main içine yazılan değişken program sonuna kadar ömrünü sürdürse de bu o değişkenin static değişken olduğu anlamına GELMEZ.
- Static ömürlü değişkenler hayata main fonksiyonu çağrılmadan gelirler.
- Static ömürlü bir değişkenle static ömürlü olan global değişken birbirinden farklıdır. Static ömürlü değişkenler tanımlandığı alanda kullanılır ve program sonlana kadar saklanır ve o alanda kullanılır fakat global değişkenlerde static’tir ve her yerden erişme imkanı vardır.
Çöp değer (garbage value) bellekte var olan silinmiş yani üzerine yazılabilir (eski değerlerdir). Otomatik ömürlü değişkenler çöp değerle başlar ve set edilmezse yanlış sonuçlar doğurur. Sonuç olarak otomatik ömürlü değişkenlere değer atamadan kullanmak hatalı olacaktır.
Kısaca otomatik ömürlü değişkenler garbage value ile başlar. Bu yüzden kullanmadan önce set etmek gerekir.
Geçici Nesne:
Çağrılan bir fonksiyon geri dönüş değerini geçici bir değişkene atar. Fonksiyonu çağrında bu değeri bu geçici değişkenden alarak işlem yapar. Ve orada geçici değişken sonlanmaktadır. Fakat fonksiyon çağrıldığında fonksiyon geçici değişkene bir şey göndermez ( bu C ‘de olası bir durumdur ) ise (Programcının hatalı kod yazımından dolayı) bu durumda geçici değişken dinamik ömürlü olduğundan dolayı garbage value değeri üzerinden işlem yapılır ve hatalı sonuçlar oluşabilir.
Linkage (Bağlantı)
Birden çok kaynak kullananıldığında, bir öğe yalnızca o andaki kaynak
tarafından biliniyor olabileceği gibi, onu öteki kaynaklar da biliyor olabilir.
auto Değişken Tanımlayıcısı
auto değişken tanımlayıcısı C ile B dili arasında uyum sağlamak amacı ile otomatik değişken bildiriminde kullanılır. C'de otomatik değişkenler LOKAL değişkenler olduğundan, ayrıca auto değişken tanımlayıcı kelimesini kullanmanıza gerek yoktur. Genellikle, bu tanımlayıcı ile C programlarında karşılaşma olanağınız pek yoktur.
extern Değişken Tanımlayıcısı
C dilinde yazılan uzun programlar derleme zamanını çok artıracağı için, genellikle uzun programlar iki veya daha fazla dosyaya bölünerek derlenir. Bu sistemden aynı zamanda farklı amaçlarla kullanılan kodların düzenlenmesi içinde faydalanılır. Bir proje içinde içinde yer alan bu dosyalar tek bir komutla ayrı ayrı derlendikten sonra birleştirilerek tek bir çalışan .exe uzantılı dosya oluşturulur. Bu durumda, bir dosya içinde tanımladığınız global değişkenler diğer dosya içinde tanınmazlar. Eğer bir dosya içinde tanımladığınız global değişkenlerin diğer dosyalar içinde geçerli olmasını isterseniz, diğer dosyalarda yer alan bütün fonksiyonların dışında yaptığınız değişken tanımlamalarının baş tarafına extern ifadesini getirmeniz gerekir. extern ifadesinin kullanılmasını örnekler üzerinde incelemeye çalışalım:
Aşağıda verilen iki dosyayı deneme1.c ve deneme2.c adları ile bir proje içine kaydettikten sonra derleyicinizi kullanarak projeyi derler ve deneme.exe adlı tek bir program adı ile çalıştırırsanız aşağıdaki satırları ekrana yazar:
10 15 10 7
Programda, ilk satırı ekrana yazan deneme2.c, ikinci satırı ekrana yazan ise deneme1.c dosyasındaki işlem satırlarıdır. 1 sayısı ile gösterilen satırda yer alan işlem satırı fonksiyon bildirimi için kullanılmakta olup ilerideki bölümlerde ele alınacaktır.
/* deneme1.c */ int gid1 = 10; void fonk1(void); /* 1 */ main() { int id2; id2 = 7; fonk1(); printf("%d %d", gid1, id2); } /* deneme2.c */ extern int gid1; void fonk1 (void) { int id2; id2 = 15; printf("%d %d", gid1, id2); printf("\n"); }
Kısaca özetlersek, extern değişken tanımlayıcısı, uzun bir program birden fazla dosyaya bölündüğünde, ilk programda kullanılan global bir değişkeni diğer dosyalara tanıtmak için kullanılır.
register Değişken Tanımlayıcısı
Eğer programınızda bir değişkeni çok sık kullanıyorsanız, bu değişken bildiriminin başında register ifadesini kullanmanız programınızın hızını artırır. çünkü, bilgisayar bu şekilde tanımlanan değişkenlere daha hızlı bir şekilde ulaşır. Bunun nedeni, register değişkenlerin Merkezi İşlem Biriminin (CPU) yazmacında saklanmış olmasıdır.
Ancak, CPU'da sınırlı sayıda yazmaç bulunduğu için, eğer register değişken sayısı çok fazla olursa, bilgisayar belli bir sayıdan sonraki register değişkenleri normal değişken olarak kabul eder. Bu tanımlamayı yaptığımızda derleyiciye bu değişkene öncelik tanıyarak, performansı artırması için bellek yerine CPU içinde yer alan yazmaçlara yerleştirmesi konusunda bir istek yapılmış olur. Ama, bu isteğin mutlaka yerine getirileceğine dair bir garanti yoktur. Bu nedenle, çok sık kullanılan değişkenleri register olarak tanımlamak gerekir. Buna örnek olarak, döngüleri kontrol etmekte kullanılan değişkenler gösterilebilir. Bu değişkenler çok sık kullanıldığından programınızın performansı hissedilir ölçüde artacaktır.
Sadece lokal değişkenler ile fonksiyon parametresi olarak bildirimi yapılan değişkenlerin başında register ifadesini kullanabilirsiniz.
Bir register değişken CPU yazmacına yüklendiğinden bellek adresi olmaz. Yani, register bir değişkenin adresini tanımlamak için & işlemcisini kullanamazsınız.
static Değişken Tanımlayıcısı
static değişken tanımlayıcısını lokal ve global değişkenlerle birlikte kullanabilirsiniz. Normal olarak, içinde lokal değişken tanımlanan bir fonksiyonu her çağırmanızda, lokal değişken değeri yenilenir. Ancak, bir fonksiyon içinde static lokal bir değişken tanımladığınızda, fonksiyonu her çağırmanızda lokal değişken bir önceki fonksiyon çağrısındaki en son değerini korur. Sonuç olarak, static lokal bir değişkene sadece fonksiyonun ilk çağrılışında bir defaya mahsus olmak üzere değer verebilirsiniz. static lokal bir değişken kullanılmasını bir örnek üzerinde incelemeye çalışalım:
#include <stdio.h> void fonk1 (void); void fonk2 (void); main() { fonk1(); fonk2(); printf("\n"); fonk1(); fonk2(); printf("\n"); fonk1(); fonk2(); } void fonk1 (void) { int id1 = 1; printf("%d ", id1); id1 = id1 + 5; printf("%d ", id1); } void fonk2 (void) { static int id1 = 0; printf("%d ", id1); id1 = id1 + 9; printf("%d ", id1); }
Yukarıdaki örnekte, program aşağıdaki satırları ekrana yazar:
1 6 0 9 1 6 9 18 1 6 18 27
Program fonk1() ve fonk2() fonksiyonlarını sırasıyla üçer kez çağırarak lokal olarak tanımlanmış değişken değerlerini ekrana yazdırır. Her iki fonksiyonda da lokal değişken değerleri artırılmasına rağmen sadece fonk2() fonksiyonu içindeki id1 değişkeni bir önceki fonksiyon çağrısında aldığı değeri korumaktadır. Bu olanağı sağlayan değişkenin statik tanımlanmış olmasıdır.
static değişken tanımlayıcısını global değişkenlerle kullanabilirsiniz. static global bir değişken tanımladığınızda, bu değişkeni sadece içinde tanımlandığı dosyada bulunan fonksiyonlar kullanabilir. Bunun yanında, aynı programa ait farklı dosyalarda bulunan ve aynı isme sahip biri normal diğeri de static olan iki global değişken tanımlayabilirsiniz. Bu özelliği bir örnek üzerinde incelemeye çalışalım:
Aşağıda verilen iki dosyayı deneme1.c ve deneme2.c adları ile bir proje içine kaydettikten sonra derleyicinizi kullanarak projeyi derler ve deneme.exe adlı tek bir program adı ile çalıştırırsanız aşağıdaki satırları ekrana yazar:
18 24
/* deneme1.c */ #include <stdio.h> void fonk1 (void); void fonk2 (void); static int gid1 = 18; main() { fonk1(); fonk2(); } void fonk1 (void) { printf("%d ", gid1); } /* deneme2.c */ #include <stdio.h> int gid1 = 24; void fonk2 (void) { printf("%d", gid1); }
Program, her iki dosyada gid1 adlı birer adet global değişken tanımlar. Aynı isme sahip 2 değişken olduğu halde deneme1.c dosyasındaki değişkenin static olarak tanımlanması farklı 2 değişken olarak algılanmalarını sağlar.
const ve volatile Değişken Tanımlayıcıları
C'de, değişken bildirimlerinin başında kullanılan const ve volatile tanımlayıcıları ile değişkenlere farklı özellikler kazandırabilirsiniz. Eğer değişken bildiriminin başına const ifadesini getirirseniz, program değişkenin değerini hiç bir şekilde değiştiremez. const değişkenlere bir ilk değer verilebilir.
Şimdi, const tanımlayıcısının kullanılmasını bir örnekle incelemeye çalışalım:
/* Bu program derleyici tarafından derlenmez. */
#include <stdio.h>
main()
{
const int id1 = 1;
id1 = 7;
printf("%d ", id1);
}
Yukarıdaki programı derlemeye çalıştığınızda hata verir. Çünkü, const olarak tanımlanmış bir değişken değeri değiştirilemez.
Eğer bir değişken bildiriminin başına volatile ifadesini getirirseniz, bu değişken değerini program içinde herhangi bir şekilde değiştirmeniz mümkündür. volatile ifadesi const ifadesinin yaptığı işlemin tersini yapar.
Etiketler:
auto,
Bilinirlik Alanı,
C,
const,
değişken tanımlayıcıları,
extern,
Menzil,
Ömür,
register,
Scope,
static,
Storage,
Storage Duration
C Dilinde Operatör Öncelikleri
SEVİYE |
OPERATÖR |
TANIM |
ÖNCELİK YÖNÜ |
1
|
(
)
|
öncelik
kazandırma ve fonksiyon çağırma
|
soldan
sağa
|
[
]
|
index
operatörü (subscript)
|
||
.
|
yapı
elemanına ulaşım (structure access)
|
||
->
|
yapı
elemanına gösterici ile ulaşım
|
||
2
|
+
|
işaret
operatörü (unary)
|
sağdan
sola
|
-
|
işaret
operatörü (unary)
|
||
++
|
1
artırma (increment)
|
||
--
|
1
eksiltme (decrement)
|
||
~
|
bitsel
değil (bitwise not)
|
||
!
|
mantıksal
değil (logical not)
|
||
*
|
içerik
operatörü (indirection)
|
||
&
|
adres
operatörü (address of)
|
||
sizeof
|
sizeof
operatörü
|
||
(tür)
|
tür
dönüştürme (type cast operator)
|
||
3
|
*
|
çarpma
(multiplication)
|
soldan
sağa
|
/
|
bölme
(division)
|
||
%
|
modulus
(bölümden kalan)
|
||
4
|
+
|
toplama
(addition)
|
soldan
sağa
|
-
|
çıkarma
(suntraction)
|
||
5
|
<<
|
bitsel
sola kaydırma (bitwise shift left)
|
soldan
sağa
|
>>
|
bitsel
saga kaydırma (bitwise shift right)
|
||
6
|
<
|
küçüktür
(less than)
|
soldan
sağa
|
>
|
büyüktür
(greater than)
|
||
<=
|
küçük
eşittir (less than or equal)
|
||
>=
|
büyük
eşittir (greater than or equal)
|
||
7
|
==
|
eşittir
(equal)
|
soldan
sağa
|
!=
|
eşit
değildir (not equal to)
|
||
8
|
&
|
bitsel
VE (bitwise AND)
|
soldan
sağa
|
9
|
^
|
bitsel
EXOR (bitwise EXOR)
|
soldan
sağa
|
10
|
|
|
bitsel
VEYA (bitwise OR)
|
soldan
sağa
|
11
|
&&
|
mantıksal
VE (logical AND)
|
soldan
sağa
|
12
|
||
|
mantıksal
VEYA (logical OR)
|
soldan
sağa
|
13
|
?:
|
koşul
operatörü (conditional operator)
|
sağdan
sola
|
14
|
=
|
atama
(assignement)
|
sağdan
sola
|
+=
|
işlemli
atama (assignment addition)
|
||
-=
|
işlemli
atama (assignment subtraction)
|
||
*=
|
işlemli
atama (assignment multiplication)
|
||
/=
|
işlemli
atama (assignment division)
|
||
%=
|
işlemli
atama (assignment modulus)
|
||
<<=
|
işlemli
atama (assignment shift left)
|
||
>>=
|
işlemli
atama (assignment shift right)
|
||
&=
|
işlemli
atama (assignment bitwise AND)
|
||
|=
|
işlemli
atama (assignment bitwise OR)
|
||
^=
|
işlemli
atama (assignment bitwise EXOR)
|
||
15
|
,
|
virgül
operatörü (comma)
|
Kaydol:
Kayıtlar (Atom)