İndeksleme neden 'C' de sıfır ile başlıyor?


154

Neden bir dizideki indeksleme 1'de değil C'de sıfır ile başlar?


7
Her şey işaretçilerle ilgili!
medopal


3
Bir işaretçi (dizi) bir bellek yönüdür ve dizin bu bellek yönünün bir
dengesidir

3
@drhirsch çünkü bir dizi nesneyi saydığımızda, bir nesneyi işaret edip "bir" diyerek başlıyoruz.
phoog

1
Amerikalılar bir binanın katlarını (katlarını) zemin kattaki birinden sayarlar; İngiliz sayısı sıfırdan (zemin kat), birinci kata, sonra ikinci kata, vb. kadar yükselir
Jonathan Leffler

Yanıtlar:


116

C'de, bir dizinin adı temelde bir işaretçi [ancak açıklamalara bakın] , bir bellek konumuna bir referanstır ve bu nedenle ifade , başlangıç ​​öğesinden uzakta array[n]bir bellek konumu nöğelerine karşılık gelir . Bu, indeksin ofset olarak kullanıldığı anlamına gelir. Dizinin ilk öğesi, dizinin başvurduğu bellek konumunda tam olarak bulunur (0 öğe uzakta), bu nedenle olarak belirtilmelidir array[0].

Daha fazla bilgi için:

http://developeronline.blogspot.com/2008/04/why-array-index-should-start-from-0.html


20
Bir dizinin adı dizinin adıdır; Yaygın yanılgının aksine, diziler hiçbir anlamda işaretçi değildir . Bir dizi ifadesi (bir dizi nesnesinin adı gibi) genellikle, ancak her zaman olmasa da, ilk öğeye bir işaretçiye dönüştürülür. Örnek: sizeof arrİşaretçinin boyutunu değil, dizi nesnesinin boyutunu verir.
Keith Thompson

Açıkçası @ KeithThompson'ın yorumuna tepki vermediyseniz de, daha fazla bir suç kursu kullanmak istiyorum: " C'de, bir dizinin adı aslında bir işaretçi, bir bellek konumuna bir referans " - Hayır, değil . En azından genel bir bakış açısından değil. Cevabınız mükemmel bir şekilde soruyu dizin başlangıcı olarak 0 önemli olduğu şekilde cevaplasa da, ilk cümle yanlıştır. Bir dizi her zaman ilk öğesinin işaretçisine bozulmaz.
RobertS, Monica Cellio

C standardından alıntı, (C18), 6.3.2.1/4: " Operatörün veya tekli operatörün işleneni sizeofveya &bir diziyi başlatmak için kullanılan bir dize değişmezi, türü olan bir ifade hariç " türünün ", dizi işaretçisinin
yazdığı

Ayrıca bu bozulma, burada önerilenden daha "örtük" veya "resmi" bir şekilde gerçekleşir; ilgili bellekteki bir işaretçi nesnesinin bozulması yoktur. Bu şu sorunun nesnesi: Dizi işaretçi çürümesine bir işaretçi nesnesine değiştirildi mi? - Lütfen yanıtınızı tamamen doğru olacak şekilde düzenleyin.
RobertS, Monica Cellio

103

Bu soru bir yıldan fazla bir süre önce gönderildi, ama işte gidiyor ...


Yukarıdaki nedenler hakkında

İken Dijkstra'nın makale (daha önce şimdi silinmiş başvurulan cevap ) matematiksel açıdan mantıklı, bu alakalı olarak değil de programlama gelince.

Dil belirtimi ve derleyici tasarımcıları tarafından alınan karar, bilgisayar sistemi tasarımcıları tarafından sayımı 0'da başlatma kararına dayanmaktadır.


Muhtemel sebep

Barış için bir savunmadan alıntı yapan Danny Cohen.

Herhangi bir b tabanı için, ilk b ^ N negatif olmayan tamsayılar yalnızca numaralandırma 0'dan başlıyorsa tam olarak N rakamıyla (baştaki sıfırlar dahil) temsil edilir .

Bu oldukça kolay bir şekilde test edilebilir. Taban-2'de, 2^3 = 8 8. sayı:

  • 8 (ikili: 1000) 1 değerine başlarsak
  • 7 (ikili: 111) sayı 0 olarak başlarsak

111bir bit (4 bit) gerektirirken 3, bitler kullanılarak temsil edilebilir 1000.


Bu neden alakalı?

Bilgisayar bellek adreslerinin bitlerle 2^Nadreslenmiş hücreleri vardır N. Şimdi 1 olarak saymaya başlarsak, 2^Nhücrelerin N+1adres satırlarına ihtiyacı olacaktır . Ekstra bit, tam olarak 1 adrese erişmek için gereklidir. ( 1000yukarıdaki durumda.). Bunu çözmenin başka bir yolu, son adrese erişilemez bırakmak ve Nadres satırlarını kullanmak olacaktır .

Her ikisi de tam adres satırlarını kullanarak tüm adreslere erişilmesini sağlayacak 0'daki başlangıç ​​sayımına kıyasla en uygun çözümlerdirN !


Sonuç

0Saymaya başlama kararı , o zamanlar üzerinde çalışan yazılımlar da dahil olmak üzere tüm dijital sistemlere nüfuz etmiştir, çünkü kodun temel sistemin yorumlayabileceği şeye çevrilmesini kolaylaştırır. Eğer böyle olmasaydı, her dizi erişimi için makine ve programlayıcı arasında gereksiz bir çeviri işlemi olurdu. Derlemeyi kolaylaştırır.


Makaleden alıntı:

resim açıklamasını buraya girin


2
Ya bit 0'ı kaldırmış olsaydı .. o zaman 8. sayı hala 111 olurdu ...
DanMatlin

2
Aslında uyum sağlamak için temel aritmetik modifikasyonunu önerir misiniz? Bugün sahip olduğumuz şeyin çok daha iyi bir çözüm olduğunu düşünmüyor musunuz?
Anirudh Ramanathan

Yıllar sonra benim 2 cnt değerinde. Deneyimlerime göre (~ 35 yıllık programlama) modulo veya modüler ekleme işlemi bir şekilde veya başka bir şekilde şaşırtıcı bir şekilde ortaya çıkıyor. Sıfır baz ile sıradaki (i + 1)% n olur, ancak baz 1 ile (i-1)% n) +1 gelir, bu yüzden 0 tabanlı tercih edilir. Bu matematik ve programlamada oldukça sık görülür. Belki de sadece benim ya da çalıştığım alandır.
nyholku

Tüm iyi nedenler bence çok daha basit: erken derleyicilerde a[b]olduğu gibi uygulandı *(a+b). Bugün bile 2[a]bunun yerine hala yazabilirsiniz a[2]. Şimdi dizinler 0'dan başlamazsa a[b]dönüşür *(a+b-1). Bu, 0 yerine zamanın CPU'larında 2 ekleme gerektiriyordu, yani hızın yarısı. Açıkçası arzu edilmez.
Goswin von Brederlow

1
Sadece 8 eyalet istemeniz, bu onların içinde 8 rakamı olması gerektiği anlamına gelmez.
Evimdeki

27

Çünkü 0, işaretçinin dizinin başına ve dizinin ilk öğesine ne kadar uzak olduğudur.

Düşünmek:

int foo[5] = {1,2,3,4,5};

0'a erişmek için:

foo[0] 

Ancak foo bir işaretçiye ayrışır ve yukarıdaki erişim, ona erişen benzer işaretçi aritmetik yoluna sahiptir

*(foo + 0)

Bugünlerde işaretçi aritmetiği sık kullanılmamaktadır. Yine de, bir adres alıp X "ints" ı bu başlangıç ​​noktasından uzaklaştırmanın uygun bir yoluydu. Tabii ki bulunduğunuz yerde kalmak istiyorsanız, 0 ekleyin!


23

0 tabanlı dizin izin verdiği için ...

array[index]

... uygulanacak ...

*(array + index)

Dizin 1 tabanlı olsaydı, derleyicinin şunu üretmesi gerekirdi: *(array + index - 1)ve bu "-1" performansa zarar verirdi.


4
İlginç bir noktaya değindin. Performansa zarar verebilir. Ancak performans isabeti, başlangıç ​​endeksi olarak 0 kullanımını haklı göstermek için önemli olacak mı? Şüpheliyim.
İsim Soyad

3
@FirstNameLastName 1 tabanlı dizinler, 0 tabanlı dizinlere göre hiçbir avantaj sağlamaz, ancak (biraz) daha kötü performans gösterirler. Bu, kazanç ne kadar küçük olursa olsun 0 tabanlı indeksleri haklı çıkarır. 1 tabanlı dizinler bazı avantajlar sunsa bile, C ++ 'ın ruhuna uygunluktan ziyade performansı seçmektir. C ++ bazen performansın her bitinin önemli olduğu bağlamlarda kullanılır ve bu "küçük" şeyler hızlı bir şekilde toplanabilir.
Branko Dimitrijevic

Evet, küçük şeylerin toplanabileceğini ve bazen büyük bir şey olabileceğini anlıyorum. Örneğin, yılda 1 $ fazla para değildir. Ancak, 2 milyar insan bağış yaparsa, insanlık için çok iyi yapabiliriz. Kötü performansa neden olabilecek kodlamada benzer bir örnek arıyorum.
Adı Soyadı

2
1'in çıkarılmasından ziyade, temel adres olarak dizi-1'in adresini kullanmalısınız. Bir zamanlar üzerinde çalıştığım bir derleyicide yaptıklarımız. Bu, çalışma zamanı çıkarma işlemini ortadan kaldırır. Bir derleyici yazarken, bu ek talimatlar çok önemlidir. Derleyici, her biri binlerce kez kullanılabilen binlerce program oluşturmak için kullanılacaktır ve bu n kare şeklindeki döngü içinde birkaç satırda fazladan 1 komut oluşabilir. Milyarlarca boşa döngü ekleyebilir.
progrmr

Hayır, derlendikten sonra performansa zarar vermez, sadece küçük bir inşa süresi ekleyecektir, çünkü sonunda makine koduna çevrilecektir.Yalnızca derleyici tasarımcılarına zarar verecektir.
Hassaan Akbar

12

Çünkü derleyici ve bağlayıcıyı basitleştirdi (yazması daha kolay).

Referans :

"... Belleği bir adres ve ofset ile yönlendirmek neredeyse tüm bilgisayar mimarilerindeki donanımda doğrudan temsil edilir, bu nedenle C'deki bu tasarım detayı derlemeyi kolaylaştırır"

ve

“... bu daha basit bir uygulama sağlar ...”


1
+1 Aşağı oylama neden emin değilim. Soruyu doğrudan cevaplamasa da, 0 tabanlı indeksleme insanlar veya matematikçiler için doğal değildir - bunun tek nedeni uygulamanın mantıksal olarak tutarlı (basit) olmasıdır.
phkahler

4
@phkahler: hata, dizi indekslerini indeks olarak çağıran yazarlar ve dillerdedir; bunu bir ofset olarak düşünüyorsanız, 0 tabanlı meslekten olmayan kişiler için de doğal hale gelir. Saati düşünün, ilk dakika 00:00 olarak yazılır, 00:01 değil, değil mi?
Yalan Ryan

3
+1 - bu muhtemelen en doğru cevaptır. C Djikistras gazetesinden önce gelir ve en erken “0'da başla” dillerinden biriydi. C, "yüksek seviyeli bir montajcı olarak" hayata başladı ve K & R'nin normalde bir temel adrese ve sıfırdan başlayan bir ofsete sahip olacağınız montajcıda yapıldığına yakından bağlı kalmak istemesi muhtemeldir.
James Anderson

Sorunun neden 0 tabanlı kullanıldığını düşündüm, hangisi daha iyi değil.
progrmr

2
Ben aşağıya vuramayacağım ama progrmr yukarıda yorumlandığı gibi üssü yürütme zamanı ne olursa olsun dizilerin adresini ayarlayarak halledilebilir ve bu derleyici veya yorumlayıcıda uygulanması önemsizdir, bu yüzden gerçekten daha basit uygulama yapmaz . Pascal
tanıklık

5

Dizi dizini her zaman sıfır ile başlar, taban adresin 2000 olduğunu varsayalım arr[i] = *(arr+i). Şimdi if i= 0, bu *(2000+0) temel adrese veya dizideki ilk öğenin adresine eşittir. bu indeks ofset olarak kabul edilir, bu nedenle varsayılan indeks sıfırdan başlar.


5

Aynı nedenden ötürü, Çarşamba olduğunda ve birisi Çarşamba gününe kadar kaç gün sorarsa, 1 yerine 0 deyin ve Çarşamba olduğunda ve birisi Perşembe gününe kadar kaç gün, 2 yerine 1 deyin.


6
Cevabınız sadece bir fikir meselesi gibi görünüyor.
heltonbiker

6
Endeks / ofsetleri eklemeyi işe yarayan şey budur. Örneğin, "bugün" 0 ve "yarın" 1 ise, "yarının yarın" 1 + 1 = 2'dir. Ancak "bugün" 1 ve "yarın" 2 ise, "yarının yarın" 2 + 2 değildir. Dizilerde, bu fenomen, bir dizinin bir alt aralığını kendi başına bir dizi olarak düşünmek istediğinizde meydana gelir.
R .. GitHub DURDURMAK BUZA YARDIM EDİN

7
3 şeyden oluşan bir koleksiyona "3 şey" adını vermek ve onları 1,2,3 olarak adlandırmak bir eksiklik değildir. Bunları birinciden ofsetle numaralandırmak, matematikte bile doğal değildir. Matematikte sıfırdan endekslediğiniz tek zaman, bir polinomda sıfırıncı güç (sabit terim) gibi bir şey eklemek istediğiniz zamandır.
phkahler

9
Re: "0 yerine 1 ile başlayan sayı dizileri, ciddi matematiksel düşünme eksikliği olan insanlar içindir." CLR'nin "Algoritmalara Giriş" sürümünde 1 tabanlı dizi indeksleme kullanılıyor; Yazarların matematiksel düşüncede eksiklikleri olduğunu düşünmüyorum.
RexE

Hayır, yedinci olanın endekste 6 veya birinciden 6 pozisyonda olduğunu söyleyebilirim.
R .. GitHub BUZA YARDIMCI DURDUR

2

Sıfır tabanlı numaralandırma için okuduğum en zarif açıklama, değerlerin sayı satırındaki işaretli yerlerde değil, aralarındaki boşluklarda depolanmadığı gözlemidir. İlk öğe sıfır ile bir arasında, diğeri bir ile iki arasında vb. Saklanır. N'inci öğe N-1 ve N arasında saklanır. Bir öğe, her iki taraftaki sayılar kullanılarak açıklanabilir. Münferit kalemler, altındaki sayılar kullanılarak açıklanan konvansiyonladır. Birine bir aralık (X, Y) verilirse, aşağıdaki sayıyı kullanarak tek tek sayıları tanımlamak, herhangi bir aritmetik kullanmadan ilk öğeyi tanımlayabileceği anlamına gelir (X öğesi), ancak son öğeyi (Y) tanımlamak için Y'den bir tane çıkarmak gerekir. 1). Yukarıdaki sayıyı kullanarak öğeleri tanımlamak, bir aralıktaki son öğeyi tanımlamayı kolaylaştırır (Y öğesi olacaktır),

Öğeleri üstlerindeki sayıya göre tanımlamak korkunç olmasa da, aralıktaki ilk öğeyi (X, Y) X'in üstünde olan olarak tanımlamak genellikle onu aşağıdaki gibi tanımlamaktan daha iyi çalışır (X + 1).


1

Teknik neden, işaretçinin bir dizinin bellek konumuna gitmesinin, dizinin ilk öğesinin içeriği olması gerçeğinden kaynaklanabilir. İşaretçiyi bir indeksle bildirirseniz, programlar elbette istediğiniz şey olmayan içeriğe erişmek için normalde işaretçinin bir değerini işaretçiye ekler.


1

1 tabanlı bir matristeki X, Y koordinatlarını kullanarak bir piksel ekranına erişmeye çalışın. Formül tamamen karmaşıktır. Neden karmaşık? Çünkü X, Y koordinatlarını bir sayıya, ofsete dönüştürüyorsunuz. Neden X, Y'yi ofsete dönüştürmelisiniz? Çünkü bellek, bilgisayarlar içinde sürekli bir bellek hücresi akışı (diziler) olarak bu şekilde düzenlenir. Bilgisayarlar dizi hücreleriyle nasıl ilgilenir? Ofsetleri kullanma (ilk hücreden yer değiştirmeler, sıfır tabanlı bir indeksleme modeli).

Bu nedenle, kodun bir noktasında, 1 tabanlı formülü 0 tabanlı bir formüle dönüştürmek için ihtiyacınız olan (veya derleyicinin ihtiyacı olan), çünkü bilgisayarlar bellekle bu şekilde ilgilenir.


1

Diyelim ki 5 boyutlu bir dizi oluşturmak istiyoruz diyelim
[5] = [2,3,5,9,8]

dizinin 1. öğesinin 100 konumuna işaret

etmesine izin verin ve dizin oluşturmanın 0.

Şimdi bir
elemanın

büyüklüğü 4-bit olduğu için 1. elementin konumunu indeks yardımıyla bulmalıyız (1. elementin konumunu hatırlayın)
-> indeks 1 dikkate alındığında pozisyon
boyut olacaktır (1) * tamsayı büyüklüğü (4) = 4,
böylece bize göstereceği gerçek konum

100 + 4 = 104

bu doğru değildir, çünkü başlangıç ​​konumu 100'dür
. 104'e değil 100'e işaret etmelidir,
bu

şimdi yanlıştır , endekslemeyi 0'dan aldığımızı varsayalım,
sonra
1. elemanın konumu
indeks (0) * tamsayı büyüklüğü olmalıdır (4) = 0

bu nedenle ->
1. elemanın konumu 100 + 0 = 100'dür

ve elemanın gerçek konumu
buydu, bu yüzden indeksleme 0'dan başlar;

Umarım amacını temizler.


1

Java geçmişindeyim. Bu soruya, kendi kendini açıklayan bir kağıda yazdığım aşağıdaki diyagramda cevap verdim

Ana Adımlar:

  1. Referans Oluşturma
  2. Dizi Örneği
  3. Verilerin diziye tahsisi

  • Ayrıca dizinin ne zaman başlatıldığına da dikkat edin .... Biz buna değer atayana kadar varsayılan olarak tüm bloklara sıfır tahsis edilir
  • Dizi sıfır ile başlar çünkü ilk adres referansı gösterecektir (resimde i: e - X102 + 0)

resim açıklamasını buraya girin

Not : Resimde gösterilen bloklar bellek temsilidir


0

her şeyden önce, dizilerin dahili olarak işaretçiler olarak kabul edildiğini bilmeniz gerekir, çünkü "dizinin kendisi dizinin ilk öğesinin adresini içerir"

ex. int arr[2] = {5,4};

dizinin adres 100'de başladığını düşünün, böylece öğe ilk öğesi 100 adresinde ve ikinci şimdi 104'te olacaktır, dizi dizini 1'den başlarsa,

arr[1]:-

bu işaretçiler ifadesinde şöyle yazılabilir.

 arr[1] = *(arr + 1 * (size of single element of array));

int boyutunu 4bayt olarak düşünün, şimdi,

arr[1] = *(arr + 1 * (4) );
arr[1] = *(arr + 4);

dizi adının ilk elemanının adresini içerdiğini bildiğimiz için şimdi arr = 100,

arr[1] = *(100 + 4);
arr[1] = *(104);

hangi verir,

arr[1] = 4;

Bu ifade nedeniyle, resmi ilk öğe olan 100 adresindeki öğeye erişemiyoruz,

Şimdi dizi dizininin 0'dan başladığını düşünün.

arr[0]:-

bu şu şekilde çözülecek

arr[0] = *(arr + 0 + (size of type of array));
arr[0] = *(arr + 0 * 4);
arr[0] = *(arr + 0);
arr[0] = *(arr);

şimdi, dizi adının ilk öğesinin adresini içerdiğini biliyoruz,

arr[0] = *(100);

doğru sonucu veren

arr[0] = 5;

bu nedenle dizi indeksi her zaman c'de 0'dan başlar.

kaynak: tüm detaylar "brian kerninghan ve dennis ritchie tarafından C programlama dili" kitabında yazılmıştır


0

Dizide, dizin başlangıç ​​öğesinden uzaklığı söyler. Bu nedenle, ilk eleman başlangıç ​​elemanından 0 uzaklıktadır. Bu yüzden dizi 0'dan başlar.


0

Bunun nedeni , dizide addresssağa işaret etmesi gerektiğidir element. Aşağıdaki diziyi varsayalım:

let arr = [10, 20, 40, 60]; 

Şimdi adres varlığın başlangıcını ele alalım 12ve boyutunu elementyönelik olacaktır 4 bytes.

address of arr[0] = 12 + (0 * 4) => 12
address of arr[1] = 12 + (1 * 4) => 16
address of arr[2] = 12 + (2 * 4) => 20
address of arr[3] = 12 + (3 * 4) => 24

Eğer öyle olsaydı değil zero-based , teknik olarak bizim ilk öğesi adres arrayolacaktır 16's konum olarak yanlıştır 12.


-2

Dizi adı, temel adrese işaret eden sabit bir işaretçidir. Arr [i] kullandığınızda derleyici bunu * (arr + i) olarak değiştirir. İnt aralığı -128 ila 127 olduğu için, derleyici -128 ila -1 arasında olduğunu düşünür. negatif sayılar ve 0 ila 128 arasında pozitif sayılar olduğundan dizi dizini her zaman sıfır ile başlar.


1
'İnt range -128 to 127' ile ne demek istiyorsun ? intEn az 16 bitlik bir aralığı desteklemek için bir tür gereklidir ve çoğu sistemde bu gün 32 biti desteklemektedir. Bence mantığınız kusurlu ve cevabınız diğer insanlar tarafından verilen diğer cevaplarda gerçekten düzelmiyor. Bunu silmenizi öneririm.
Jonathan Leffler
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.