Ana sayfa > Programlama > C++ Programlama > Yapılar (Structures)

Yapılar (Structures)

► Detaylı anlatım

Daha önce, aynı türden olan verileri diziler içinde tanımladıktan sonra, sadece bir dizi ismini kullanarak bu verilere erişim sağladığımızı gördük. Türleri farklı olan verileri tek bir isim altında toplayabilmemiz için ise, yapı (structure) adı verilen kullanıcı tanımlı veri türlerini kullanabiliriz.

Yapı, farklı veri türlerini bir grup altında toplayan kullanıcı tanımlı bir veri türüdür. İki veya daha fazla elemandan oluşur. Bir yapı içindeki bütün veri tipleri aynı olabileceği gibi, her veri türü birbirinden farklı da olabilir.

Yapı bildirimi

Yapıları tanımlamak için aşağıda gösterilen üç yöntemden birini kullanabiliriz::


// 1. Veri yapısı ve değişkenleri birlikte tanımlama
struct adı {
   veri-türü eleman1;
   veri-türü eleman2;
   .
   .
   .
   veri-türü elemanN;
} değişken-listesi;

// 2. Veri yapısı ve değişkenleri ayrı ayrı tanımlama
struct adı {
   veri-türü eleman1;
   veri-türü eleman2;
   .
   .
   .
   veri-türü elemanN;
} 

// struct adı değişken;
3. Yapı adı kullanmadan sadece değişken kullanarak yapı tanımlama

struct {
   veri-türü eleman1;
   veri-türü eleman2;
   .
   .
   .
   veri-türü elemanN;
} değişken-listesi;

Yapı bildiriminde, adı veya değişken-listesi ifadelerinden birisi mutlaka tanımlanmış olmalıdır. Yukarıdaki her üç yöntemde de, bu kural uygulanmaktadır.

Yukarıda görülen struct kelimesi bir yapı tanımlar. adı ifadesi ise yapının adını göstermektedir. veri-türü ifadesi C++'da kullanılan herhangi bir veri türünü gösterir. değişken-listesi ifadesi yapı için tanımlanan değişkenleri göstermektedir.

Yukarıda kullanılan yapı tanımlama yönteminin ilkinde yapı ve yapı değişken değerleri birlikte tanımlanır. İkinci yöntemde, önce yapı daha sonra yapı değişken değeri tanımlanmaktadır. Üçüncü yöntemde ise, yapı adı kullanmadan sadece değişken adı kullanarak yapı tanımlanmaktadır. Her üç yöntem de aynı sonucu vermektedir.

Eğer sadece adı ifadesi kullanılırsa, veri türünün sadece yapısı oluşturulmuş olur. Değişken bildirimi ayrıca yapılmalıdır.

Bir yapı içinde yer alan bölümlere eleman veya alan adı verilir.

Bir yapı içindeki veriler birbiri ile mantıksal olarak ilişkilidir:


struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
} yd;

Yukarıdaki ifadeler, dört adedi karakter dizisi ve bir adedi int bir değer olmak üzere toplam beş elemandan oluşan yap adlı bir yapı ve bu yapı için ayrıca yd adlı bir değişken tanımlar. İstediğimiz sayıda tanımlayabileceğimiz bu değişken yoluyla yapının elemanlarına ulaşabiliriz.

Yapı elemanlarına değer atama

Bir yapı ve yapı değişkeni oluşturulduktan sonra, yapı içinde yer alan bir elemana yapı değişkeni yolu ile ulaşmak için aşağıdaki ifadeyi kullanabiliriz:

yapı-değişkeni.alan-adı

Yapı değişkeni kullanımını gösteren farklı uygulamalar aşağıda gösterilmektedir:


// yap adlı yapı ve yd adlı yapı değişkeni bildirimi
struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
} yd;

// yap adlı yapının id değişkenine 21 değeri atar.
yd.id = 21;

// yap adlı yapının id değişken değerini ekrana yazma
cout << yd.id;

// yap adlı yapının id değişkenine klavyeden girilen bir değeri okutma
scanf("%d", &yd.id);

// yap adlı yapının cdizi1 dizisine bir değer girme ve aynı değeri ekrana yazdırma
cout << "Adını giriniz: ";
fgets(yd.cdizi1, 20, stdin);
cout << yd.cdizi1;

// yap adlı yapının cdizi1 dizisindeki 2.karakteri ekrana yazma
cout << yd.cdizi1[1];
 

Yapılar sayesinde tek bir değişken yolu ile birden fazla farklı türden veriye tek isim yoluyla erşim sağlayabiliriz.

Şimdi, bu özellikleri bir örnek üzerinde incelemeye çalışalım:


#include <iostream>
#include <cstdio>

using namespace std;

struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
} yd;

char* bg_fgets(char *str, int count);

int main(void)
{
  cout << "Adı: ";
  bg_fgets(yd.cdizi1, 20);
  cout << "Soyadı: ";
  bg_fgets(yd.cdizi2, 20);
  cout << "Memleketi: ";
  bg_fgets(yd.cdizi3, 20);
  cout << "Tahsili: ";
  bg_fgets(yd.cdizi4, 20);
  cout << "Yaşı: ";
  scanf("%d", &yd.id);

  cout << yd.cdizi1 << " " << yd.cdizi2 << " " << yd.cdizi3 << " " << yd.cdizi4 << " " << yd.id;

  return 0;
}

char* bg_fgets(char *str, int count)
{
  const char *s;

  fgets(str, count, stdin);

  for (s=str; *s && *s!='\n'; ++s);

  if ((s-str) < (count-1)) *(str+(s-str)) = '\0';

  return str;
}

Yukarıdaki örnekte, program bir kişi için girdiğiniz verileri yap adlı bir yapının elemanlarına atar ve elemanları ekrana yazar. Bu durumda yapı elemanlarına daima yd değişkeni yoluyla ulaşılır.

bg_fgets() fonksiyonu, fgets() fonksiyonu ile klavyeden okunan karakter dizisi girilebilecek maksimum karakter sayısından az olduğunda, karakter dizisine '\0' karakterinden hemen önce otomatik olarak eklenen '\n' karakteri yerine '\0' karakteri koymak için kullanılır.

Yapılar için değişken tanımlama

Yukarıda yap adlı bir yapı bildirimi yaparken aynı zamanda yd adlı bir değişken tanımladık. yap yapısının bildirimini yaptıktan sonra, program içindeki işlem satırları ile aynı yapı için tekrar değişken tanımlayabiliriz. Bir yapıyı bir kez tanımladıktan sonra, aşağıdaki ifade ile daha fazla değişken tanımlayabiliriz:

struct yapı-adı değişken-listesi;

Örneğin aşağıdaki ifadeyi kullanarak yap yapısı için 2 değişken tanımlayabiliriz:


struct yap yd2, yd3;

Bu işlem satırı, yapı tanımlamasından bağımsız olarak değişken tanımlama olanağı sağlar. Bu özellikten dolayı, yapı tanımlamalarında değişken tanımlamak şart değildir. Bazı durumlarda yapı tanımlamalarında yapı adı tanımlamayabilirsiniz. Ancak, bu durumda değişken adlarını mutlaka tanımlamamız gerekir:


struct {
  char cdizi[10];
  int id;
  char cd;
} yd1, yd2, yd3;

Yapı tanımlamalarında yapı-adı ve değişken-listesi ifadelerinin en az birisini kullanmamız gereklidir. İkisini birlikte kullanmak ise isteğe bağlıdır.

Şimdi bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

struct yap1 {
  char cdizi[20];
  int id;
} yd1;

struct yap2 {
  char cdizi[20];
  int id;
};

struct {
  char cdizi[20];
  int id;
} yd3;

struct yap2 yd2;

char* bg_fgets(char *str, int count);

int main(void)
{
  char cdizi[20];

  cout << "Bir karakter dizisi giriniz: ";
  bg_fgets(yd1.cdizi, 20);
  cout << "int bir değer giriniz: ";
  bg_fgets(cdizi, 20);
  yd1.id = (int) atoi(cdizi);

  cout << "\n" << "Bir karakter dizisi giriniz: ";
  bg_fgets(yd2.cdizi, 20);
  cout << "int bir değer giriniz: ";
  bg_fgets(cdizi, 20);
  yd2.id = (int) atoi(cdizi);

  cout << "\n" << "Bir karakter dizisi giriniz: ";
  bg_fgets(yd3.cdizi, 20);
  cout << "int bir değer giriniz: ";
  bg_fgets(cdizi, 20);
  yd3.id = (int) atoi(cdizi);

  cout << yd1.cdizi << " " << yd1.id << "\n";
  cout << yd2.cdizi << " " << yd2.id << "\n";
  cout << yd3.cdizi << " " << yd3.id;

  return 0;
}

char* bg_fgets(char *str, int count)
{
  const char *s;

  fgets(str, count, stdin);

  for (s=str; *s && *s!='\n'; ++s);

  if ((s-str) < (count-1)) *(str+(s-str)) = '\0';

  return str;
}

Program, 3 farklı yapı tanımlar. yap1 yapısının bildirimi hem yapı adı hem de değişken, yap2 yapısının bildirimi sadece yapı adı ve yap3 yapısının bildirimi ise sadece değişken adı tanımlanarak yapılmıştır. Girilen değerleri bu yapı içindeki elemanlara atayarak ekrana yazar.

bg_fgets() fonksiyonu, fgets() fonksiyonu ile klavyeden okunan karakter dizisi girilebilecek maksimum karakter sayısından az olduğunda, karakter dizisine '\0' karakterinden hemen önce otomatik olarak eklenen '\n' karakteri yerine '\0' karakteri koymak için kullanılır.

Yapı değişken dizileri oluşturma

Yapılar için kullanacağınız değişkenleri bir dizi içinde tanımlayabiliriz. Bu işlemi aşağıdaki şekilde yapabilirsiniz:


struct yap {
  char cdizi1[20];
  char cdizi2[20];
  int id;
} ydizi[10];

Yukarıdaki işlem satırları 3 elemanlı ve yap adlı bir yapı ve bu yapı için, bir dizinin elemanları olarak, 10 adet değişken tanımlar. Burada, üçüncü yapı değişkeni ile id değişkenine aşağıdaki işlem satırı ile 21 değeri atanır:


ydizi[2].id = 21;


#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

struct yap {
  char cdizi1[20]; // İsim
  char cdizi2[20]; // Soyadı
  int id;          // Yaşı
} ydizi[5];

char* bg_fgets(char *str, int count);

int main(void)
{
  int id;
  char cdizi[20];

  for (id=0; id<5; id++) {
       cout << "Adı: ";
       bg_fgets(ydizi[id].cdizi1, 20);
       cout << "Soyadı: ";
       bg_fgets(ydizi[id].cdizi2, 20);
       cout << "Yaşı: ";
       bg_fgets(cdizi, 20);
       ydizi[id].id = (int) atoi(cdizi);

       cout << "\n";
  }

  for (id=0; id<5; id++) {
       cout << ydizi[id].cdizi1 << " " << ydizi[id].cdizi2 << " " << ydizi[id].id << "\n";
  }

  return 0;
}

char* bg_fgets(char *str, int count)
{
  const char *s;

  fgets(str, count, stdin);

  for (s=str; *s && *s!='\n'; ++s);

  if ((s-str) < (count-1)) *(str+(s-str)) = '\0';

  return str;
}

Program, yap adlı bir yapı ve bu yapı için bir dizi içinde 5 adet değişken tanımlar. Sonra, bu değişkenler yoluyla yapıya girilen verileri ekrana yazar.


#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;

struct yap {
  char cdizi1[20]; // İsim
  char cdizi2[20]; // Soyadı
  int id;          // Yaşı
} ydizi[5];

char* bg_fgets(char *str, int count);

int main(void)
{
  ofstream outfile("deneme.txt"); // Dosyaya yazma işlemi için akış oluşturma
  int id;
  char cdizi[20];

  // Dosya açma hata kontrolü
  if(!outfile) {
     cout << "Yazma amaçlı dosya açma hatası!" << endl;
     exit(1);
  }

  for (id=0; id<5; id++) {
       cout << "Adı: ";
       bg_fgets(ydizi[id].cdizi1, 20);
       cout << "Soyadı: ";
       bg_fgets(ydizi[id].cdizi2, 20);
       cout << "Yaşı: ";
       bg_fgets(cdizi, 20);
       ydizi[id].id = (int) atoi(cdizi);

       cout << "\n";
  }

  outfile.write((const char*)ydizi, sizeof(ydizi)); // Nesneyi dosyaya yazma

  outfile.close(); // Dosya kapatma

  ifstream infile("deneme.txt"); // Dosyadan okuma işlemi için akış oluşturma

  // Dosya açma hata kontrolü
  if(!infile) {
     cout << "Okuma amaçlı dosya açma hatası!" << endl;
     exit(1);
  }

  infile.read((char*)ydizi, sizeof(ydizi));

  for (id=0; id<5; id++) {
       cout << ydizi[id].cdizi1 << " " << ydizi[id].cdizi2 << " " << ydizi[id].id << "\n";
  }

  infile.close(); // Dosya kapatma

  return 0;
}

char* bg_fgets(char *str, int count)
{
  const char *s;

  fgets(str, count, stdin);

  for (s=str; *s && *s!='\n'; ++s);

  if ((s-str) < (count-1)) *(str+(s-str)) = '\0';

  return str;
}

Program, yap adlı bir yapı ve bu yapı için bir dizi içinde 5 adet değişken tanımlar. Sonra, bu değişkenler yoluyla yapıya girilen verileri deneme.txt adlı dosyaya yazar. Daha sonra, kayıtları dosyadan okuyarak ekrana yazar.

Yapılara ilk değer atama

Bir yapı değişkeninin bildirimini yaparken ilk değer atama yöntemini kullanarak, yapı elemanlarına birer değer atayabiliriz. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
} yd = { "Murat", "Kalender", "Ankara", "Lise", 21 };

int main(void)
{
  cout << yd.cdizi1 << " " << yd.cdizi2 << " " << yd.cdizi3 << " " << yd.cdizi4 << " " << yd.id;

  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Murat Kalender Ankara Lise 21

Program, yap adlı bir yapı bildirimi yapar. yap yapısı için yd adlı değişkeninin bildirimini yaparken, yap yapısının elemanlarına ilk değer atama yöntemi ile bazı değerler atar. Sonra, yapı eleman değerlerini ekrana yazar.

Şimdi, yukarıdaki örneği biraz değiştirerek incelemeye çalışalım:


#include <iostream>

using namespace std;

struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
};

int main(void)
{
  struct yap yd = { "Murat", "Kalender", "Ankara", "Lise", 21 };

  cout << yd.cdizi1 << " " << yd.cdizi2 << " " << yd.cdizi3 << " " << yd.cdizi4 << " " << yd.id;

  return 0;
}

Program, bir önceki programın yaptığı işlem ile aynı işlemi gerçekleştirir. Tek fark yapı değişken bildirim işleminin main() fonksiyonu içinde yapılmış olmasıdır.

Bir yapı için tanımlanan birden fazla değişkene ilk değer atama yöntemi ile değerler atayabiliriz. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <iostream>

using namespace std;

struct yap {
  char cdizi1[20]; // Adı
  char cdizi2[20]; // Soyadı
  char cdizi3[20]; // Memleketi
  char cdizi4[20]; // Tahsili
  int id;          // Yaşı
} ydizi[4] = { "Ahmet", "Efendi", "Rize", "Lise", 25,
               "Mehmet", "Sakin", "Kars", "Ortaokul", 36,
               "Mustafa", "Kibar", "Niğde", "Lise", 42,
               "Murat", "Sade", "Sinop", "Üniversite", 28
             };

int main(void)
{
  int id;

  for (id=0; id<4; id++) {
       cout << ydizi[id].cdizi1 << " " << ydizi[id].cdizi2 << " ";
       cout << ydizi[id].cdizi3 << " " << ydizi[id].cdizi4 << " " << ydizi[id].id << "\n";
  }

  return 0;
}

Yukarıdaki örnekte, program aşağıdaki satırları ekrana yazar:

Ahmet Efendi Rize Lise 25
Mehmet Sakin Kars Ortaokul 36
Mustafa Kibar Niğde Lise 42
Murat Sade Sinop Üniversite 28