C-Style Diziler
Programlama dünyasında en temel veri yapılarından biri dizi (array) kavramıdır. Şimdiye kadar tek tek değişkenler tanımladık — bir int, bir double, bir string. Ama ya 100 öğrencinin notunu saklamak istersen? 100 tane ayrı değişken mi tanımlayacaksın? İşte diziler tam da bu sorunu çözer.
Bu derste C++'ın "eski tarz" dizilerini, yani C-style dizileri öğreneceğiz. Modern C++'ta daha iyi alternatifler var (bir sonraki derste göreceğiz), ama C-style dizileri anlamak şart — çünkü tonla eski kod bunlarla yazılmış ve pointer mantığını kavramak için mükemmel bir başlangıç noktası.
Dizi Nedir?
Bir diziyi yan yana dizilmiş kutular gibi düşün. Her kutunun içinde aynı türden bir değer var ve her kutunun bir numarası (indeksi) var.
Mesela bir apartman düşün: 10 katlı, her katta bir daire. "3. kattaki daire" dediğinde hangi daireyi kastettiğin belli. İşte dizi de böyle — bellekte yan yana duran, numaralandırılmış kutucuklar.
Önemli özellikler:
Tüm elemanlar aynı türde olmalı (hepsi
int, hepsidoublevs.)Boyut derleme zamanında belli olmalı (sabit)
Elemanlar bellekte ardışık (contiguous) yerleşir
Dizi Tanımlama ve Başlatma
Temel Söz Dizimi
Bir dizi tanımlamak için türün yanına köşeli parantez içinde boyutu yazarsın:
#include <iostream>
using namespace std;
int main() {
int notlar[5]; // 5 elemanlı int dizisi (değerler çöp!)
// Tek tek atama
notlar[0] = 90;
notlar[1] = 85;
notlar[2] = 78;
notlar[3] = 92;
notlar[4] = 88;
cout << "İlk not: " << notlar[0] << endl; // 90
cout << "Son not: " << notlar[4] << endl; // 88
return 0;
}Dikkat: indeksler 0'dan başlar. 5 elemanlı bir dizinin geçerli indeksleri 0, 1, 2, 3, 4'tür. notlar[5] yazmak tanımsız davranış (undefined behavior) — program çöker, yanlış değer okur veya dünyayı yakar. Belli olmaz.
Tanımlarken Başlatma (Initialization)
Diziyi tanımlarken değer atayabilirsin:
#include <iostream>
using namespace std;
int main() {
// Tam başlatma
int notlar[5] = {90, 85, 78, 92, 88};
// Boyut belirtmeden — derleyici sayar
int puanlar[] = {100, 95, 80}; // 3 elemanlı
// Kısmi başlatma — geri kalanlar 0 olur
int dizi[10] = {1, 2, 3}; // ilk 3: 1,2,3 — kalan 7 tanesi 0
// Hepsini sıfırla
int sifirlar[100] = {}; // tüm elemanlar 0
// C++17: Class Template Argument Deduction ile
// (C-style dizilerde yok ama bilgi olsun)
for (int i = 0; i < 5; i++) {
cout << notlar[i] << " ";
}
cout << endl;
return 0;
}💡 İpucu: Diziyi başlatmadan kullanırsan içinde çöp değerler (garbage values) olur. Bu C++'ın "sana güveniyorum, sen ne yaptığını biliyorsun" felsefesinin bir parçası. Her zaman başlat!
Uniform Initialization (C++11)
int dizi[3]{10, 20, 30}; // = işareti olmadan da olur
int dizi2[5]{}; // hepsi 0
// int hata[3]{1, 2, 3, 4}; // HATA: çok fazla elemanDiziye Erişim ve Döngü ile Gezinme
İndeks ile Erişim
Dizi elemanlarına [] operatörü ile erişirsin:
#include <iostream>
using namespace std;
int main() {
int gunler[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
cout << "Ocak: " << gunler[0] << " gün" << endl;
cout << "Şubat: " << gunler[1] << " gün" << endl;
// Değer değiştirme
gunler[1] = 29; // Artık yıl!
cout << "Şubat (artık yıl): " << gunler[1] << " gün" << endl;
return 0;
}Klasik for Döngüsü ile Gezinme
#include <iostream>
using namespace std;
int main() {
int sayilar[] = {10, 20, 30, 40, 50};
int boyut = 5;
// Tüm elemanları yazdır
for (int i = 0; i < boyut; i++) {
cout << "sayilar[" << i << "] = " << sayilar[i] << endl;
}
// Toplam hesapla
int toplam = 0;
for (int i = 0; i < boyut; i++) {
toplam += sayilar[i];
}
cout << "Toplam: " << toplam << endl;
return 0;
}Range-based for Döngüsü (C++11)
C++11 ile gelen bu döngü, diziyi doğrudan gezmeyi sağlar. İndeksle uğraşmana gerek kalmaz:
#include <iostream>
using namespace std;
int main() {
int notlar[] = {90, 85, 78, 92, 88};
// Sadece okuma
for (int not_degeri : notlar) {
cout << not_degeri << " ";
}
cout << endl;
// Değer değiştirmek istiyorsan referans kullan
for (int& not_degeri : notlar) {
not_degeri += 5; // herkese 5 puan bonus
}
// Kontrol
for (int n : notlar) {
cout << n << " "; // 95 90 83 97 93
}
cout << endl;
return 0;
}⚠️ Dikkat: Range-based for döngüsünde
int n : diziyazarsan elemanın kopyasını alırsın. Değiştirmek istiyorsanint& n : dizi(referans) kullanmalısın.
Dizi Boyutu ve sizeof Hilesi
C-style dizilerde boyutu öğrenmek için yerleşik bir fonksiyon yok. Ama bir hile var — sizeof operatörü:
#include <iostream>
using namespace std;
int main() {
int notlar[] = {90, 85, 78, 92, 88};
// sizeof dizinin TOPLAM byte boyutunu verir
cout << "Toplam boyut: " << sizeof(notlar) << " byte" << endl; // 20
// Bir elemanın boyutu
cout << "Bir eleman: " << sizeof(notlar[0]) << " byte" << endl; // 4
// Eleman sayısı = toplam / bir eleman
int eleman_sayisi = sizeof(notlar) / sizeof(notlar[0]);
cout << "Eleman sayısı: " << eleman_sayisi << endl; // 5
// Döngüde kullanmak
for (int i = 0; i < sizeof(notlar) / sizeof(notlar[0]); i++) {
cout << notlar[i] << " ";
}
cout << endl;
return 0;
}std::size() — Modern Yol (C++17)
C++17'den itibaren std::size() fonksiyonunu kullanabilirsin:
#include <iostream>
#include <iterator> // std::size için
using namespace std;
int main() {
int notlar[] = {90, 85, 78, 92, 88};
cout << "Eleman sayısı: " << size(notlar) << endl; // 5
for (size_t i = 0; i < size(notlar); i++) {
cout << notlar[i] << " ";
}
cout << endl;
return 0;
}💡 İpucu:
std::size()hem daha okunabilir hem de daha güvenli.sizeofhilesi fonksiyon parametresi olarak geçen dizilerde çalışmaz (birazdan göreceğiz).std::size()da çalışmaz ama en azından derleme hatası verir, sessizce yanlış sonuç vermez.
Dizinin Fonksiyona Geçirilmesi (Decay to Pointer)
İşte C-style dizilerin en tuzaklı konusu. Bir diziyi fonksiyona parametre olarak geçirdiğinde, dizi pointer'a dönüşür (decay). Yani fonksiyon dizinin kendisini değil, ilk elemanının adresini alır.
Bu ne demek? Fonksiyonun içinde sizeof hilesi çalışmaz — çünkü artık elinde bir dizi değil, bir pointer var.
Sorunun Gösterimi
#include <iostream>
using namespace std;
void yanlis_boyut(int dizi[]) {
// Bu dizinin boyutunu DEĞİL, pointer'ın boyutunu verir!
cout << "Fonksiyon içi sizeof: " << sizeof(dizi) << endl; // 8 (64-bit sistemde)
}
int main() {
int notlar[] = {90, 85, 78, 92, 88};
cout << "Main içi sizeof: " << sizeof(notlar) << endl; // 20
yanlis_boyut(notlar);
return 0;
}Doğru Yol: Boyutu Ayrı Parametre Olarak Geç
#include <iostream>
using namespace std;
void dizi_yazdir(int dizi[], int boyut) {
for (int i = 0; i < boyut; i++) {
cout << dizi[i] << " ";
}
cout << endl;
}
double ortalama_hesapla(int dizi[], int boyut) {
int toplam = 0;
for (int i = 0; i < boyut; i++) {
toplam += dizi[i];
}
return static_cast<double>(toplam) / boyut;
}
int main() {
int notlar[] = {90, 85, 78, 92, 88};
int boyut = sizeof(notlar) / sizeof(notlar[0]);
dizi_yazdir(notlar, boyut);
cout << "Ortalama: " << ortalama_hesapla(notlar, boyut) << endl;
return 0;
}Fonksiyona Geçen Dizi Değiştirilebilir
Dizi pointer olarak geçtiği için, fonksiyon içinde yapılan değişiklikler orijinal diziyi etkiler:
#include <iostream>
using namespace std;
void hepsini_ikiyle_carp(int dizi[], int boyut) {
for (int i = 0; i < boyut; i++) {
dizi[i] *= 2; // orijinal dizi değişir!
}
}
void dizi_yazdir(const int dizi[], int boyut) {
// const ile işaretlersek değiştirilemez
for (int i = 0; i < boyut; i++) {
cout << dizi[i] << " ";
}
cout << endl;
}
int main() {
int sayilar[] = {1, 2, 3, 4, 5};
cout << "Önce: ";
dizi_yazdir(sayilar, 5);
hepsini_ikiyle_carp(sayilar, 5);
cout << "Sonra: ";
dizi_yazdir(sayilar, 5); // 2 4 6 8 10
return 0;
}Değiştirilmesini istemiyorsan const anahtar kelimesini kullan. Bu "ben sadece okuyacağım, değiştirmeyeceğim" demek.
C-Style Dizilerde Sık Yapılan Hatalar
1. Sınır Dışı Erişim (Out of Bounds)
int dizi[5] = {1, 2, 3, 4, 5};
// TEHLİKE! Tanımsız davranış
cout << dizi[5] << endl; // geçerli indeksler 0-4
cout << dizi[-1] << endl; // negatif indeks de sorun
dizi[10] = 42; // başka bellek alanına yazıyorsun!C++ sana sınır kontrolü yapmaz. Bu senin sorumluluğun. Java veya Python'dan geliyorsan bu seni şaşırtabilir — oralarda hemen hata alırsın, C++'ta ise program "çalışıyor gibi" yapıp sessizce yanlış sonuç üretebilir.
2. Değişken Boyutlu Dizi (VLA) Kullanımı
int n;
cin >> n;
int dizi[n]; // Bazı derleyicilerde çalışır ama STANDART DEĞİL!Bu sözdizimi C99'da var ama C++ standardında yok. GCC izin verir (extension olarak), ama taşınabilir kod yazmak istiyorsan kullanma. Dinamik boyut istiyorsan std::vector kullan.
3. Dizi Atama ve Karşılaştırma
int a[3] = {1, 2, 3};
int b[3] = {1, 2, 3};
// b = a; // HATA! Dizi ataması yapılamaz
// if (a == b) ... // Adresleri karşılaştırır, içerikleri DEĞİL!C-style dizileri ne kopyalayabilirsin ne de == ile karşılaştırabilirsin. Bu işlemler için ya döngü yazarsın ya da std::array / std::vector kullanırsın.
Pratik Örnek: En Büyük ve En Küçük Elemanı Bulma
#include <iostream>
#include <climits> // INT_MAX, INT_MIN
using namespace std;
int main() {
int sicakliklar[] = {23, 18, 31, 27, 15, 29, 22};
int boyut = sizeof(sicakliklar) / sizeof(sicakliklar[0]);
int en_buyuk = INT_MIN; // olabilecek en küçük int
int en_kucuk = INT_MAX; // olabilecek en büyük int
for (int i = 0; i < boyut; i++) {
if (sicakliklar[i] > en_buyuk) {
en_buyuk = sicakliklar[i];
}
if (sicakliklar[i] < en_kucuk) {
en_kucuk = sicakliklar[i];
}
}
cout << "En sıcak gün: " << en_buyuk << "°C" << endl; // 31
cout << "En soğuk gün: " << en_kucuk << "°C" << endl; // 15
return 0;
}Pratik Örnek: Diziyi Ters Çevirme
#include <iostream>
using namespace std;
void ters_cevir(int dizi[], int boyut) {
for (int i = 0; i < boyut / 2; i++) {
int gecici = dizi[i];
dizi[i] = dizi[boyut - 1 - i];
dizi[boyut - 1 - i] = gecici;
}
}
int main() {
int sayilar[] = {1, 2, 3, 4, 5};
int boyut = 5;
cout << "Önce: ";
for (int s : sayilar) cout << s << " ";
cout << endl;
ters_cevir(sayilar, boyut);
cout << "Sonra: ";
for (int s : sayilar) cout << s << " ";
cout << endl; // 5 4 3 2 1
return 0;
}Pratik Örnek: Lineer Arama
#include <iostream>
using namespace std;
int ara(const int dizi[], int boyut, int hedef) {
for (int i = 0; i < boyut; i++) {
if (dizi[i] == hedef) {
return i; // bulundu, indeksi döndür
}
}
return -1; // bulunamadı
}
int main() {
int notlar[] = {90, 85, 78, 92, 88};
int boyut = 5;
int sonuc = ara(notlar, boyut, 78);
if (sonuc != -1) {
cout << "78 bulundu, indeks: " << sonuc << endl;
} else {
cout << "Bulunamadı" << endl;
}
return 0;
}C-Style Dizilerin Sınırlamaları
C-style dizileri anlaman önemli ama günlük kodda bunları kullanmak için pek neden yok. İşte neden:
| Sorun | Açıklama |
|---|---|
| Boyut sabit | Derleme zamanında belli olmalı, çalışma zamanında büyüyüp küçülemez |
| Sınır kontrolü yok | dizi[100] yazsan bile hata vermez, sessizce bellek bozar |
| Boyut bilgisi kayboluyor | Fonksiyona geçince pointer'a dönüşür, boyut bilgisi uçar |
| Kopyalama yok | = ile kopyalayamazsın |
| Karşılaştırma yok | == adresleri karşılaştırır, içerikleri değil |
| Iterator desteği yok | STL algoritmaları ile doğrudan kullanımı sınırlı |
Bu sorunların hepsini çözen iki modern alternatif var: std::array (sabit boyut) ve std::vector (dinamik boyut). Bunları bir sonraki derste göreceğiz.
⚠️ Tavsiye: Yeni kod yazarken C-style dizi yerine
std::arrayveyastd::vectorkullan. C-style dizileri sadece eski kodları okurken veya düşük seviyeli (low-level) işler yaparken karşına çıkacak.
Özet
C-style dizi, bellekte yan yana duran aynı türde elemanlar topluluğudur.
int dizi[5]gibi tanımlanır.İndeksler 0'dan başlar; 5 elemanlı dizide geçerli indeksler 0–4'tür.
Dizi boyutunu öğrenmek için
sizeof(dizi)/sizeof(dizi[0])hilesi veya C++17'dekistd::size()kullanılır.Fonksiyona geçince dizi pointer'a dönüşür (decay); bu yüzden boyut bilgisi kaybolur, ayrı parametre olarak geçirilmelidir.
C-style diziler kopyalanamaz,
==ile karşılaştırılamaz ve sınır kontrolü yapılmaz.Modern C++'ta
std::arrayvestd::vectortercih edilmelidir; C-style diziler eski kodları anlamak için bilinmelidir.
AI Asistan
Sorularını yanıtlamaya hazır