Menu

C++ Diziler: Tanımlama, İndeksleme ve Sık Yapılan Hatalar

C++ ham dizileri açıklanıyor: nasıl tanımlanır ve ilklendirilir, güvenli indeksleme, boyutuyla döngü kurma, diziden işaretçiye bozulma tuzağı ve neden std::array ile vector genellikle daha iyidir.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Sabit Boyutlu Bir Değer Dizisi

Bir dizi, aynı türden sabit sayıda değeri tutan bitişik bir bellek bloğudur. Tek bir int bir sayı saklarken, bir int dizisi bunlardan birçoğunu arka arkaya saklar ve her birine bir tamsayı indeksiyle ulaşılır.

Bir dizi tanımlamak için eleman tipini, bir adı ve köşeli parantez içinde bir boyut verirsiniz. Doldurmak için süslü parantezli bir liste ekleyin:

İndeksleme sıfır tabanlıdır: ilk eleman scores[0]'dır ve boyutu 4 olan bir dizinin geçerli indeksleri 0'dan 3'e kadardır. Boyut, derleme zamanı sabiti olmalıdır; standart C++'ta int n = readInput(); int a[n]; yazamazsınız (bu, taşınabilir olmayan bir uzantıdır). Boyutun çalışma zamanında belirlenmesi gerektiğinde bunun yerine bir vector kullanın.

Dizileri İlklendirme

Bir diziyi doldurmanın birkaç yolu ve bilinmeye değer birkaç kısayol vardır:

İçselleştirilmesi gereken püf nokta: boyuttan daha az ilklendirici verdiğinizde, geri kalanlar çöp olarak bırakılmaz, değerle ilklendirilir (sayısal türler için sıfır). Ancak hiç ilklendiricisi olmayan bir dizi — yerel olarak tanımlanmış int e[4]; — belirsiz değerler içerir ve atama yapmadan önce onları okumak tanımsız davranıştır.

Bir Dizi Üzerinde Döngü Kurma

Elemanlar bitişik saklandığı için bir diziyi düz bir indeks döngüsüyle dolaşırsınız. Sınırlar içinde kalmak için döngüyü, koda gömülü bir sayı yerine dizinin gerçek uzunluğuyla sürün:

sizeof(scores) tüm dizinin toplam bayt sayısıdır; bunu sizeof(scores[0])'a (bir elemanın boyutu) bölmek eleman sayısını verir. C++17'den beri daha temiz bir yazım var: std::size(scores). Bu daha okunaklıdır ve yanlışlıkla ona bir işaretçi verirseniz derlenmeyi reddeder. Yalnızca değerlere ihtiyacınız olduğunda daha da basiti: bir aralık tabanlı for indeks hesaplamasını tamamen atlar.

Sınır Dışı Tuzağı

C++, arr[i] üzerinde hiçbir sınır denetimi yapmaz. Son elemanın ötesine indekslemek bir istisna fırlatmaz veya uyarı vermez; oraya ne denk geliyorsa o belleği okur ya da yazar. Bu, en sık görülen dizi hatasıdır ve klasik bir tanımsız davranış örneğidir:

int a[3] = {1, 2, 3};
a[3] = 99;          // OOPS - valid indices are 0..2, not 3
cout << a[5];       // garbage, crash, or corruption - undefined behavior

Bir-fazla (off-by-one) hatası genellikle bir döngü koşulunda gizlenir. i < n yerine i <= n yazmak bir adım fazla giderek var olmayan arr[n]'ye dokunur:

for (int i = 0; i <= n; i++)   // BUG: when i == n, arr[i] is out of bounds
    cout << arr[i];

Çözüm, önceki bölümdeki disiplindir: döngüyü asla <= ile değil i < size ile kurun ve boyutu, bir eleman eklediğinizde senkronizasyondan çıkan bir sabiti yeniden yazmak yerine diziden hesaplayın.

Dizi Bozulması: Gizli İşaretçi

C++'taki en aldatıcı dizi davranışı bozulmadır (decay): bir diziyi bir fonksiyona geçirdiğinizde, sessizce ilk elemanına bir işaretçiye dönüşür. Boyut bilgisi kaybolur, bu yüzden fonksiyonun içindeki sizeof diziyi değil işaretçiyi ölçer.

Fonksiyon parametreleri olarak int arr[] ile int* arr'ın aynı olduğuna dikkat edin; köşeli parantezler yalnızca süslemedir. Sayım kaybolduğu için, uzunluğu dizinin yanında kendiniz geçirmeniz gerekir:

int sum(const int* arr, int n) {
    int total = 0;
    for (int i = 0; i < n; i++) total += arr[i];
    return total;
}

Bu "bir işaretçi ile bir uzunluk geçir ve uyuşmaları için dua et" deseni, çoğu C++ kodunu kendi boyutunu taşıyan ve asla bozulmayan std::array ve std::vector'a iten sürtünmenin ta kendisidir.

Çok Boyutlu Diziler Üzerine Kısa Bir Not

Bir ızgara oluşturmak için köşeli parantezleri iç içe geçirebilirsiniz. Bir 2B dizi aslında bir diziler dizisidir ve bellekte satır satır yerleşir:

Onu grid[row][col] olarak indeksleyin. Aynı sınır ve bozulma uyarıları geçerlidir ve daha da kötüleşir, çünkü bir 2B diziyi bir fonksiyona geçirmek ilki dışındaki her boyutu açıkça yazmayı gerektirir (void f(int g[][3])). Küçük, sabit bir ızgaranın ötesindeki her şey için, bir vector'lardan oluşan vector çok daha az hataya açıktır.

Sıradaki: Vector

Ham diziler hızlı ve öngörülebilirdir, ancak sabit boyutları, sınır güvenliğinin olmaması ve işaretçiye bozulma davranışları onları günlük kod için hantal kılar. Sırada std::vector ile tanışacağız — talep üzerine büyüyen, kendi boyutunu hatırlayan ve doğrudan STL algoritmalarına bağlanan, yeniden boyutlandırılabilir bir dizi; size kendinizi vurmanın çok daha az yoluyla dizilerin sunduğunun neredeyse tamamını verir.

Sıkça Sorulan Sorular

C++ dilinde bir dizi nasıl tanımlanır ve ilklendirilir?

Eleman tipini, bir adı ve köşeli parantez içinde boyutu yazın, ardından isteğe bağlı olarak süslü parantezli bir liste ekleyin: int scores[4] = {90, 75, 100, 60};. İlklendiriciler verdiğinizde boyutu atlayabilirsiniz; int scores[] = {90, 75, 100, 60}; derleyicinin onları sizin yerinize saymasını sağlar.

C++ dilinde bir dizinin uzunluğu nasıl alınır?

Hâlâ kapsam içinde olan gerçek bir dizi için std::size(arr) (C++17) veya sizeof(arr) / sizeof(arr[0]) kullanın. Dizi bir işaretçiye bozulduğunda (örneğin int arr[] alan bir fonksiyonun içinde) bu çalışmaz; orada sizeof dizinin değil işaretçinin boyutunu verir.

C++ dilinde bir diziye sınır dışı erişirsen ne olur?

Bu tanımsız davranıştır. C++, arr[i] üzerinde sınır denetimi yapmaz; bu yüzden sonun ötesinde okuma veya yazma çökmeye, çöp değer dönmesine ya da yakındaki belleğin sessizce bozulmasına yol açabilir. İndeksinizi her zaman 0 ile size - 1 aralığında tutun.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA