C Değişkenlerine Giriş ve Bellek Kavramı

C programlama dili ile ilgili en temel bilgileri öğrenmiş olduk. Bu bölümde birçok programlama dilinde önemli bir yere sahip olan değişken kavramını inceleyeceğiz. Tabii ki bu kavramı incelerken bilgisayar belleğinde neler döndüğünü de basit bir şekilde açıklamaya çalışacağım. Her şeyden önce kullanıcıdan iki sayı alan ve aldığı sayıların toplamını ekrana basan bir program ile başlayalım.

// Code 1.4.1: Code1_4_1.c
// Toplama programı
#include <stdio.h>

// main fonksiyonu programı başlatır
int main(void)
{
    int integer1; // Kullanıcı tarafından girilecek olan ilk sayı
    int integer2; // Kullanıcı tarafından girilecek olan ikinci sayı
    int sum; // Toplam değerinin tutulacağı değişken

    printf("Ilk sayiyi girin: "); // Ekrana basılan istem(prompt)
    scanf("%d", &integer1); // Kullanıcıdan bir tamsayı değeri oku

    printf("Ikinci sayiyi girin: "); // Ekrana basılan istem(prompt)
    scanf("%d", &integer2); // Kullanıcıdan bir tamsayı değeri oku

    sum = integer1 + integer2; // Toplama işlemini yap ve "sum" değişkenine ata

    printf("Toplam: %d", sum) // Toplamı ekrana bas
} // main fonksiyonunun sonu

Bu programı çalıştırdığımızda ve gereken yerlerde girdi (input) girdiğimizde karşımıza şöyle bir sonuç çıkar (burada koyu yazılan kısımlar bizim girdiğimiz verileri göstermektedir):

ÇIKTI
Ilk sayiyi girin: 48
Ikinci sayiyi girin: 60
Toplam: 108

Bu sefer yazmış olduğumuz programın geçen bölümdekinden farkı, bu programın kullanıcıdan girdi alabilmesi ve belli başlı işlemler yapabilmesidir. Yorum satırlarına aşina olmak için onları tekrar inceleyebilir, hatta siz de kendi örneklerinizi yaparken yorum satırı kullanmaya özen gösterebilirsiniz. Şu noktadan sonra onlarla ilgili daha fazla açıklama yapmayacağım. #include önişlemci bildirimini ve main fonksiyonunu da daha önceki bölümde zaten görmüştük. Burada karşımıza çıkan ve bizim için yeni olan şeyler değişkenlerdir. Peki nedir bu değişkenler?

Değişken Kavramı

Değişken (Variable), bir programda bilgisayarın geçici belleğinde (RAM) saklanan verileri elde etmek ve depolamak için, o bellek bölgesini belirten isimli bir nesnedir. Elbette RAM’de saklanan bilgiler sadece ikilik sistemde tutulan verilerden ibarettir. Bu verilerin program içinde yorumlanabilmesi için, boyutlarının da bilinmesi gerekir. Bu nedenle değişkenlerin tür (type) adı verilen başka bir özelliğinin olması gerekir. Tür, değişkenlerin bellekte nasıl yerleşeceğini ve nasıl yorumlanacağını belirten bir özelliktir. Bu şekilde bu tür bilgisine göre bellekte veriler saklanır ve yine bu tür bilgisine göre okunur. C’de basit bir değiken bildirimi şu şekilde yapılmaktadır:

int integer1;

Yukarıdaki örnekte de gördüğünüz gibi değişkenler önce tür, daha sonra da isim bilgisi girilerek bildirilirler. Buradaki int kelimesi C’de yer alan ve tür bildiren özel bir kelimedir. Bu tür kelimelere C’de anahtar kelime (keyword) adı verilir. Buna birazdan değineceğim. Veri türleriyle ilgili konuları ve diğer anahtar kelimeleri ise başka yazılarda ayrıntılı olarak ele alacağım. Şimdi değişken isimlendirmesi ve onun kuralları hakkında biraz konuşalım.

Tanımlayıcılar

Az önceki örnekte integer1 isimli bir değişken bildirmiştik. İşte bir programlama dilinde "X isimli değişken", "Y isimli fonksiyon", "Z isimli yapı" gibi ifadeler kullanırken bazı isimler söylememiz gerekir. C programlama dilinde nesneleri tanımlayan bu isimlere tanımlayıcı (identifier) adı verilmektedir. Tanımlayıcılar değişkenleri, fonksiyonları ve daha birçok özelliği C programlama dilinde kullanabilmek için onları tanımlayan isimlerdir. Elbette bu isimlerin belli başlı kuralları bulunmaktadır. C dilinde tanımlayıcılara ait olan belli başlı kurallar şunlarıdır:

  • Tanımlayıcılar İngilizce (küçük ve büyük) harflerden (a-z, A-Z), rakamlardan (0-9) ve alt çizgiden (_) meydana gelebilir. Bunun dışında Türkçe harfleri, diğer özel karakterleri ve boşluk karakterlerini içeremezler. Ayrıca tanımlayıcılar rakam ile başlayamaz. Harf veya alt çizgi ile başlamak zorundadırlar. (Alt çizgi ile başlama, derleyici tarafından oluşturulan tanımlayıcılarla çakışabilmesi ihtimaline karşı pek tercih edilmez.)
  • C dili büyük-küçük harf duyarlılığı olan (case-sensitive) bir dildir. Mustafa ismi ile mustafa ismi birbirlerinden tamamen farklı şeyleri ifade edebilir. Bu nedenle tanımlayıcılar ve C diline özel birçok anahtar kelimenin yazımında büyük-küçük harf ayrımına dikkat edilmelidir.
  • İleride bahsedeceğimiz C diline özel anahtar kelimeler tanımlayıcı olarak kullanılamaz.
  • Tanımlayıcılar en fazla 31 karakterden oluşabilir. 31 karakterden uzun tanımlayıcıların ilk 31 karakteri işleme alınmaktadır. Bazı derleyici implementasyonlarında bundan daha fazlası yazılabilse de taşınailirlik açısından tavsiye edilmemektedir.

Şimdi geçerli ve geçersiz tanımlayıcı ismlerine örnekler verelim:

Tanımlayıcı Geçerlilik
sayi1 Geçerli
12ay Geçersiz
mustafa_yemural Geçerli
m€hm€t Geçersiz
çağlar Geçersiz
mutlu birey Geçersiz
_test Geçerli

Bildirim ve Tanımlama

C’de değişkenler, fonksiyonlar, yapılar gibi bileşenlerin derleyiciye var olduklarının bildirilmesi ile onların bellekte çalışma zamanında yer kaplamaları farklı anlamlara gelir. Örneğin siz bir C kaynak kodunda bir değişkeni sadece var olduğunu bildirmek için yazmış olabilirsiniz. Daha sonra başka bir kaynak kodunda bu değişkenin tanımını yazacak ve bu şekilde bağlama aşamasında onun tanımını ve bildirimini birleştirmiş olacaksınız. İşte değişkenleri derleyiciye tanıtmak amacıyla türü ile birlikte yazmaya bildirim (declaration) adı verilmektedir.

Değişkenlere değer vererek onların bellekte yer kaplamasını sağlamaya ise tanımlama (definition) adı verilmektedir. Bunu en basit haliyle şu şekilde düşünebilirsiniz:

int integer1; // Bildirim
int integer2 = 5; // Tanımlama

Ancak C dilinde bu işler her zaman bu kadar kolay değildir. C dilinde bir değişkeni herhangi bir değer vermeden de yazsanız, onu tanımlamış olursunuz. Yani burada integer1 ve integer2 isimli değişkenlerin hem bildirimi hem de tanımı yer almaktadır. Bu iki kavramı yer yer birbirlerinin yerine kullanabilirsiniz. Peki ilk anlattığım örnekteki gibi durumlar mümkün müdür? Yani bir kaynak kodda değişkenin bildirimini, diğerinde ise değişkenin tanımını yapmanın olanağı var mıdır? Elbette vardır. Ancak bu konu biraz daha ileride ele alınacaktır. Şimdilik bildirim ve tanımlama kelimelerini birbirlerinin yerine kullanabilirsiniz.

C’de bir değişkeni en basit şekilde şöyle bildirebilirsiniz veya tanımlayabilirsiniz:

<Değişken Türü> <Değişken Adı>;

Yukarıdaki ilk örneğimizde yer alan şu satırlar değişken bildirimlerine örnektir:

int integer1; // Kullanıcı tarafından girilecek olan ilk sayı
int integer2; // Kullanıcı tarafından girilecek olan ikinci sayı
int sum; // Toplam değerinin tutulacağı değişken

Değişken adları daha önce bahsettiğimiz tanımlayıcı kurallarına uygun olarak verilmelidir. Bildirim bittikten sonra noktalı virgül koymayı unutmamak gerekir. Değişkenlere ilk değer atayarak da onları bildirmek mümkündür. Bunu şu formda yapabilirsiniz:

<Değişken Türü> <Değişken Adı> = <İlk Değer>;

Örnekler:

int test1 = 5;
int test2 = 15;
double test3 = 56.7;

Değişkenlerin Bellekte Yerleşimi

C’de değişkenlerin aslında bir bellek bölgesini gösteren isimlerden ibaret olduğunu söylemiştik. Şimdi de çok ayrıntıya girmeden bu bellek konusunu biraz daha açalım. Değişkenler bellek bölgesinde bir alanı belirttiğinden, onların tür bilgileri ve bu tür bilgilerinin de önceden belirlenmiş boyutlarının olması kaçınılmazdır. Değişkenlerin ismi ise o bellek bölgesine erişimi sağlayan adresi elde etmemize yarayan bir araçtır. Bir de değişkenlere verilen değerler (value) vardır ki bu da o bellek bölgesinde tutulan değerlere karşılık gelir.

Bilgisayarlarımızda buluan RAM, yazdığımız programları çalıştırdığımızda bu programların yüklendiği yerdir. Program içinde tanımlanmış olan değişkenler de RAM’de işletim sisteminin (veya yükleyici programın diyelim) belirlediği bir adreste tutulurlar. RAM’i değişkenlerin tutulduğu bir blok yapısı gibi düşünürsek, programımızda tanımladığımız integer1 ve integer2 isimli değişkenler için bellekte şöyle bir yer ayırma olacaktır:

Değişkenlerin bellekte saklanması
Figür 1: Değişkenlerin bellekte saklanması

Buradaki 45 ve 72 değerlerinin kullanıcı tarafından girildiğini varsayıyoruz. Burada ayrıntılı olarak adres kavramından bahsetmek istemiyorum. Veri tipi, yani değişkenlerin türünden ise yakın bir bölümde ayrıntılı olarak bahsedeceğim. Şu an sadece tanımlanan değişkenlerin ve değerlerinin bellekte bu şekilde tutulduğunu bilin yeter. Şimdi de programımızı satır satır çalıştırdığımızda bellekte ne gibi değişikliklerin olduğunu görelim:

Satır satır bellek değişimi
Figür 2: Satır satır bellek değişimi

Yukarıdaki resimde koyu gri bölgeler RAM’deki bellek hücrelerini temsil etmektedir. Şimdilik bu bellek hücrelerinin her birinde bir değişken saklanabileceğini varsayalım. 7. satıra kadar bellekte herhangi bir değişiklik olmaz (main fonksiyonunun içerisindeki değişikliklerden bahsediyorum). 8, 9 ve 10. satırlarda sırasıyla integer1, integer2 ve sum değişkenleri belleğe yerleştirilir. Burada değer verilmeden tanımlanan yerel değişkenler (yerel ve global değişkenleri ileride ayrıntılı bir biçimde inceleyeceğiz) için bir not bırakalım; herhangi bir ilk değer verilmeyen yerel değişkenlere çalışma zamanında belirsiz bir değer ile (indeterminate value) ilk değer verilir.

Değişkenlerimiz bellekte yerini aldıktan sonra 13. satırda kullanıcıdan bir girdi aldık ve aldığımız girdinin 45 olduğunu varsaydık. 13. satırdan sonra artık integer1 değişkeni 45 değerini tutmaktadır. Aynı işlem 16. satırda da olmaktadır. 18. satıra gelindiğinde ise bir sonraki bölümde ayrıntılı olarak göreceğimiz aritmetik bir işlem yapılmakta ve sonuç sum değişkenine atanmaktadır. Bu atama işleminin sonucu sum değişkeninin değeri 105 olmaktadır. Programın ilerleyen aşamalarında sum = 90; gibi bir satır eklersek, o andan itibaren sum değişkeninin değeri değişip 90 olacaktır. İşte değişkenlerin bellek üzerinde bütün çalışma mekanizmaları bu şekildedir.

C’de Girdi/Çıktı İşlemlerine Genel Bakış

Örnek kodun geri kalanında kullanıcıdan girdi alma ve ekrana çıktı verme işlemlerinin yapıldığını görmekteyiz. Bu işlemlerin C’de en temel düzeyde nasıl yapıldığından biraz bahsedelim. Öncelikle ekrana çıktı verme ile başlayalım. C’de ekrana çıktı vermek için en sık kullanılan fonksiyon printf fonksiyonudur. Bunu zaten önceki bölümde de görmüştük. Bizim örneğimizde ise kullanıcının tam olarak neyi ekrana girmesi gerektiğini ona anlatmak için bu fonksiyonu kullanarak ekrana bilgi metinleri yazdırıyoruz. Daha sonra yine sonucu ekrana basmak için printf fonksiyonunu kullanıyoruz:

printf("Toplam: %d", sum) // Toplamı ekrana bas

Buradaki kullanımda farklı olan şeyler String içerisinde "%" karakterini kullanmamız ve fonksiyona ekstra bir argüman daha vermemizdir. Bu fonksiyon aslında birden fazla argüman alabilen bir fonksiyondur. Bu da demek oluyor ki bu fonksiyon ile farklı türden birçok değişkeni ekrana aynı anda yazdırabiliriz. Ancak bunu yapmak için de String içerisindeki "%" karakterine ihtiyaç duyarız. Elbette "%" karakterinden sonra gelen karakterler, ekrana basacağınız değişkenin türünü belirtmek ve ona göre formatlı çıktı vermek için kullanılmaktadır. Bu açıklamadan da anlayacağınız üzere aslında printf fonksiyon ismindeki "f" harfi "format" anlamına gelmektedir.

String içerisinde kullanılan bu "%" işaretine C’de format belirteci (format specifier) adı verilir. Format belirteçleri bu gibi fonksiyonların String kısımlarında yazdırılacak değişkenin türünü ve konumunu belirtmek amacıyla kullanılırlar. Örneğin burada kullandığımız "d" harfi, değişkenin bir tamsayı olarak ekrana basılacağını belirtmektedir. Format belirteçlerinin birçok farklı çeşiti ve özelliği bulunmaktadır. İleride bu konu daha detaylı bir şekilde ele alınacaktır. Şimdilik tamsayı yazdırmayla ilgili birkaç örnek gösterelim. Örneğin elimizde değeri 10 olan x değişkeni ve değeri 20 olan y değişkeni olsun:

printf("X'in degeri: %d", x);
ÇIKTI
X’in degeri: 10
printf("Y degiskeni %d degerine sahiptir.", y);
ÇIKTI
Y degiskeni 20 degerine sahiptir.
printf("X = %d, Y = %d", x, y);
ÇIKTI
X = 10, Y = 20

Son örnekte gördüğünüz gibi printf fonksiyonu ilk parametresindeki String’in içerisindeki "%" ile başlayan karakter dizisi kadar argüman alabilir. Son örnekte iki adet "%" ile başlayan karakter dizisi bulunduğundan, String’e ek olarak iki argüman daha yazılmıştır. Yine parametrelerdeki ifadelerin değerlerinin atanma işleminin soldan sağa doğru yapıldığını da örnekten görebilirsiniz.

Şimdi de scanf fonksiyonunu inceleyelim. Bu fonksiyon kullanıcıdan bir (veya birkaç) veri alıp bunu değişkene (veya değişkenlere) atama işlemini gerçekleştirmektedir. Örneğimizdeki kullanımlarda yine ilk argümanda String ve onun içerisinde de bir format belirteci görmekteyiz. Bu belirteç, kullanıcıdan alınan verinin nasıl işlenip değişkene yazdırılacağını belirtir. Burada kullanıcıdan alınan değerin tamsayı olarak alınmaya zorlanacağı ve bir sonraki argümanda yer alan değişkene yazılacağı belirtilmektedir.

Burada dikkat edilmesi gereken konu, ikinci ve sonraki argümanlara yazılan değişkenlerin başına ampersand (&) işaretinin konulmasının unutulmamasıdır. Bu işaret adres operatörünü belirtir ve ileride göreceğimiz işaretçiler (pointers) ile ilgili bir konudur. Şimdilik scanf kullanırken bunun konulmasına dikkat etmeniz yeterlidir. Program scanf kullanılan satırlara geldiğinde durur ve kullanıcıdan bir girdi bekler. Kullanıcı bir şeyler girip Enter tuşuna bastığında, veri belirtilen değişkene belirtilen formatta yazılır ve program çalışmaya devam eder. Yine scanf fonksiyonunun detaylarına ileride değineceğiz.

Anahtar Kelimeler

Son olarak da az önce bahsettğimiz anahtar kelime kavramına değinelim. Anahtar kelimeler (keywords), bir programlama dilinde özel anlamlara gelen kelimelerdir. Bu nedenle kullanıcılar tarafından verilen isimlerde bu kelimeler kullanılamaz. C dilinde de pek çok özel işlevi olan anahtar kelimeler mevcuttur. Bu kelimelerin her birinin bir görevi vardır. İlk C standartlarında yer alan ve daha sonradan C99 ve C11 standartlarıyla da eklenen, ayrıca C23 standartları ile de eklenecek olan anahtar kelimeleri şu şekilde gösterebiliriz.

Anahtar Kelimeler
auto break case char const
continue default do double else
enum extern float for goto
if int long register return
short signed sizeof static struct
switch typedef union unsigned void
volatile while
C99 ile Eklenen Anahtar Kelimeler
_Bool _Complex _Imaginary inline restrict
C11 ile Eklenen Anahtar Kelimeler
_Alignas _Alignof _Atomic _Generic _Noreturn
_Static_assert _Thread_local
C23 ile Eklenecek Anahtar Kelimeler
alignas alignof bool constexpr false
nullptr static_assert thread_local true typeof
typeof_unqual _BitInt _Decimal32 _Decimal64 _Decimal128

Görüldüğü gibi genel anlamda varolan anahtar kelimelerin hepsi küçük harflidir. Daha sonradan eklenen anahtar kelimeler ise "_" karakteri ile başlamaktadır. Bu anahtar kelimelerin ne işe yaradığını ilerleyen bölümlerdeki konularda göreceksiniz. C23 anahtar kelimeleri ile ilgili küçük bir not: _Alignas, _Alignof, _Bool, _Static_assert ve _Thread_local anahtar kelimeleri C23 standartları ile dilden kaldırılıp yerlerine alt tire ile başlamayan küçük harfli formatlarının getirilmesi planlanmaktadır.

Bu bölümün çok uzun olduğunun farkındayım. Fakat burada gördükleriniz C dilini ve programlamayı anlamak için sahip olmanız gereken en temel bilgilerdendir. Bu bilgilerin çoğu sadece C programlama dilinde değil, diğer dillerde de karşınıza çıkacaktır. Bu nedenle bu temel kavramları bilmeniz sizin açınızdan oldukça sağlam bir başlangıç olacaktır. Bir sonraki bölüm de programlama dillerinde kullanılan artimetik işlemlerin nasıl yapıldığını anlamak açısından oldukça önemli olacaktır.

5 6 votes
Article Rating
Subscribe
Bildir
guest

3 Yorum
Eskiler
En Yeniler Beğenilenler
mehmet

Diline beynine ve yazına sağlık.

Emre

Thank you for your work

Ahmet

Paylaştığınız bilgiler için teşekkür ediyorum.