Dengan array, mengapa case [5] == 5 [a]?

1622

Seperti yang ditunjukkan Joel dalam Stack Overflow podcast # 34 , dalam Bahasa Pemrograman C (alias: K & R), disebutkan properti array ini di C:a[5] == 5[a]

Joel mengatakan bahwa itu karena pointer aritmatika tetapi saya masih tidak mengerti. Kenapa begitua[5] == 5[a] ?

Dina
sumber
48
apakah sesuatu seperti [+] juga berfungsi seperti * (a ++) ATAU * (++ a)?
Egon
45
@Egon: Itu sangat kreatif tetapi sayangnya itu bukan cara kerja kompiler. Compiler mengartikan a[1]sebagai serangkaian token, bukan string: * ({lokasi integer} a {operator} + {integer} 1) sama dengan * ({integer} 1 {operator} + {lokasi integer} a) tetapi tidak sama dengan * ({lokasi integer} a {operator} + {operator} +)
Dinah
11
Variasi gabungan yang menarik tentang hal ini diilustrasikan dalam akses array yang tidak logis , di mana Anda memiliki char bar[]; int foo[];dan foo[i][bar]digunakan sebagai ekspresi.
Jonathan Leffler
5
@ ElldCitchundrum, mengapa Anda berpikir 'kompiler tidak dapat memeriksa bahwa bagian kiri adalah pointer'? Ya bisa. Memang benar bahwa a[b]= *(a + b)untuk apa pun yang diberikan adan b, tapi itu adalah pilihan bebas perancang bahasa untuk +didefinisikan komutatif untuk semua jenis. Tidak ada yang bisa mencegah mereka dari melarang i + psementara mengizinkan p + i.
ach
13
@Andrey One biasanya mengharapkan +menjadi komutatif, jadi mungkin masalah sebenarnya adalah memilih untuk membuat operasi pointer menyerupai aritmatika, alih-alih merancang operator offset yang terpisah.
Eldritch Conundrum

Jawaban:

1926

Standar C mendefinisikan []operator sebagai berikut:

a[b] == *(a + b)

Karena itu a[5]akan dievaluasi untuk:

*(a + 5)

dan 5[a]akan mengevaluasi untuk:

*(5 + a)

aadalah pointer ke elemen pertama array. a[5]adalah nilai yang 5 elemen lebih jauh dari a, yang sama dengan *(a + 5), dan dari matematika sekolah dasar kita tahu mereka sama (penambahan bersifat komutatif ).

Mehrdad Afshari
sumber
325
Saya bertanya-tanya apakah itu tidak lebih seperti * ((5 * sizeof (a)) + a). Penjelasan yang bagus.
John MacIntyre
92
@Dinah: Dari perspektif C-compiler, Anda benar. Tidak diperlukan ukuran dan ekspresi yang saya sebutkan adalah SAMA. Namun, kompiler akan mempertimbangkan ukuran ketika memproduksi kode mesin. Jika a adalah array int, a[5]akan dikompilasi ke sesuatu seperti mov eax, [ebx+20]bukannya[ebx+5]
Mehrdad Afshari
12
@Dinah: A adalah alamat, katakan 0x1230. Jika a berada dalam array int 32-bit, maka [0] adalah pada 0x1230, a [1] pada 0x1234, a [2] pada 0x1238 ... a [5] pada x1244 dll. Jika kita hanya menambahkan 5 ke 0x1230, kami mendapatkan 0x1235, yang salah.
James Curran
36
@ sr105: Itu adalah kasus khusus untuk operator +, di mana salah satu operan adalah pointer dan yang lainnya adalah integer. Standar mengatakan bahwa hasilnya adalah tipe pointer. Kompiler / harus / cukup pintar.
aib
48
"dari matematika sekolah dasar kita tahu mereka sama" - Saya mengerti bahwa Anda menyederhanakan, tapi saya dengan mereka yang merasa seperti ini terlalu menyederhanakan. Bukan SD itu *(10 + (int *)13) != *((int *)10 + 13). Dengan kata lain, ada lebih banyak yang terjadi di sini daripada aritmatika sekolah dasar. Commutativity bergantung secara kritis pada kompiler yang mengenali operand mana yang merupakan pointer (dan untuk ukuran objek apa). Dengan kata lain (1 apple + 2 oranges) = (2 oranges + 1 apple),, tapi (1 apple + 2 oranges) != (1 orange + 2 apples).
LarsH
288

Karena akses array didefinisikan dalam hal pointer. a[i]didefinisikan sebagai mean *(a + i), yang komutatif.

David Thornley
sumber
42
Array tidak didefinisikan dalam hal pointer, tetapi akses ke sana adalah.
Lightness Races in Orbit
5
Saya akan menambahkan "jadi sama dengan *(i + a), yang dapat ditulis sebagai i[a]".
Jim Balter
4
Saya menyarankan Anda menyertakan kutipan dari standar, yaitu sebagai berikut: 6.5.2.1: 2 Ekspresi postfix diikuti oleh ekspresi dalam tanda kurung siku [] adalah penunjukan subscript dari elemen elemen array. Definisi operator subskrip [] adalah bahwa E1 [E2] identik dengan (* ((E1) + (E2)))). Karena aturan konversi yang berlaku untuk operator biner +, jika E1 adalah objek array (ekuivalen, pointer ke elemen awal objek array) dan E2 adalah integer, E1 [E2] menunjuk elemen E2-th dari E1 (menghitung dari nol).
Vality
Agar lebih benar: Array peluruhan ke dalam pointer ketika Anda mengaksesnya.
12431234123412341234123
Nitpick: Tidak masuk akal untuk mengatakan bahwa " *(a + i)bersifat komutatif". Namun, *(a + i) = *(i + a) = i[a]karena penambahan bersifat komutatif.
Andreas Rejbrand
231

Saya pikir ada sesuatu yang terlewatkan oleh jawaban lain.

Ya, p[i]secara definisi setara dengan *(p+i), yang (karena penambahan komutatif) setara dengan *(i+p), yang (sekali lagi, menurut definisi []operator) setara dengan i[p].

(Dan dalam array[i], nama array secara implisit dikonversi menjadi pointer ke elemen pertama array.)

Tetapi komutatifitas penambahan tidak begitu jelas dalam kasus ini.

Ketika kedua operan adalah dari jenis yang sama, atau bahkan dari jenis numerik yang berbeda yang dipromosikan ke jenis umum, komutatif masuk akal: x + y == y + x.

Tetapi dalam kasus ini kita berbicara secara spesifik tentang pointer aritmatika, di mana satu operan adalah pointer dan yang lainnya adalah integer. (Integer + integer adalah operasi yang berbeda, dan pointer + pointer tidak masuk akal.)

Deskripsi standar C +operator ( N1570 6.5.6) mengatakan:

Sebagai tambahan, kedua operan harus memiliki tipe aritmatika, atau satu operan harus menjadi pointer ke tipe objek lengkap dan yang lainnya harus memiliki tipe integer.

Itu bisa dengan mudah dikatakan:

Sebagai tambahan, kedua operan harus memiliki tipe aritmatika, atau operan kiri harus menjadi pointer ke tipe objek lengkap dan operan kanan harus memiliki tipe integer.

dalam hal ini keduanya i + pdan i[p]akan ilegal.

Dalam istilah C ++, kami benar-benar memiliki dua set +operator kelebihan beban , yang secara longgar dapat digambarkan sebagai:

pointer operator+(pointer p, integer i);

dan

pointer operator+(integer i, pointer p);

dimana hanya yang pertama yang benar-benar diperlukan.

Jadi mengapa demikian?

C ++ mewarisi definisi ini dari C, yang mendapatkannya dari B (komutatifitas pengindeksan array secara eksplisit disebutkan dalam referensi pengguna 1972 ke B ), yang mendapatkannya dari BCPL (manual bertanggal 1967), yang mungkin mendapatkannya dari gen bahasa sebelumnya (CPL? Algol?).

Jadi gagasan bahwa pengindeksan array didefinisikan dalam hal penambahan, dan penambahan itu, bahkan penunjuk dan bilangan bulat, adalah komutatif, kembali beberapa dekade, ke bahasa leluhur C.

Bahasa-bahasa itu diketik kurang kuat daripada C modern. Secara khusus, perbedaan antara pointer dan integer sering diabaikan. (Pemrogram C awal kadang-kadang menggunakan pointer sebagai bilangan bulat yang tidak ditandatangani, sebelum unsignedkata kunci ditambahkan ke bahasa.) Jadi ide membuat penambahan non-komutatif karena operan dari tipe yang berbeda mungkin tidak akan terjadi pada perancang bahasa tersebut. Jika pengguna ingin menambahkan dua "hal", apakah "hal" itu adalah bilangan bulat, pointer, atau sesuatu yang lain, itu tidak sesuai dengan bahasa untuk mencegahnya.

Dan selama bertahun-tahun, setiap perubahan pada aturan itu akan merusak kode yang ada (meskipun standar ANSI C 1989 mungkin merupakan peluang yang baik).

Mengubah C dan / atau C ++ untuk mengharuskan meletakkan pointer di sebelah kiri dan integer di sebelah kanan dapat merusak beberapa kode yang ada, tetapi tidak akan ada kehilangan kekuatan ekspresif nyata.

Jadi sekarang kita memiliki arr[3]dan 3[arr]memaknai hal yang persis sama, meskipun bentuk yang terakhir seharusnya tidak pernah muncul di luar IOCCC .

Keith Thompson
sumber
12
Deskripsi fantastis dari properti ini. Dari sudut pandang tingkat tinggi, saya pikir 3[arr]ini adalah artefak yang menarik tetapi jarang digunakan. Jawaban yang diterima untuk pertanyaan ini (< stackoverflow.com/q/1390365/356> ) yang saya tanyakan beberapa waktu lalu telah mengubah cara saya memikirkan sintaksis. Meskipun seringkali secara teknis tidak ada cara yang benar dan salah untuk melakukan hal-hal ini, fitur-fitur ini mulai Anda pikirkan dengan cara yang terpisah dari detail implementasi. Ada manfaat untuk cara berpikir yang berbeda ini yang sebagian hilang ketika Anda terpaku pada detail implementasi.
Dinah
3
Selain itu bersifat komutatif. Untuk standar C untuk mendefinisikannya kalau tidak akan aneh. Itu sebabnya ia tidak bisa dengan mudah mengatakan, "Sebagai tambahan, kedua operan harus memiliki tipe aritmatika, atau operan kiri harus menjadi pointer ke tipe objek lengkap dan operan kanan harus memiliki tipe integer." - Itu tidak masuk akal bagi kebanyakan orang yang menambahkan sesuatu.
iheanyi
9
@iheanyi: Penambahan biasanya komutatif - dan biasanya membutuhkan dua operan dari jenis yang sama. Tambahan pointer memungkinkan Anda menambahkan pointer dan integer, tetapi tidak dua pointer. IMHO itu sudah merupakan kasus khusus yang cukup aneh yang membutuhkan pointer menjadi operan kiri tidak akan menjadi beban yang signifikan. (Beberapa bahasa menggunakan "+" untuk penggabungan string; itu tentu tidak komutatif.)
Keith Thompson
3
@ supercat, Itu lebih buruk. Itu berarti bahwa kadang-kadang x + 1! = 1 + x. Itu akan sepenuhnya melanggar properti asosiatif penambahan.
iheanyi
3
@iheanyi: Saya pikir maksud Anda adalah properti komutatif; Selain itu sudah tidak asosiatif, karena pada sebagian besar implementasi (1LL + 1U) -2! = 1LL + (1U-2). Memang, perubahan akan membuat beberapa situasi asosiatif yang saat ini tidak, misalnya 3U + (UINT_MAX-2L) akan sama dengan (3U + UINT_MAX) -2. Namun, yang terbaik adalah bahasa tersebut telah menambahkan jenis berbeda baru untuk bilangan bulat yang dapat dipromosikan dan "membungkus" cincin aljabar, sehingga menambahkan 2 ke ring16_tyang memegang 65.535 akan menghasilkan ring16_tnilai dengan 1, terlepas dari ukuranint .
supercat
196

Dan tentu saja

 ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')

Alasan utama untuk ini adalah bahwa kembali di tahun 70-an ketika C dirancang, komputer tidak memiliki banyak memori (64KB banyak), sehingga kompiler C tidak melakukan banyak pemeriksaan sintaks. Karenanya " X[Y]" diterjemahkan agak membabi buta ke " *(X+Y)"

Ini juga menjelaskan sintaksis " +=" dan " ++". Segala sesuatu dalam bentuk " A = B + C" memiliki bentuk kompilasi yang sama. Tetapi, jika B adalah objek yang sama dengan A, maka optimasi tingkat perakitan tersedia. Tetapi kompiler tidak cukup pintar untuk mengenalinya, jadi pengembang harus ( A += C). Demikian pula, jika Cada 1, optimasi tingkat perakitan berbeda tersedia, dan sekali lagi pengembang harus membuatnya eksplisit, karena kompiler tidak mengenalinya. (Kompiler yang lebih baru melakukannya, jadi sintaksis itu sebagian besar tidak perlu hari ini)

James Curran
sumber
127
Sebenarnya, itu bernilai false; istilah pertama "ABCD" [2] == 2 ["ABCD"] dievaluasi menjadi true, atau 1, dan 1! = 'C': D
Jonathan Leffler
8
@ Jonathan: ambiguitas yang sama mengarah pada pengeditan judul asli posting ini. Apakah kita sama dengan tanda kesetaraan matematis, sintaksis kode, atau pseudo-code. Saya berpendapat kesetaraan matematis, tetapi karena kita berbicara tentang kode, kita tidak dapat menghindari bahwa kita melihat semuanya dalam hal sintaksis kode.
Dinah
19
Bukankah ini mitos? Maksud saya operator + = dan ++ dibuat untuk mempermudah penyusun? Beberapa kode menjadi lebih jelas dengan mereka, dan itu adalah sintaks yang berguna untuk dimiliki, tidak peduli apa yang dilakukan oleh kompiler.
Thomas Padron-McCarthy
6
+ = dan ++ memiliki manfaat signifikan lainnya. jika sisi kiri mengubah beberapa variabel saat dievaluasi, perubahan hanya akan dilakukan sekali. a = a + ...; akan melakukannya dua kali.
Johannes Schaub - litb
8
Tidak - "ABCD" [2] == * ("ABCD" + 2) = * ("CD") = 'C'. Dereferencing string memberi Anda char, bukan substring
MSalters
55

Satu hal yang sepertinya tidak ada yang menyebutkan tentang masalah Dinah dengan sizeof:

Anda hanya bisa menambahkan integer ke sebuah pointer, Anda tidak bisa menambahkan dua pointer bersamaan. Dengan begitu ketika menambahkan pointer ke integer, atau integer ke pointer, kompiler selalu tahu bit mana yang memiliki ukuran yang perlu diperhitungkan.

pengguna30364
sumber
1
Ada percakapan yang cukup lengkap tentang ini di komentar dari jawaban yang diterima. Saya mereferensikan percakapan tersebut di edit ke pertanyaan asli tetapi tidak secara langsung mengatasi masalah ukuran Anda yang sangat valid. Tidak yakin bagaimana cara terbaik melakukan ini dalam SO. Haruskah saya membuat edit lain ke orig. pertanyaan?
Dinah
49

Untuk menjawab pertanyaan secara harfiah. Tidak selalu benar demikianx == x

double zero = 0.0;
double a[] = { 0,0,0,0,0, zero/zero}; // NaN
cout << (a[5] == 5[a] ? "true" : "false") << endl;

cetakan

false
Peter Lawrey
sumber
27
Sebenarnya "nan" tidak sama dengan dirinya sendiri: cout << (a[5] == a[5] ? "true" : "false") << endl;adalah false.
TrueY
9
@ TrueY: Dia menyatakan bahwa khusus untuk kasus NaN (dan khususnya itu x == xtidak selalu benar). Saya pikir itu niatnya. Jadi dia secara teknis benar (dan mungkin, seperti yang mereka katakan, jenis terbaik yang benar!).
Tim Čas
4
Pertanyaannya adalah tentang C, kode Anda bukan kode C. Ada juga NANin <math.h>, yang lebih baik daripada 0.0/0.0, karena 0.0/0.0UB ketika __STDC_IEC_559__tidak didefinisikan (Sebagian besar implementasi tidak mendefinisikan __STDC_IEC_559__, tetapi pada sebagian besar implementasi 0.0/0.0akan tetap berfungsi)
12431234123412341234123
26

Saya baru tahu sintaks jelek ini bisa "berguna", atau setidaknya sangat menyenangkan untuk dimainkan ketika Anda ingin berurusan dengan array indeks yang merujuk ke posisi ke dalam array yang sama. Itu dapat menggantikan tanda kurung bersarang dan membuat kode lebih mudah dibaca!

int a[] = { 2 , 3 , 3 , 2 , 4 };
int s = sizeof a / sizeof *a;  //  s == 5

for(int i = 0 ; i < s ; ++i) {  

           cout << a[a[a[i]]] << endl;
           // ... is equivalent to ... 
           cout << i[a][a][a] << endl;  // but I prefer this one, it's easier to increase the level of indirection (without loop)

}

Tentu saja, saya cukup yakin bahwa tidak ada kasus penggunaan untuk itu dalam kode nyata, tetapi saya tetap merasa menarik :)

Frédéric Terrazzoni
sumber
Ketika Anda melihat i[a][a][a]Anda berpikir saya adalah penunjuk ke array atau array dari penunjuk ke array atau array ... dan amerupakan indeks. Ketika Anda melihat a[a[a[i]]], Anda berpikir a adalah pointer ke array atau array dan imerupakan indeks.
12431234123412341234123
1
Wow! Sangat keren penggunaan fitur "bodoh" ini. Bisa berguna dalam kontes algoritmik dalam beberapa masalah))
Serge Breusov
26

Pertanyaan / jawaban yang bagus.

Hanya ingin menunjukkan bahwa pointer C dan array tidak sama , meskipun dalam hal ini perbedaannya tidak penting.

Pertimbangkan deklarasi berikut:

int a[10];
int* p = a;

Di a.out, simbol aberada di alamat yang merupakan awal array, dan simbol pberada di alamat tempat pointer disimpan, dan nilai pointer di lokasi memori itu adalah awal dari array.

PolyThinker
sumber
2
Tidak, secara teknis mereka tidak sama. Jika Anda mendefinisikan beberapa b sebagai int * const dan membuatnya menunjuk ke array, itu masih sebuah pointer, yang berarti bahwa dalam tabel simbol, b merujuk ke lokasi memori yang menyimpan alamat, yang pada gilirannya menunjuk ke tempat array berada. .
PolyThinker
4
Poin yang sangat bagus. Saya ingat memiliki bug yang sangat buruk ketika saya mendefinisikan simbol global sebagai karakter [100] dalam satu modul, mendeklarasikannya sebagai karakter eksternal; dalam modul lain. Setelah menghubungkan semuanya, program tersebut bertingkah aneh. Karena modul yang menggunakan deklarasi extern menggunakan byte awal dari array sebagai pointer ke char.
Giorgio
1
Awalnya, dalam C kakek-nenek BCPL, sebuah array adalah sebuah pointer. Artinya, apa yang Anda dapatkan ketika Anda menulis (saya telah transliterasi ke C) int a[10]adalah sebuah pointer yang disebut 'a', yang menunjuk ke toko yang cukup untuk 10 integer, di tempat lain. Jadi a + i dan j + i memiliki bentuk yang sama: tambahkan konten dari beberapa lokasi memori. Bahkan, saya pikir BCPL tidak ada artinya, jadi mereka identik. Dan penskalaan tipe sizeof tidak berlaku, karena BCPL murni berorientasi pada kata (pada mesin yang dialamatkan juga kata).
dave
Saya pikir cara terbaik untuk memahami perbedaan adalah untuk membandingkan int*p = a;ke int b = 5; Dalam yang terakhir, "b" dan "5" keduanya bilangan bulat, tetapi "b" adalah variabel, sedangkan "5" adalah nilai tetap. Demikian pula, "p" & "a" keduanya alamat karakter, tetapi "a" adalah nilai tetap.
James Curran
20

Untuk petunjuk dalam C, kami punya

a[5] == *(a + 5)

dan juga

5[a] == *(5 + a)

Karena itu memang benar demikian a[5] == 5[a].

pengguna1055604
sumber
15

Bukan jawaban, tapi hanya makanan untuk dipikirkan. Jika kelas memiliki operator indeks / subskrip kelebihan, ekspresi 0[x]tidak akan berfungsi:

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

Karena kami tidak memiliki akses ke kelas int , ini tidak dapat dilakukan:

class int
{
   int operator[](const Sub&);
};
Ajay
sumber
2
class Sub { public: int operator[](size_t nIndex) const { return 0; } friend int operator[](size_t nIndex, const Sub& This) { return 0; } };
Ben Voigt
1
Sudahkah Anda benar-benar mencoba mengompilasinya? Ada sekumpulan operator yang tidak dapat diimplementasikan di luar kelas (yaitu sebagai fungsi non-statis)!
Ajay
3
Ups, Anda benar. " operator[]Akan menjadi fungsi anggota tidak statis dengan tepat satu parameter." Saya terbiasa dengan pembatasan itu operator=, tidak berpikir itu berlaku [].
Ben Voigt
1
Tentu saja, jika Anda mengubah definisi []operator, itu tidak akan pernah menjadi setara lagi ... jika a[b]sama dengan *(a + b)dan Anda mengubah ini, Anda harus kelebihan beban juga int::operator[](const Sub&);dan intbukan kelas ...
Luis Colorado
7
Ini ... bukan ... C.
MD XF
11

Ini memiliki penjelasan yang sangat baik dalam A TUTORIAL ON POINTERS DAN ARRAYS IN C oleh Ted Jensen.

Ted Jensen menjelaskannya sebagai:

Bahkan, ini benar, yaitu di mana pun orang menulis a[i]itu dapat diganti *(a + i) tanpa masalah. Bahkan, kompiler akan membuat kode yang sama dalam kedua kasus. Jadi kita melihat bahwa pointer aritmatika adalah hal yang sama dengan pengindeksan array. Entah sintaks menghasilkan hasil yang sama.

Ini BUKAN mengatakan bahwa pointer dan array adalah hal yang sama, mereka tidak. Kami hanya mengatakan bahwa untuk mengidentifikasi elemen tertentu dari array kami memiliki pilihan dua sintaks, satu menggunakan indeks array dan yang lainnya menggunakan aritmatika pointer, yang menghasilkan hasil yang identik.

Sekarang, melihat ekspresi terakhir ini, bagian dari itu .. (a + i), adalah tambahan sederhana menggunakan operator + dan aturan C menyatakan bahwa ekspresi seperti itu komutatif. Artinya (a + i) identik dengan (i + a). Jadi kita bisa menulis *(i + a)semudah itu *(a + i). Tapi *(i + a)bisa saja berasal i[a]! Dari semua ini muncul kebenaran yang aneh bahwa jika:

char a[20];

penulisan

a[3] = 'x';

sama dengan menulis

3[a] = 'x';
Sebagai Bhullar
sumber
4
a + i BUKAN penambahan sederhana, karena itu pointer aritmatika. jika ukuran elemen a adalah 1 (char), maka ya, itu seperti integer +. Tetapi jika itu (misalnya) bilangan bulat, maka itu mungkin setara dengan + 4 * i.
Alex Brown
@AlexBrown Ya, ini adalah aritmatika penunjuk, yang merupakan alasan mengapa kalimat terakhir Anda salah, kecuali jika Anda pertama kali melemparkan 'a' menjadi (char *) (dengan asumsi bahwa int adalah 4 karakter). Saya benar-benar tidak mengerti mengapa begitu banyak orang yang terpaku pada hasil nilai aktual dari aritmatika pointer. Seluruh tujuan aritmatika Pointer adalah untuk mengabstraksi nilai-nilai pointer yang mendasarinya dan membiarkan programmer memikirkan objek yang dimanipulasi daripada nilai-nilai alamat.
jschultz410
8

Saya tahu pertanyaannya dijawab, tetapi saya tidak tahan untuk tidak membagikan penjelasan ini.

Saya ingat desain Principles of Compiler, Mari kita asumsikan aadalah intarray dan ukurannya intadalah 2 byte, & Base address aadalah 1000.

Bagaimana cara a[5]kerjanya ->

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

Begitu,

Demikian pula ketika kode c dipecah menjadi kode 3-alamat, 5[a]akan menjadi ->

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

Jadi pada dasarnya kedua pernyataan menunjuk ke lokasi yang sama di memori dan karenanya a[5] = 5[a],.

Penjelasan ini juga merupakan alasan mengapa indeks negatif dalam array bekerja di C.

yaitu jika saya mengaksesnya a[-5]akan memberi saya

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

Ini akan mengembalikan saya objek di lokasi 990.

Ajinkya Patil
sumber
6

Dalam C array , arr[3]dan 3[arr]adalah sama, dan notasi pointer mereka setara yang *(arr + 3)ke *(3 + arr). Tetapi sebaliknya [arr]3atau [3]arrtidak benar dan akan menghasilkan kesalahan sintaksis, karena (arr + 3)*dan (3 + arr)*bukan ekspresi yang valid. Alasannya adalah operator dereference harus ditempatkan sebelum alamat yang dihasilkan oleh ekspresi, bukan setelah alamat.

Krishan
sumber
6

dalam c compiler

a[i]
i[a]
*(a+i)

ada berbagai cara untuk merujuk ke elemen dalam array! (BUKAN SEMUA WEIRD)

AVIK DUTTA
sumber
5

Sedikit sejarah sekarang. Di antara bahasa-bahasa lain, BCPL memiliki pengaruh yang cukup besar pada perkembangan awal C. Jika Anda mendeklarasikan array di BCPL dengan sesuatu seperti:

let V = vec 10

yang sebenarnya mengalokasikan 11 kata memori, bukan 10. Biasanya V adalah yang pertama, dan berisi alamat dari kata berikut segera. Jadi tidak seperti C, penamaan V pergi ke lokasi itu dan mengambil alamat elemen zeroeth dari array. Oleh karena itu array tidak langsung dalam BCPL, dinyatakan sebagai

let J = V!5

benar-benar harus melakukan J = !(V + 5)(menggunakan sintaks BCPL) karena itu perlu untuk mengambil V untuk mendapatkan alamat basis dari array. Jadi V!5dan 5!Vitu identik. Sebagai pengamatan anekdotal, WAFL (Warwick Functional Language) ditulis dalam BCPL, dan yang terbaik dari ingatan saya cenderung menggunakan sintaks yang terakhir daripada yang sebelumnya untuk mengakses node yang digunakan sebagai penyimpanan data. Memang ini dari suatu tempat antara 35 dan 40 tahun yang lalu, jadi ingatanku agak berkarat. :)

Inovasi mengeluarkan kata penyimpanan ekstra dan meminta kompiler memasukkan alamat dasar array ketika dinamai datang kemudian. Menurut makalah sejarah C ini terjadi pada sekitar waktu struktur ditambahkan ke C.

Perhatikan bahwa !dalam BCPL adalah operator awalan unary dan operator infiks biner, dalam kedua kasus melakukan tipuan. Hanya saja bentuk biner termasuk penambahan dua operan sebelum melakukan tipuan. Mengingat sifat berorientasi kata BCPL (dan B) ini sebenarnya membuat banyak akal. Pembatasan "pointer dan integer" dibuat perlu di C ketika memperoleh tipe data, dan sizeofmenjadi sesuatu.

dengan sungguh-sungguh
sumber
1

Ya, ini adalah fitur yang hanya mungkin karena dukungan bahasa.

Compiler mengartikan a[i]sebagai *(a+i)dan ekspresi 5[a]dievaluasi untuk *(5+a). Karena penambahan bersifat komutatif, ternyata keduanya sama. Karenanya ekspresi dievaluasi menjadi true.

Harsha JK
sumber
Meskipun mubazir ini jelas, singkat dan pendek.
Bill K
0

Dalam C

 int a[]={10,20,30,40,50};
 int *p=a;
 printf("%d\n",*p++);//output will be 10
 printf("%d\n",*a++);//will give an error

Pointer adalah "variabel"

nama array adalah "mnemonic" atau "sinonim"

p++;valid tetapi a++tidak valid

a[2] sama dengan 2 [a] karena operasi internal pada keduanya adalah

"Aritmatika Pointer" dihitung secara internal sebagai

*(a+3) sama dengan *(3+a)

Jayghosh Wankar
sumber
-4

jenis penunjuk

1) pointer ke data

int *ptr;

2) const pointer ke data

int const *ptr;

3) pointer pointer ke data const

int const *const ptr;

dan array adalah tipe (2) dari daftar kami.
Ketika Anda mendefinisikan sebuah array pada suatu waktu, satu alamat diinisialisasi dalam pointer tersebut.
Seperti yang kita tahu bahwa kita tidak dapat mengubah atau memodifikasi nilai const dalam program kita karena itu melemparkan ERROR saat dikompilasi. waktu

Perbedaan utama yang saya temukan adalah ...

Kami dapat menginisialisasi ulang pointer dengan alamat tetapi tidak dengan case yang sama dengan array.

======
dan kembali ke pertanyaan Anda ...
a[5]tidak lain adalah *(a + 5)
Anda dapat memahami dengan mudah dengan
a - berisi alamat (orang menyebutnya sebagai alamat dasar) seperti jenis penunjuk (2) dalam daftar kami
[]- operator itu dapat diganti dengan pointer *.

jadi akhirnya ...

a[5] == *(a +5) == *(5 + a) == 5[a] 
Jeet Parikh
sumber