Bir dizinin boyut türü neden türünün bir parçasıdır?


14

C ++ Primer kitabını okurken, şu ifadeyle karşılaştım: "Bir dizideki öğelerin sayısı dizinin türünün bir parçasıdır." Bu yüzden aşağıdaki kodu kullanarak öğrenmek istedim:

#include<iostream>

int main()
{
    char Array1[]{'H', 'e', 'l', 'p'};
    char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};

    std::cout<<typeid(Array1).name()<<std::endl;        //prints  A4_c
    std::cout<<typeid(Array2).name()<<std::endl;        //prints  A6_c

    return 0;
}

Ve ilginç bir şekilde, iki dizideki yazı tipinin sonucu, bunların bir şekilde farklı olduğunu gösterdi.

  • Perde arkasında neler oluyor?
  • Dizilerin boyutunu içeren bir türe sahip olması neden gereklidir? Sadece boyutu değişmemeli mi?
  • Bu, dizileri karşılaştırmayı nasıl etkiler?

Sadece kavramı derinden anlayabilmek istiyorum.


3
Boyut bilgisini türe dahil etmek kesinlikle gerekli değildir , ancak yararlıdır
byxor

Dizilerle ilgili her ders açıklanacaktır (1). Dizileri karşılaştırmak için yerleşik bir yol olmadığından (3) ile ne demek istediğinizden emin değilim.
HolyBlackCat

Yanıtlar:


20

Perde arkasında neler oluyor?

Dinamik olarak tahsis edilmemiş bir tanım gereği, sabit boyutlu bir homojen eleman konteyneri olmaktadır. Bir Ntür elemanlar dizisi, tipte nesnelerin Tbitişik dizisi olarak hafızaya yerleştirilir .NT


Dizilerin boyutunu içeren bir türe sahip olması neden gereklidir?

Ben bir dizinin türü boyutunu eklemek için "gerekli" olduğunu sanmıyorum - aslında, Tnesnelerin bitişik bir dizi başvurmak için bir işaretçi kullanabilirsiniz . Böyle bir işaretçi dizi hakkında boyut bilgilerini kaybeder.

Ancak, sahip olmak yararlı bir şeydir. Tip güvenliğini arttırır ve derleme zamanında çeşitli şekillerde kullanılabilecek faydalı bilgileri kodlar. Örnek olarak, farklı boyutlardaki dizilere aşırı yükleme yapmak için dizilere referanslar kullanabilirsiniz

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

veya bir dizinin boyutunu sabit bir ifade olarak bulmak için

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

Bu, dizileri karşılaştırmayı nasıl etkiler?

Gerçekten değil.

C stili dizileri, iki sayıyı (örneğin, intnesneleri) karşılaştırdığınız şekilde karşılaştıramazsınız . Bir çeşit sözlükbilimsel karşılaştırma yazmanız ve farklı boyutlardaki koleksiyonlar için ne anlama geldiğine karar vermeniz gerekir. std::vector<T>bunu sağlar ve dizilere aynı mantık uygulanabilir.


Bonus: C ++ 11 ve üstü, std::arraykonteyner benzeri bir arayüze sahip bir C stili dizi etrafında bir sarıcıdır. Diğer kaplarla (örn. std::vector<T>) Daha tutarlı olduğundan ve aynı zamanda kutudan çıkan sözlükbilimsel karşılaştırmaları desteklediği için C tarzı dizilere tercih edilmelidir .


2
"Bir çeşit sözlükbilimsel karşılaştırma yazmalı ve farklı büyüklükteki koleksiyonlar için ne anlama geldiğine karar vermelisiniz." Sadece kullanabilirsiniz std::equal( diziler için std::beginve aracılığıyla std::endtanımlanır). Bu durumda, farklı boyutlu diziler eşit değildir.
Stu

3
Aralığı bir dizi olan döngülerin derleme zamanında dizinin boyutunu okuması gereken döngülere dayalı olduğunu belirtmek gerekebilir - (neyse ki!) Bu örnekte dizinin türünü asla yazmadığından, ancak büyüklüğe göre aşırı yüklemeden çok daha fazlası geliyor gibi görünüyor.
Milo Brandt

8

Bir nesneyi oluşturduğunuzda ayrılan alanın miktarı tamamen türüne bağlıdır. Bahsettiğim ayırma, newveya öğesinden ayırmalar değil malloc, ayrılan alandır, böylece kurucunuzu çalıştırabilir ve nesnenizi başlatabilirsiniz.

(Örneğin) olarak tanımlanan bir yapınız varsa

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

Sonra nesneyi oluştururken:

A a{'a', 'b'};

Nesneyi inşa etme sürecini bir süreç olarak düşünebilirsiniz:

  • 2 bayt alan ayırın (yığın üzerinde, ancak bu örnek için nerede önemli değil)
  • Nesnenin yapıcısını çalıştırın (bu durumda kopya 'a've 'b'nesneye)

Gerekli 2 bayt alanın tamamen nesnenin türüne göre belirlendiğine dikkat etmek önemlidir, fonksiyonun argümanları önemli değildir. Bu nedenle, bir dizi için işlem aynıdır, ancak şimdi gereken alan miktarı dizideki öğelerin sayısına bağlıdır.

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

Bu yüzden 1 karakter için yeterli alana ve 5 karakter için yeterli alana ihtiyaç duyduğu gerçeğini ave türlerini byansıtmalıdır . Bu, bu dizilerin boyutunun aniden değişemeyeceği anlamına gelir, 5 öğeli bir dizi oluşturulduktan sonra her zaman 5 öğeli bir dizidir. Boyutun değişebileceği "dizi" benzeri nesnelerin olması için, kitabınızın bir noktada kapsanması gereken dinamik bellek ayırmaya ihtiyacınız vardır.ab


0

Çalışma zamanı kitaplığının dahili bir nedeni vardır. Örneğin, aşağıdaki ifadeleri göz önünde bulundurursanız:

unsigned int i;
unsigned int *iPtr;
unsigned int *iPtrArr[2];
unsigned int **iPtrHandle;

O zaman sorunun ne olduğu açıklığa kavuşur: Örneğin, adreslemenin unsigned int *kendisi ile sizeof operatorveya adreslemeyle ilgilenmesi gerekir unsigned int.

Burada gördüğünüz şeylerin geri kalanı için daha ayrıntılı bir açıklama var, ancak beyan edilen türün düz dil metnini basan programla ilgili olarak C Programlama Dili, 2. Baskı Kernighan ve Ritchie tarafından kapsanan şeylerin büyük bir özeti. dize.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.