Saya telah menemukan pengalaman aneh dalam pemrograman C. Pertimbangkan kode ini:
int main(){
int array1[6] = {0, 1, 2, 3, 4, 5};
int array2[6] = {6, 7, 8, 9, 10, 11};
printf("%d\n", array1[-1]);
return 0;
}
Ketika saya mengkompilasi dan menjalankan ini, saya tidak mendapatkan kesalahan atau peringatan. Seperti kata dosen saya, indeks array -1
mengakses variabel lain. Saya masih bingung, mengapa ada bahasa pemrograman yang memiliki kemampuan ini? Maksud saya, mengapa mengizinkan indeks array negatif?
programming-languages
arrays
c
Mohammed Fawzan
sumber
sumber
-1
-array dan merujuk ke elemen subarray adalah cara yang benar-benar valid untuk merujuk ke elemen sebelum array dalam array yang lebih besar. Yang lain adalah bahwa jika indeks tidak valid, program tidak valid, tetapi dalam kebanyakan implementasi Anda akan mendapatkan perilaku buruk yang diam, bukan kesalahan di luar jangkauan.Jawaban:
Operasi pengindeksan array
a[i]
mendapatkan artinya dari fitur-fitur C berikutSintaksnya
a[i]
setara dengan*(a + i)
. Oleh karena itu sah untuk mengatakan5[a]
untuk mendapatkan elemen ke-5 daria
.Pointer-aritmatika mengatakan bahwa diberi pointer
p
dan integeri
,p + i
pointerp
maju olehi * sizeof(*p)
byteNama array
a
dengan cepat berpindah ke sebuah pointer ke elemen 0 daria
Akibatnya, pengindeksan array adalah kasus khusus pengindeksan pointer. Karena pointer dapat menunjuk ke suatu tempat di dalam array, setiap ekspresi arbitrer yang terlihat seperti
p[-1]
itu tidak salah dengan pemeriksaan, dan kompiler tidak (tidak bisa) menganggap semua ekspresi sebagai kesalahan.Contoh Anda di
a[-1]
manaa
sebenarnya nama array sebenarnya tidak valid. IIRC, itu tidak terdefinisi jika ada nilai pointer yang berarti sebagai hasil dari ekspresi dia - 1
manaa
diketahui menjadi pointer ke elemen 0 array. Jadi, kompiler yang pintar bisa mendeteksi ini dan menandainya sebagai kesalahan. Kompiler lain masih dapat memenuhi persyaratan sementara memungkinkan Anda untuk menembak diri sendiri dengan memberikan pointer ke slot tumpukan acak.Jawaban ilmu komputer adalah:
Dalam C,
[]
operator didefinisikan pada pointer, bukan array. Secara khusus, itu didefinisikan dalam hal pointer aritmatika dan pointer dereference.Dalam C, sebuah pointer secara abstrak adalah tuple
(start, length, offset)
dengan kondisi itu0 <= offset <= length
. Pointer aritmatika pada dasarnya mengangkat aritmatika pada offset, dengan peringatan bahwa jika hasil operasi melanggar kondisi pointer, itu adalah nilai yang tidak ditentukan. De-referensi pointer menambahkan kendala tambahan ituoffset < length
.C memiliki gagasan
undefined behaviour
yang memungkinkan kompiler untuk secara konkret menyatakan bahwa tuple sebagai angka tunggal, dan tidak harus mendeteksi pelanggaran kondisi pointer. Setiap program yang memenuhi semantik abstrak akan aman dengan semantik konkret (lossy). Apa pun yang melanggar semantik abstrak dapat, tanpa komentar, diterima oleh kompiler dan dapat melakukan apa pun yang ingin dilakukan dengannya.sumber
Array hanya ditata sebagai potongan memori yang berdekatan. Akses array seperti [i] dikonversi ke akses ke alamat lokasi memori. Dari (a) + i. Kode
a[-1]
ini dapat dimengerti dengan sempurna, hanya merujuk ke alamat satu sebelum dimulainya array.Ini mungkin terlihat gila, tetapi ada banyak alasan mengapa ini diizinkan:
a[-1]
valid. Sebagai contoh, jika saya tahu bahwaa
sebenarnya bukan awal dari array, tetapi sebuah pointer ke tengah array, makaa[-1]
cukup mendapatkan elemen array yang ada di sebelah kiri pointer.sumber
a[-1]
masuk akal untuk beberapa kasusa
, dalam kasus khusus ini jelas ilegal (tetapi tidak ditangkap oleh kompiler)Seperti jawaban lain menjelaskan, ini adalah perilaku yang tidak terdefinisi dalam C. Pertimbangkan bahwa C didefinisikan (dan sebagian besar digunakan) sebagai "assembler tingkat tinggi". Pengguna C menghargainya karena kecepatannya yang tidak kenal kompromi, dan memeriksa hal-hal saat runtime (sebagian besar) di luar pertanyaan demi kinerja semata. Beberapa konstruksi C yang terlihat tidak masuk akal untuk orang-orang yang datang dari bahasa lain masuk akal dalam bahasa C, seperti ini
a[-1]
. Ya, itu tidak selalu masuk akal (sumber
Seseorang dapat menggunakan fitur seperti itu untuk menulis metode alokasi memori yang mengakses memori secara langsung. Salah satu penggunaan tersebut adalah untuk memeriksa blok memori sebelumnya menggunakan indeks array negatif untuk menentukan apakah dua blok dapat digabungkan. Saya telah menggunakan fitur ini ketika saya mengembangkan manajer memori yang tidak mudah menguap.
sumber
C tidak diketik dengan kuat. Kompiler C standar tidak akan memeriksa batas array. Hal lain adalah bahwa array dalam C hanyalah blok memori yang berdekatan dan pengindeksan dimulai pada 0 sehingga indeks -1 adalah lokasi dari bit-pattern apa pun sebelumnya
a[0]
.Bahasa lain mengeksploitasi indeks negatif dengan cara yang baik. Dalam Python,
a[-1]
akan mengembalikan elemen terakhir,a[-2]
akan mengembalikan elemen kedua ke terakhir dan seterusnya.sumber
int
, jadia[-5]
dan, lebih umum,int i; ... a[i] = ...;
diketik dengan benar. Kesalahan indeks hanya terdeteksi pada saat runtime. Tentu saja, kompiler pintar dapat mendeteksi beberapa pelanggaran.Dengan kata sederhana:
Semua variabel (termasuk array) di C disimpan dalam memori. Katakanlah Anda memiliki 14 byte "memori" dan Anda menginisialisasi yang berikut:
Juga, pertimbangkan ukuran int sebagai 2 byte. Kemudian, secara hipotetis, dalam 2 byte pertama memori integer a akan disimpan. Dalam 2 byte berikutnya integer posisi pertama array akan disimpan (itu berarti array [0]).
Kemudian, ketika Anda mengatakan array [-1] seperti merujuk ke integer yang disimpan dalam memori yang tepat sebelum array [0], yang dalam kita adalah, secara hipotesis, integer a. Pada kenyataannya, ini bukan cara variabel disimpan dalam memori.
sumber
sumber