Apa tujuan array dalam C, ketika pointer bisa melakukan pekerjaan itu?

8

Array dan pointer bukan hal yang sama dalam C, meskipun mereka terkait dan dapat digunakan dengan cara yang sama. Sejauh ini kita semua sepakat.

Namun, saya tidak melihat mengapa array dimasukkan dalam C, ketika pointer bisa melakukan pekerjaan mereka dengan sempurna.

Saya tidak mengatakan untuk menghapus notasi array (misalnya, a [5] atau int a [4] = {0,1,2,3};), yang cukup berguna dan nyaman. Tetapi Anda dapat memiliki notasi yang sama bekerja di atas pointer (seperti halnya), sebagai ukuran kosmetik. Jadi notasi array bukan alasan untuk memiliki array, hanya notasi!

Satu-satunya perbedaan yang saya lihat adalah array adalah pointer konstan, dan ukuran memori yang mereka tunjuk tidak dapat diubah. Tapi ini bisa dicapai dengan pointer juga, tepatnya dengan membuatnya konstan (memori tidak akan berukuran tetap, tapi saya tidak yakin apakah ini masalah).

Jadi mengapa tidak hanya memiliki pointer dan biarkan programmer memutuskan bagaimana pointer harus berperilaku (yaitu, konstan, bukan konstan, ukuran tetap, ukuran variabel, dll)?

Daniel Scocco
sumber
6
Mengapa memiliki char ketika Anda dapat mencapai hal yang sama dengan byte?
WuHoUnited
2
Pada catatan yang lebih serius, bagaimana Anda ingin menyelesaikan alokasi memori dengan pointer?
WuHoUnited
5
Secara pribadi, saya menganggap pointer sebagai (terkadang) berpura-pura menjadi array daripada sebaliknya. Dalam banyak bahasa lain, pointer tidak memiliki perilaku seperti array - jika Anda ingin mengakses array melalui pointer, Anda menggunakan tipe pointer-to-array atau Anda melakukan aritmatika pointer (menghitung dalam byte, bukan elemen). Saya berani bertaruh sejumlah uang yang menurut penemu C dalam hal tweaker pointer untuk mendapatkan perilaku seperti array yang lebih nyaman - Saya sangat ragu mereka sudah memiliki perilaku pointer seperti array kemudian memutuskan "Saya tahu, mari tambahkan array. terlalu".
Steve314
3
Mengapa memiliki 0xAB ketika Anda dapat mencapai hal yang sama dengan 171?
e-MEE
2
mengapa memiliki ekspresi majemuk seperti x = a + b * 2;ketika Anda dapat mencapai hal yang sama dengan urutan ekspresi sederhana seperti x = b; x*=2; x+=a;?
fortran

Jawaban:

14

Array adalah memori yang berdekatan yang dibuat pada stack. Anda tidak dapat menjamin memori tumpukan berdekatan tanpa gula sintaksis ini, dan bahkan jika Anda bisa, Anda harus mengalokasikan pointer terpisah untuk dapat melakukan aritmatika pointer (kecuali jika Anda ingin melakukannya *(&foo + x), yang saya tidak tentu tetapi itu mungkin melanggar semantik nilai-l, tetapi setidaknya cukup canggung, dan akan berteriak untuk semacam gula sintaksis). Dari segi desain, ini juga merupakan bentuk enkapsulasi, karena Anda dapat merujuk ke koleksi dengan pengenal tunggal (yang jika tidak akan memerlukan pointer terpisah). Dan bahkan jika Anda dapat mengalokasikannya secara berdekatan dan mengalokasikan pointer terpisah untuk referensi mereka, Anda akan memiliki salah satu int fooForSomething, fooForSomethingElse... yang memaksa cukup banyak kreativitas ketika koleksi Anda tumbuh, sehingga Anda mungkin berpikir untuk menyederhanakan dengan int foo1, foo2 ..., yang terlihat seperti array tetapi lebih sulit untuk dipertahankan.

Kylben
sumber
Oh, dan berikan nilai untuk foo1, foo2 ... menjadi berantakan dengan cepat, terutama jika Anda ingin memperbolehkan jumlah variabel anggota.
kylben
2
Hanya array yang dinyatakan sebagai automatics yang berakhir di stack. Apa pun (mis., staticS) biasanya berakhir di tempat lain tergantung pada lingkungan.
Blrfl
Ini bukan "gula sintaksis", itu jauh lebih dalam - bagian penting dari sistem tipe C, serta peluruhan array yang terkenal.
SK-logic
1
apa perbedaan antara array pada stack dan alokasi ()
sylvanaar
@sylvanaar, lihat pertanyaan SO ini: stackoverflow.com/questions/1018853/... Saya sebenarnya tidak pernah mendengarnya sebelumnya, tetapi tampaknya tidak standar dan berbahaya dalam cara saya mengharapkan hal seperti itu menjadi berbahaya.
kylben
12

Notasi array nyaman, lebih mudah dibaca, dan lebih rentan terhadap kesalahan. Ini memberikan formalisme atas petunjuk. Ini mungkin gula sintaksis, tetapi kita semua perlu sedikit rasa manis sesekali, bukan?

Seperti halnya semua abstraksi, Anda memberikan sedikit fleksibilitas untuk kenyamanan yang disediakan abstraksi.

Robert Harvey
sumber
1
Seperti yang saya sebutkan dalam pertanyaan, saya tidak menentang notasi array. Tetapi notasi yang sama dapat bekerja di atas pointer, jadi di mana perlunya array sendiri?
Daniel Scocco
1
@DanielScocco - Mungkin bisa. Tapi itu dibuat seperti ini. Akhir dari cerita. Tidak ada yang bisa menjawab ini, karena tidak ada yang tahu apa yang ada di kepala penulis saat itu.
Benteng
10

Saya terkejut bahwa belum ada yang berkomentar tentang array multidimensi.

Jika Anda memiliki matriks yang terbuat dari "nested pointer" (katakanlah int **p) apa yang Anda miliki di setiap "baris" (dimensi luar) adalah pointer yang menunjuk ke elemen pertama di baris itu, sehingga mengakses suatu nilai memerlukan dua akses memori. Plus, memori yang dibutuhkan adalah sizeof(*int)*n + n*m*sizeof(int).

Dalam skenario array dua dimensi int p[n][m], mengakses elemen hanya membutuhkan satu akses memori, karena alamat baris dihitung daripada melihat ke atas; dan memori yang dibutuhkan adalah adil n*m*sizeof(int).

Tempat lain di mana array tidak dapat diganti oleh pointer adalah struktur di dalamnya.

struct s {
    int[2];
    float;
}

secara definitif tidak sama dengan

struct s {
   *int;
   float;
}

ukuran array penting di sana, dan pointer tidak memiliki informasi itu.

Jadi ya, array unidimensional dan pointer tunggal sebagian besar dapat dipertukarkan, tetapi kesamaan mereka berakhir di sana.

fortran
sumber
Tunjukkan kami perbedaan assembler. Array multidimensi, pengemasan struktur, dan padding, semuanya hanyalah cara untuk menyediakan kerangka acuan yang masuk akal bagi manusia yang harus memahami dan menggunakan bahasa.
sylvanaar
@ sylvanaar kamu serius? apakah Anda benar-benar perlu melihat assembler untuk memastikan bahwa struktur pertama menampung ruang untuk dua bilangan bulat dan float, dan yang kedua hanya untuk menyimpan alamat memori dan float?
fortran
1
Aku tidak mengikutimu. Apa yang harus dilakukan dengan set instruksi dengan semua ini? Op bertanya apa yang bisa Anda lakukan dengan array dan bukan dengan pointer, dan menyatakan struct dengan array ukuran tetap tidak dapat ditiru dengan pointer. Tentang array multidimensi, tentu saja Anda dapat memiliki hanya sepotong memori dan menghitung indeks sel i,jdengan i*cols+j, tetapi saya pikir tidak harus melakukannya sendiri adalah alasan yang cukup baik untuk membenarkan keberadaan tipe array.
fortran
2
"Mendeklarasikan struct [...] memang membuat alokasi memori statis dalam gambar yang dikompilasi" Tidak, mendeklarasikan variabel (tipe struct, atau tipe lain) melakukan hal ini. Mendeklarasikan struct hanya memberi tahu kompiler seberapa besar tipe itu dan apa offset masing-masing anggotanya; Anda mungkin tidak pernah mengalokasikan satu, atau hanya mengalokasikannya sebagai variabel lokal.
Random832
1
+1 untuk secara praktis mengidentifikasi nilai praktis memiliki array dengan ukuran tetap menjadi "tipe" sejauh menyangkut kompiler - array multidimensi, dan khususnya fakta bahwa Anda dapat dengan mudah mengindeksnya dengan kompiler yang melakukan aritmatika pointer dengan ukuran yang tepat untuk Anda, rontok secara alami dan elegan dari aturan bahasa sederhana lainnya dengan membuat array "tipe" nyata - Anda bisa mencapai gula sintaksis yang sama tanpa itu, tetapi logikanya harus lebih istimewa, keduanya dalam kompiler dan dalam spesifikasi bahasa.
mtraceur
2

Mengapa saya ingin tidak dapat menggunakan array untuk tipe nilai?

int a[4] = {0,1,2,3};

Demian Brecht
sumber
Anda masih dapat menggunakannya bahkan jika kami hanya memiliki pointer, bukan? Kompiler hanya perlu tahu apa yang harus dilakukan.
Daniel Scocco
2
@DanielScocco dan bagaimana ia tahu apa yang harus dilakukan? array
ratchet freak
Setuju - apa yang akan Anda sebut fitur yang menyediakan ruang untuk urutan item bertipe sama sebagai variabel lokal atau global, jika bukan array? Tipe pointer adalah tipe pointer - tidak menentukan apakah menunjuk ke urutan, atau urutan ukuran apa.
Steve314
4
@DanielScocco Apa yang datang dengan array yang tidak datang dengan pointer adalah informasi tentang ukuran. Jadi pasangan (penunjuk, ukuran) atau pasangan (penunjuk, penunjuk) memang dapat menampung informasi sebanyak nama array. Apakah ini berarti bahwa array adalah pasangan pointer (atau sebaliknya) sepertinya lebih seperti pertanyaan metafisik, jadi saya tidak benar-benar tertarik menjawabnya. (Jawabannya mungkin tidak karena pasangan pointer lebih mirip irisan, dan karenanya dapat melakukan lebih dari sekadar merujuk ke array.)
Luc Danton
1
@Daniel Scocco, array memiliki ukuran . Anda dapat mengalokasikan array pada stack, Anda dapat menempatkan array ke dalam struktur yang berdekatan, Anda dapat menggunakannya dalam suatu kesatuan. Jika jenis array tidak ada, itu tidak akan mungkin.
SK-logic
1

Bagaimana Anda menangani platform, seperti 8031 ​​tanpa memori eksternal, yang tidak mendukung mallocatau alloca? Mungkin Anda lupa bahwa C tidak hanya untuk setrika besar tetapi juga untuk pengontrol elevator dan pemanggang roti.

David Schwartz
sumber
1

Dalam C, notasi array dalam ekspresi selalu hanya pointer aritmatika. Semua penggunaan pengidentifikasi array dalam ekspresi segera dikonversi dari "array T" ke "pointer ke T" dan nilainya dikonversi ke pointer ke elemen pertama array. Notasi array (misalnya a[1][2]) selalu diperluas menjadi aritmatika pointer (misalnya *(*(t+1)+2)).

Namun notasi array dalam deklarasi dan definisi adalah sesuatu yang sepenuhnya berbeda. Sebuah declarator Array menggambarkan "array T " jenis di mana nilai-nilai jenis ini adalah urutan dari elemen tipe T . Definisi objek array adalah semua tentang menggunakan notasi array yang mudah dan mudah dipahami untuk mengalokasikan jumlah penyimpanan yang sesuai untuk objek array yang diinginkan sedemikian rupa sehingga pengidentifikasi array merujuk ke penyimpanan ini tanpa terlihat seperti pointer. Akibatnya notasi array dalam deklarasi atau definisi adalah makro yang menghasilkan ekspresi menggunakan sizeof()dan aritmatika, dan dalam kasus definisi, setara denganalloca() untuk array otomatis atau yang setara di linker untuk array global, dan melakukan semuanya pada waktu kompilasi (baik kecuali untuk array panjang variabel C99).

Penggunaan notasi array dalam ekspresi dan penggunaan tipe array tidak begitu terhubung, meskipun itu adalah tradisi dan idiom untuk menggunakan notasi array dalam ekspresi untuk referensi penyimpanan dalam objek yang dideklarasikan dan / atau didefinisikan sebagai array. Anda dapat dengan mudah menggunakan notasi array dengan tipe pointer untuk membuat pointer aritmatika lebih bersih dan lebih bermakna. Memang dalam C ekspresi bentuk e1[e2]persis sama dengan ekspresi *((e1)+(e2)). Biasa konversi biner diterapkan pada dua operan, dan hasilnya selalu merupakan lvalue . Karena operator tidak langsung ( *) harus memiliki penunjuk sebagai operan, salah satu dari e1dan e2harus menjadi penunjuk dan yang lainnya harus bilangan bulat, tetapi tidak masalahkarena konversi unary awal untuk setiap "array T" adalah mengubahnya menjadi "pointer ke T". Notasi array dalam ekspresi pada dasarnya adalah kompiler (tingkat bahasa) makro untuk menghasilkan ekspresi aritmatika pointer.

Jadi sebenarnya C sudah berfungsi seperti yang Anda sarankan, tetapi Anda membingungkan penggunaan notasi dalam dua konteks yang sangat terpisah.

Greg A. Woods
sumber