Mengapa pengindeksan dimulai dengan nol dalam 'C'?

154

Mengapa pengindeksan dalam array dimulai dengan nol dalam C dan bukan dengan 1?

Nitish Pareek
sumber
7
Ini semua tentang Pointer!
medopal
3
kemungkinan duplikat Pertahankan susunan berbasis nol
dmckee --- ex-moderator kitten
3
Sebuah penunjuk (array) adalah arah memori dan indeks adalah offset dari arah memori itu, sehingga elemen pertama dari penunjuk (array) adalah orang yang mengimbangi sama dengan 0.
D33pN16h7
3
@ Radhirsch karena ketika kita menghitung satu set objek, kita mulai dengan menunjuk pada suatu objek dan mengatakan "satu".
phoog
1
Orang Amerika menghitung lantai (lantai) bangunan dari satu di lantai dasar; Inggris menghitung dari nol (lantai dasar), naik ke lantai satu, kemudian lantai dua, dll.
Jonathan Leffler

Jawaban:

116

Dalam C, nama array pada dasarnya adalah sebuah pointer [tetapi lihat komentar] , referensi ke lokasi memori, dan dengan demikian ekspresi array[n]merujuk ke nelemen lokasi memori jauh dari elemen awal. Ini berarti bahwa indeks digunakan sebagai offset. Elemen pertama dari array persis terkandung di lokasi memori yang merujuk (0 elemen), sehingga harus dilambangkan sebagai array[0].

Untuk info lebih lanjut:

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

Massimiliano Peluso
sumber
20
Nama array adalah nama array; bertentangan dengan kesalahpahaman umum, array bukanlah petunjuk dalam arti apa pun. Ekspresi array (seperti nama objek array) biasanya, tetapi tidak selalu , dikonversi menjadi pointer ke elemen pertama. Contoh: sizeof arrmenghasilkan ukuran objek array, bukan ukuran pointer.
Keith Thompson
Meskipun Anda jelas tidak bereaksi terhadap komentar @ KeithThompson, saya ingin Anda menggunakan kursus yang lebih menyinggung: " Dalam C, nama array pada dasarnya adalah sebuah pointer, referensi ke lokasi memori " - Tidak, itu bukan . Setidaknya tidak dalam sudut pandang generik. Sementara jawaban Anda sempurna menjawab pertanyaan dengan cara bagaimana 0 sebagai awal indeks itu penting, kalimat pertama jelas salah. Array tidak selalu membusuk ke pointer ke elemen pertamanya.
RobertS mendukung Monica Cellio
Kutipan dari standar C, (C18), 6.3.2.1/4: " Kecuali ketika itu adalah operan dari sizeofoperator, atau &operator unary , atau string literal yang digunakan untuk menginisialisasi array, ekspresi yang memiliki tipe" array tipe "dikonversi ke ekspresi dengan tipe" pointer to type "yang menunjuk ke elemen awal objek array dan bukan nilai. Jika objek array memiliki kelas penyimpanan terdaftar, perilaku tidak ditentukan. "
RobertS mendukung Monica Cellio
Juga pembusukan ini terjadi dengan cara yang lebih "implisit" atau "secara formal" daripada yang disarankan di sini; tidak ada kerusakan pada objek pointer di memori yang terlibat. Ini adalah objek dari pertanyaan ini: Apakah pembusukan array ke pointer berubah menjadi objek pointer? - Harap edit jawaban Anda agar sepenuhnya benar.
RobertS mendukung Monica Cellio
103

Pertanyaan ini diposting lebih dari setahun yang lalu, tetapi begini ...


Tentang alasan di atas

Sementara artikel Dijkstra (sebelumnya dirujuk dalam jawaban yang sekarang dihapus ) masuk akal dari perspektif matematika, itu tidak relevan ketika datang ke pemrograman.

Keputusan yang diambil oleh spesifikasi bahasa & perancang-kompiler didasarkan pada keputusan yang dibuat oleh perancang sistem komputer untuk mulai menghitung pada 0.


Alasan yang mungkin

Mengutip dari Permohonan Damai oleh Danny Cohen.

Untuk setiap basis b, b ^ N pertama bilangan bulat non-negatif diwakili oleh digit N persis (termasuk nol di depan) hanya jika penomoran dimulai pada 0.

Ini dapat diuji dengan cukup mudah. Di base-2, ambil 2^3 = 8 nomor 8 adalah:

  • 8 (biner: 1000) jika kita mulai menghitung 1
  • 7 (biner: 111) jika kita mulai menghitung pada 0

111dapat direpresentasikan menggunakan 3bit, sementara 1000akan membutuhkan bit tambahan (4 bit).


Mengapa ini relevan?

Alamat memori komputer memiliki 2^Nsel yang ditangani oleh Nbit. Sekarang jika kita mulai menghitung pada 1, 2^Nsel akan membutuhkan N+1garis alamat. Bit ekstra diperlukan untuk mengakses tepat 1 alamat. ( 1000dalam kasus di atas.). Cara lain untuk menyelesaikannya adalah meninggalkan alamat terakhir tidak dapat diakses, dan menggunakan Nbaris alamat.

Keduanya merupakan solusi sub-optimal , dibandingkan dengan penghitungan mulai pada 0, yang akan membuat semua alamat dapat diakses, menggunakan Ngaris alamat yang tepat !


Kesimpulan

Keputusan untuk mulai menghitung 0, sejak itu meresapi semua sistem digital , termasuk perangkat lunak yang menjalankannya, karena membuatnya lebih mudah bagi kode untuk menerjemahkan apa yang dapat ditafsirkan oleh sistem yang mendasarinya. Jika tidak, akan ada satu operasi terjemahan yang tidak perlu antara mesin dan pemrogram, untuk setiap akses array. Itu membuat kompilasi lebih mudah.


Mengutip dari kertas:

masukkan deskripsi gambar di sini

Anirudh Ramanathan
sumber
2
Bagaimana jika mereka baru saja menghapus bit 0 .. maka nomor 8 masih akan menjadi 111 ...
DanMatlin
2
Apakah Anda benar-benar menyarankan modifikasi aritmatika dasar agar sesuai? Tidakkah Anda berpikir apa yang kita miliki hari ini adalah solusi yang jauh lebih baik?
Anirudh Ramanathan
Bertahun-tahun kemudian, nilai 2 cnt saya. Dalam pengalaman saya (~ 35 tahun pemrograman) modulo atau operasi penambahan modular dalam satu atau lain bentuk muncul secara mengejutkan sering. Dengan nol basis urutan berikutnya adalah (i + 1)% n tetapi dengan basis 1 ia datang (i-1)% n) +1, jadi saya pikir 0 berbasis lebih disukai. Ini muncul dalam matematika dan pemrograman cukup sering. Mungkin hanya saya atau bidang tempat saya bekerja.
nyholku
Sementara semua alasan bagus saya pikir itu jauh lebih sederhana: a[b]diimplementasikan seperti *(a+b)pada kompiler awal. Bahkan saat ini Anda masih dapat menulis 2[a]bukan a[2]. Sekarang jika indeks tidak dimulai pada 0 maka a[b]akan berubah menjadi *(a+b-1). Ini akan membutuhkan 2 tambahan pada CPU pada waktu bukan 0, yang berarti setengah dari kecepatan. Jelas tidak diinginkan.
Goswin von Brederlow
1
Hanya karena Anda ingin 8 negara bagian, itu tidak berarti Anda harus memiliki angka 8 di dalamnya. Sakelar lampu di rumah saya dengan senang hati menyatakan status "lampu menyala", "padam", tanpa pernah bertanya-tanya mengapa mereka tidak mewakili angka 2.
Spyryto
27

Karena 0 adalah seberapa jauh dari pointer ke kepala array ke elemen pertama array.

Mempertimbangkan:

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

Untuk mengakses 0 kami lakukan:

foo[0] 

Tapi foo terurai menjadi pointer, dan akses di atas memiliki cara aritmatika pointer analog untuk mengaksesnya

*(foo + 0)

Aritmatika penunjuk hari ini tidak sering digunakan. Namun ketika masih jauh, itu adalah cara yang mudah untuk mengambil alamat dan memindahkan X "ints" dari titik awal. Tentu saja jika Anda ingin tetap di tempat Anda sekarang, Anda tinggal menambahkan 0!

Doug T.
sumber
23

Karena indeks berbasis 0 memungkinkan ...

array[index]

... untuk diimplementasikan sebagai ...

*(array + index)

Jika indeks berbasis 1, kompiler harus menghasilkan:, *(array + index - 1)dan "-1" ini akan merusak kinerja.

Branko Dimitrijevic
sumber
4
Anda memunculkan poin yang menarik. Ini dapat merusak kinerja. Tetapi apakah kinerja yang dicapai signifikan untuk membenarkan penggunaan 0 sebagai indeks awal? Aku meragukan itu.
FirstName LastName
3
@FirstNameLastName indeks berbasis 1 tidak menawarkan keuntungan lebih dari indeks berbasis 0 namun kinerjanya (sedikit) lebih buruk. Itu membenarkan indeks berbasis 0 tidak peduli seberapa "kecil" keuntungannya. Bahkan jika indeks berbasis 1 menawarkan beberapa keuntungan, itu adalah semangat C ++ untuk memilih kinerja daripada kenyamanan. C ++ kadang-kadang digunakan dalam konteks di mana setiap bit kinerja penting, dan hal-hal "kecil" ini dapat dengan cepat bertambah.
Branko Dimitrijevic
Ya, saya mengerti bahwa hal-hal kecil dapat bertambah dan terkadang menjadi hal besar. Misalnya, $ 1 per tahun tidak banyak uang. Tetapi, jika 2 miliar orang menyumbangkannya, maka kita dapat melakukan banyak hal baik untuk kemanusiaan. Saya mencari contoh serupa dalam pengkodean yang dapat menyebabkan kinerja yang buruk.
FirstName LastName
2
Daripada mengurangi 1, Anda harus menggunakan alamat array-1 sebagai alamat dasar. Itu yang kami lakukan di kompiler yang pernah saya kerjakan. Itu menghilangkan pengurangan runtime. Saat Anda menulis kompiler, instruksi tambahan itu sangat berarti. Compiler akan digunakan untuk menghasilkan ribuan program, yang masing-masingnya dapat digunakan ribuan kali, dan bahwa instruksi tambahan 1 dapat terjadi di beberapa baris di dalam n squared loop. Itu dapat menambahkan hingga miliaran siklus terbuang.
program
Tidak itu tidak akan merusak kinerja setelah dikompilasi, itu hanya akan menambah waktu membangun kecil karena pada akhirnya akan diterjemahkan ke kode mesin. Itu hanya akan merugikan desainer kompiler.
Hassaan Akbar
12

Karena itu membuat kompiler dan linker lebih sederhana (lebih mudah untuk menulis).

Referensi :

"... Mengacu memori dengan alamat dan offset diwakili langsung dalam perangkat keras pada hampir semua arsitektur komputer, jadi detail desain ini di C membuat kompilasi lebih mudah"

dan

"... ini membuat implementasi yang lebih sederhana ..."

program
sumber
1
+1 Tidak yakin mengapa suara turun. Meskipun tidak langsung menjawab pertanyaan, pengindeksan berbasis 0 tidak alami untuk orang atau ahli matematika - satu-satunya alasan dilakukan adalah karena implementasi konsisten secara logis (sederhana).
phkahler
4
@ phkahler: kesalahannya ada pada penulis dan bahasa yang memanggil indeks array sebagai indeks; jika Anda menganggapnya sebagai offset, maka berbasis 0 menjadi alami untuk orang awam juga. Pertimbangkan jamnya, menit pertama ditulis sebagai 00:00, bukan 00:01 bukan?
Lie Ryan
3
+1 - ini mungkin jawaban yang paling benar. C mendahului kertas Djikistras dan merupakan salah satu bahasa "awal pada 0" yang paling awal. C memulai kehidupan "sebagai assembler tingkat tinggi" dan kemungkinan bahwa K&R ingin menempel sedekat mungkin dengan yang dilakukan pada assembler di mana Anda biasanya akan memiliki alamat basis ditambah offset mulai dari nol.
James Anderson
Saya pikir pertanyaannya adalah mengapa 0 berbasis digunakan, bukan yang lebih baik.
progrmr
2
Saya tidak akan downvote tetapi sebagai progrmr berkomentar di atas basis dapat diurus dengan menyesuaikan alamat array sehingga terlepas dari waktu eksekusi basis sama dan ini sepele untuk diterapkan dalam kompiler atau juru bahasa sehingga tidak benar-benar membuat implementasi lebih sederhana . Saksikan Pascal tempat Anda dapat menggunakan rentang apa pun untuk mengindeks IIRC, sudah 25 tahun;)
nyholku
5

Indeks array selalu dimulai dengan nol. Mari kita asumsikan alamat basis adalah 2000. Sekarang arr[i] = *(arr+i). Sekarang if i= 0, ini berarti *(2000+0) sama dengan alamat dasar atau alamat elemen pertama dalam array. indeks ini diperlakukan sebagai offset, sehingga indeks bydeafault dimulai dari nol.

Amit Prakash
sumber
5

Untuk alasan yang sama bahwa, ketika hari Rabu dan seseorang bertanya berapa hari sampai hari Rabu, Anda mengatakan 0 daripada 1, dan bahwa ketika hari Rabu dan seseorang bertanya berapa hari hingga Kamis, Anda mengatakan 1 daripada 2.

R .. GitHub BERHENTI MEMBANTU ES
sumber
6
Jawaban Anda sepertinya hanya masalah pendapat saja.
heltonbiker
6
Nah, itu yang membuat menambahkan indeks / offset bekerja. Misalnya jika "hari ini" adalah 0 dan "besok" adalah 1, "besok besok" adalah 1 + 1 = 2. Tetapi jika "hari ini" adalah 1 dan "besok" adalah 2, "besok besok" bukan 2 + 2. Dalam array, fenomena ini terjadi kapan pun Anda ingin mempertimbangkan subrange dari array sebagai array sendiri.
R .. GitHub BERHENTI MEMBANTU ICE
7
Menyebut koleksi 3 hal "3 hal" dan memberi angka 1,2,3 bukanlah kekurangan. Menomori mereka dengan offset dari yang pertama adalah tidak alami bahkan dalam matematika. Satu-satunya waktu Anda mengindeks dari nol dalam matematika adalah ketika Anda ingin memasukkan sesuatu seperti kekuatan nol-(istilah konstan) dalam polinomial.
phkahler
9
Re: "Array penomoran dimulai dengan 1 daripada 0 adalah untuk orang-orang dengan kekurangan pemikiran matematika." Edisi CLR "Introduction to Algorithms" CLR saya menggunakan pengindeksan array berbasis 1; Saya tidak berpikir penulis memiliki kekurangan dalam pemikiran matematika.
RexE
Tidak, saya akan mengatakan yang ketujuh ada di indeks 6, atau 6 posisi jauh dari yang pertama.
R .. GitHub BERHENTI MEMBANTU ICE
2

Penjelasan paling elegan yang pernah saya baca untuk penomoran berbasis nol adalah pengamatan bahwa nilai-nilai tidak disimpan di tempat-tempat yang ditandai pada garis bilangan, melainkan di ruang di antara mereka. Item pertama disimpan antara nol dan satu, item berikutnya antara satu dan dua, dll. Item N disimpan di antara N-1 dan N. Berbagai item dapat dijelaskan menggunakan angka-angka di kedua sisi. Masing-masing item berdasarkan konvensi dijelaskan menggunakan angka-angka di bawahnya. Jika seseorang diberi rentang (X, Y), mengidentifikasi nomor individual menggunakan angka di bawah ini berarti bahwa seseorang dapat mengidentifikasi item pertama tanpa menggunakan aritmatika (itu item X) tetapi seseorang harus mengurangi satu dari Y untuk mengidentifikasi item terakhir (Y -1). Mengidentifikasi item menggunakan nomor di atas akan membuatnya lebih mudah untuk mengidentifikasi item terakhir dalam suatu rentang (itu akan menjadi item Y),

Meskipun tidak akan mengerikan untuk mengidentifikasi item berdasarkan nomor di atasnya, mendefinisikan item pertama dalam rentang (X, Y) sebagai item di atas X umumnya bekerja lebih baik daripada mendefinisikannya sebagai yang di bawah ini (X + 1).

supercat
sumber
1

Alasan teknis mungkin berasal dari fakta bahwa penunjuk ke lokasi memori array adalah isi dari elemen pertama array. Jika Anda mendeklarasikan pointer dengan indeks satu, program biasanya akan menambahkan nilai itu ke pointer untuk mengakses konten yang bukan yang Anda inginkan, tentu saja.

rampok
sumber
1

Cobalah untuk mengakses layar piksel menggunakan koordinat X, Y pada matriks berbasis 1. Rumusnya sangat kompleks. Mengapa rumit? Karena Anda akhirnya mengonversi koordinat X, Y menjadi satu angka, offset. Mengapa Anda perlu mengonversi X, Y ke offset? Karena itulah cara memori diatur di dalam komputer, sebagai aliran sel memori (array) yang berkelanjutan. Bagaimana komputer menangani sel array? Menggunakan offset (perpindahan dari sel pertama, model pengindeksan berbasis nol).

Jadi pada titik tertentu dalam kode yang Anda butuhkan (atau kebutuhan kompilator) untuk mengubah rumus 1-basis menjadi rumus berbasis 0 karena itulah cara komputer menangani memori.

Gianluca Ghettini
sumber
1

Misalkan kita ingin membuat array dengan ukuran 5
int array [5] = [2,3,5,9,8]

mari elemen pertama dari array diarahkan ke lokasi 100

dan mari kita pertimbangkan pengindeksan dimulai dari 1 bukan dari 0.

sekarang kita harus menemukan lokasi elemen 1 dengan bantuan indeks
(ingat lokasi elemen 1 adalah 100)

karena ukuran bilangan bulat adalah 4-bit
karena itu -> dengan mempertimbangkan indeks 1 posisi akan menjadi
ukuran of index (1) * size of integer (4) = 4
sehingga posisi aktual yang akan ditunjukkan kepada kita adalah

100 + 4 = 104

yang tidak benar karena lokasi awal berada pada 100.
seharusnya menunjuk ke 100 bukan pada 104
ini salah

sekarang misalkan kita telah mengambil pengindeksan dari 0
maka
posisi elemen 1 harus
ukuran indeks (0) * ukuran bilangan bulat (4) = 0

karena itu ->
lokasi elemen 1 adalah 100 + 0 = 100

dan itu adalah lokasi sebenarnya dari elemen
ini mengapa pengindeksan dimulai pada 0;

Saya harap ini akan menjelaskan maksud Anda.

sahil singh
sumber
1

Saya dari latar belakang Java. Saya telah mempresentasikan jawaban untuk pertanyaan ini dalam diagram di bawah ini yang telah saya tulis di selembar kertas yang cukup jelas

Langkah Utama:

  1. Membuat Referensi
  2. Instansiasi Array
  3. Alokasi Data ke array

  • Perhatikan juga ketika array baru saja dipakai .... Nol dialokasikan ke semua blok secara default sampai kami menetapkan nilai untuknya
  • Array dimulai dengan nol karena alamat pertama akan menunjuk ke referensi (i: e - X102 + 0 pada gambar)

masukkan deskripsi gambar di sini

Catatan : Blok yang ditunjukkan pada gambar adalah representasi memori

Setan
sumber
0

pertama-tama Anda perlu tahu bahwa array secara internal dianggap sebagai pointer karena "nama array itu sendiri berisi alamat elemen pertama array"

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

pertimbangkan bahwa array dimulai pada alamat 100 sehingga elemen elemen pertama akan di alamat 100 dan yang kedua akan berada di 104 sekarang, pertimbangkan bahwa jika indeks array dimulai dari 1, maka

arr[1]:-

ini dapat ditulis dalam ekspresi pointer seperti ini-

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

pertimbangkan ukuran int adalah 4bytes, sekarang,

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

seperti yang kita ketahui nama array berisi alamat elemen pertama sehingga arr = 100 sekarang,

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

pemberian yang mana,

arr[1] = 4;

karena ungkapan ini kami tidak dapat mengakses elemen di alamat 100 yang merupakan elemen pertama resmi,

sekarang pertimbangkan indeks array mulai dari 0, jadi

arr[0]:-

ini akan diselesaikan sebagai

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

sekarang, kita tahu bahwa nama array mengandung alamat elemen pertamanya jadi,

arr[0] = *(100);

yang memberikan hasil yang benar

arr[0] = 5;

Oleh karena itu indeks array selalu dimulai dari 0 di c.

referensi: semua detail ditulis dalam buku "Bahasa pemrograman C oleh brian kerninghan dan dennis ritchie"

akshay chaudhari
sumber
0

Dalam array, indeks memberi tahu jarak dari elemen awal. Jadi, elemen pertama berjarak 0 dari elemen awal. Jadi, itu sebabnya array mulai dari 0.

Rishi Raj Tandon
sumber
0

Itu karena addressharus menunjuk ke kanan elementdalam array. Mari kita asumsikan array di bawah ini:

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

Mari kita mempertimbangkan awal keberadaan alamat 12dan ukuran elementbe 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

Jika itu tidak zero-based , secara teknis alamat elemen pertama kami di arrayakan 16yang salah karena lokasi itu adalah 12.

Thalaivar
sumber
-2

Nama array adalah pointer konstan yang menunjuk ke alamat basis. Ketika Anda menggunakan arr [i] kompiler memanipulasi sebagai * (arr + i). Karena kisaran int adalah -128 hingga 127, kompiler berpikir bahwa -128 ke -1 adalah angka negatif dan 0 hingga 128 adalah angka positif. Jadi indeks array selalu dimulai dengan nol.

Niks
sumber
1
Apa yang Anda maksud dengan 'kisaran int adalah -128 hingga 127' ? intDiperlukan suatu jenis untuk mendukung setidaknya kisaran 16-bit, dan pada kebanyakan sistem dewasa ini mendukung 32-bit. Saya pikir logika Anda cacat, dan jawaban Anda benar-benar tidak meningkat pada jawaban lain yang sudah disediakan oleh orang lain. Saya sarankan menghapus ini.
Jonathan Leffler