C Programlamada Structure – Yapılar

Herkese selamlar bu yazımda C Programlama Dilinde önemli bir yeri olan Struct yapıları hakkında bildiklerimi yazmak istiyorum. Yapıları kullanarak farklı tipteki verileri (int,char) aralarında belirli bir ilişki bulunmak şartıyla birarada tutabiliyoruz. Bir öğrencinin bilgilerini ele alırsak, adı soyadı, numarası, yaşı vs. gibi bilgiler birbiri ile ilişkili olduğundan hepsini belirli bir yapı altında kullanmak oldukça mantıklı değil mi ?

Aslında mantıksal olarak dizilere oldukça benziyen bu yapılar, dizilerin biraz daha gelişmiş versiyonu diyebiliriz. Öyle ki, dizilerde aynı tipten verileri bellekte sürekli bir şekilde saklıyabiliyorken, yapılarda farklı tipten verileri de sürekli bir şekilde saklayabiliyoruz. Bu yazdıklarımı bir giriş olarak kabul edersek, yapıların bildirimleri ve değişkenlerinin tanımlanması ile devam edelim.

Struct Bildirimleri ve Değişkenlerinin Tanımlanması

struct tarih {
   int gun;
   int ay;
   int yil;
};

Burada tarih adlı bir yapı oluşturduk. Bu yapının içinde yapıyı oluşturan değişkenler (yapı elemanları) bulunmaktadır. Dikkat edilmesi gereken nokta ise şudur : bu kod ile sadece struct bildirimi yapılır, yani bellekte şu an bu yapı için herhangi bir yer ayrılmamıştır. Bunu fonksiyonların prototiplerine benzetebiliriz. Yapmış olduğumuz bildirim ile ancak derleyiciyi bilgilendirmiş oluruz. Bellekte yer ayırma işlemi ise yapı türünden değişkenlerin tanımlanmasıyla olur. Burada bahsettiğim değişkenler, yapıyı oluşturan değişkenler ile karıştırılmamlıdır. Bir örnekle açıklarsak :

struct tarih {
   int gun;
   int ay;
   int yil;
};
struct tarih dogum;

Gördüğünüz gibi yapıyı bildirdikten sonra yapı değişkenini tanımladık. Bu şekilde bellekte 12 bytelık  bir yer tahsis edilmiş oldu. Dikkat ettiyseniz yapı değişkeninin tanımını yapı bildirimi yaptıktan sonra yaptık. Fakat ikisini beraber yapmamız da mümkün.

struct tarih {
   int gun;
   int ay;
   int yil;
} dogum,olum;

Yapı değişkenlerini birbirine atamak da mümkündür. Ancak farklı bir yapıdan değişkeni gelip tarih yapısından herhangi bir değişkene atayamazsınız.

dogum = olum ataması yapmak doğru olacaktır.

Yapının bildirimini nerede yaptığınız önemlidir. Yapı bildirimini global olarak yaparsanız, yapıya ait değişken tanımını istediğiniz yerde yapabilirsiniz. (main içinde, oluşturduğunuz bir fonksiyonun içinde vs.) Eğer bildirimi local olarak yapmışsanız, yapı değişkenini kullanacağınız yerde kısıtlanmış olur.

Oluşturduğunuz yapıların bellekte ne kadar yer tutacağını öğrenmeniz de mümkün, bunun için sizeof fonksiyonundan yararlanabilirsiniz.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct tarih {
   int gun;
   int ay;
   int yil;
} dogum;
int main() {
   int x = sizeof(dogum);
   int y = sizeof(struct tarih);
   printf("Yapinin bellekte byte olarak kapladigi alan  ---> %d",x);
   printf("\nYapinin bellekte byte olarak kapladigi alan  ---> %d",y);
   getch();
}

Yapı bildirimleri ve değişkenlerini gördükten sonra bir de yapıyı oluşturan değişkenlere ilk değer atamasının yapılışına bakalım.

struct tarih {
   int gun;
   int ay;
   int yil;
} dogum = {22,12,1991};

Bu kod ile yapıyı oluşturan değişkenlerden ilki olan gun içine 22 değeri, ay içine 12 değeri ve yil içine 1991 değeri yerleştirilir. Yazının başında yapı elemanlarını, bellekte sürekli bir şekilde bulundukları için dizilere benzetmiştim. Bellekte nasıl dizildiklerini biraz daha kurcalarsak :

Şekilde görüldüğü gibi sıralı bir şekilde belleğe yerleşmektedirler. Burada bütün değişkenler int olmak zorunda değildir, mesela int yil yerine long yil gibi bir değişken tanımı yapılabilir, bellekte ise bu değişken için 8 byte yer ayrılır.

Sormaya başlamışsınızdır : iyi güzel de arkadaşım biz bunlara nasıl ulaşıp değiştiricez ?

Yapı Elemanlarına Erişim ve Nokta (.) Operatörü

Nokta operatörü soluna ve sağına operandlar almaktadır. Hemen bir örnek ile göstereyim :

struct tarih {
   int gun, yil, ay;
} dogum;
dogum.gun = 22;
dogum.ay = 12;
dogum.yil = 1991;

Nokta operatörünün sol tarafında yapı türünden bir değişken ve sağ tarafında ise yapının bir elemanı bulunmak zorundadır. Bu şekilde yapı elemanlarına erişilebilmektedir.

Yapı elemanlarını oluştururken şu ana kadar değişken tipi olarak hep integer (int) kullandım. Fakat integer dışında char, float, double veya pointer’da kullanılabilmektedir.

Yapı Elemanları Olarak Diziler ve Pointerlar

struct ogr {
   char ad_soyad[25];
   int yas;
   int no;
   char *ptr;
} ogrenci;

Yapı elemanı olarak dizi ve pointerlar yukarıdaki gibi tanımlanabilirler. Öğrencinin yaşına erişmek istediğimiz zaman ogrenci.yas yazmamız yeterliydi. Fakat öğrencinin ad soyadına ulaşmak istediğimiz zaman ogrenci.ad_soyad yazmak yeterli olmayacaktır. Çünkü ogrenci.ad_soyad bir nesne değildir, sadece bir adrestir. ogrenci.ad_soyad[0] dediğimiz zaman bu adresteki bellek bölgesini işaret etmiş oluyoruz, dolayısıyla öğrencinin adını ve soyadını ancak bu şekilde girebiliyoruz.

Pointer kullanırken ise dikkat edilmesi gereken, oluşturulan pointerın güvenli bir bölgeyi işaret etmemesidir. Pointera bir adres tanımlamak için malloc fonksiyonu kullanılabilir.

Yapı Pointerları

struct ogrenci {
   char a;
   int b;
} x,*p;

Yukarıda yapı pointerının nasıl tanımlanacağı gösterilmiştir.

(*p).a gibi bir ifadenin x.a’dan aslında hiçbir farkı yoktur. Tam bu noktada sizlere ok operatörünü (->) tanıtmak istiyorum. Bu operatör ile (*p).a yazmak yerin p->a yazabiliyoruz. İkisi aynı anlamı taşıyor. Fakat x->a yazarsak derleyici hata verir, bu mümkün değil. -> operatörünü ancak yapı pointerları ile kullanabiliriz.

Yapıların Fonksiyonlara Parametre Olarak Geçirilmesi

Herhangi bir fonksiyona parametre gönderdiğinizde, göndermiş olduğnuzu parametre fonksiyonun prototipinde belirttiğiniz değişkene atanır, bu bir çeşit kopyalama işlemi gibidir. Gönderdiğiniz değişken yapı türünden olunca da değişen hiçbirşey olmuyor, fakat göndermiş olduğunuz yapı türünden değişkeni alacak olana fonksiyonun prototipindeki değişken de yapı türünden olmalıdır. (Biraz ağır bir cümle olmuş olabilir, kusura bakmayın :) ) Dilerseniz aşağıdaki örneği inceleyebilirsiniz.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct ogrenci {
   int gun,ay,yil;
} dogum;
f(struct ogrenci d) {
   printf("%d %d %d",d.gun,d.ay,d.yil);
}
int main() {
   dogum.gun = 22;
   dogum.ay = 12;
   dogum.yil = 1991;
   f(dogum);
   getch();
}

Bu aktarım biçimi, yani değişkenlerin kopyalanma işlemleri büyük yapılar için sıkıntı yaratacaktır ve verimsiz bir durum oluşacaktır. Dolayısıyla kopyalama yapmak yerine adres göndermek daha mantıklı olacaktır. Bunu yapabilmemizi sağlayan, verilerin bellekte sürekli bir biçimde yerleşmiş olmasıdır. Yukarıdaki örneğin bir de adres gönderilerek yapılmış haline bakınız :

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct ogrenci {
   int gun,ay,yil;
} dogum;
f(struct ogrenci *d) {
   printf("%d %d %d",d->gun,d->ay,d->yil);
}
int main() {
   dogum.gun = 22;
   dogum.ay = 12;
   dogum.yil = 1991;
   f(&dogum);
   getch();
}

Burada gönderilen değer adres olduğundan fonksiyonun prototipinde de yapı göstericisi bulunmaktadır. İşin içinde yapı göstericisi olduğu için (.) operatörü yerine (->) operatörü kullanılmıştır.

Yapı Değişkenleri Olarak Diziler

Bir öğrenci topluluğu olduğunu varsayınız, bu öğrencilerin her birinin isim, yaş ve numara bilgilerini birarada tutmak isteyebilirsiniz. Bunun için yapı değişkenlerini dizi olarak kullanmamız gerekiyor. Aşağıdaki örneği inceleyiniz.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
struct ogrenciler {
   char ad[20];
   int yas;
   int no;
} ogrenci[10];
int main() {
   ogrenci[0].yas = 20;
   ogrenci[3].no = 10910;
   printf("1. Ogrencinin Yasi ---> %d",ogrenci[0].yas);
   printf("\n4. Ogrencinin Numarasi ---> %d",ogrenci[3].no);
   getch();
}

ogrenci[10] ile 10 adet yapı değişkeni tanımlamış oldum. Bellekte bunun için ayrılan bölge ise 280 byte olacaktır.

Oldukça uzun bir yazı oldu, bazı püf noktaları yazmaya çalıştım. Umarım okurken sıkılmamışsınızdır.

Benzer Yazılar

Yorumlar

Yorum Yazın

Su elementleri kullanabilirsiniz : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Arama
RSS
Beni yukari isinla