C ++ array yang diwarisi dari C di mana mereka digunakan hampir di mana-mana. C ++ menyediakan abstraksi yang lebih mudah digunakan dan lebih sedikit rawan kesalahan ( std::vector<T>
sejak C ++ 98 dan std::array<T, n>
karena C ++ 11 ), sehingga kebutuhan untuk array tidak muncul sesering seperti di C. Namun, ketika Anda membaca legacy kode atau berinteraksi dengan perpustakaan yang ditulis dalam C, Anda harus memiliki pemahaman yang kuat tentang cara kerja array.
FAQ ini dibagi menjadi lima bagian:
- array pada level tipe dan elemen mengakses
- pembuatan dan inisialisasi array
- penugasan dan melewati parameter
- array multidimensi dan array pointer
- perangkap umum saat menggunakan array
Jika Anda merasa ada sesuatu yang penting tidak ada dalam FAQ ini, tulis jawaban dan tautkan di sini sebagai bagian tambahan.
Dalam teks berikut, "larik" berarti "larik C", bukan templat kelas std::array
. Pengetahuan dasar tentang sintaks deklarator C diasumsikan. Perhatikan bahwa penggunaan manual new
dan delete
seperti yang ditunjukkan di bawah ini sangat berbahaya dalam menghadapi pengecualian, tetapi itulah topik dari FAQ lainnya .
(Catatan: Ini dimaksudkan sebagai entri untuk FAQ C ++ Stack Overflow . Jika Anda ingin mengkritik gagasan memberikan FAQ dalam formulir ini, maka posting pada meta yang memulai semua ini akan menjadi tempat untuk melakukan itu. Jawaban untuk pertanyaan itu dipantau di chatroom C ++ , di mana ide FAQ dimulai sejak awal, jadi jawaban Anda sangat mungkin untuk dibaca oleh mereka yang mengemukakan ide itu.)
std::array
s,std::vector
s dangsl::span
s - saya akan terus terang berharap FAQ tentang cara menggunakan array di C ++ untuk mengatakan "Sekarang, Anda dapat mulai mempertimbangkan, yah, tidak menggunakannya."Jawaban:
Array pada tingkat jenis
Sebuah array tipe dilambangkan sebagai
T[n]
manaT
adalah jenis elemen dann
merupakan positif ukuran , jumlah elemen dalam array. Jenis array adalah jenis produk dari jenis elemen dan ukurannya. Jika salah satu atau kedua bahan tersebut berbeda, Anda mendapatkan jenis yang berbeda:Perhatikan bahwa ukuran adalah bagian dari tipe, yaitu, tipe array dengan ukuran berbeda adalah tipe yang tidak kompatibel yang sama sekali tidak ada hubungannya satu sama lain.
sizeof(T[n])
setara dengann * sizeof(T)
.Array-to-pointer decay
Satu-satunya "koneksi" antara
T[n]
danT[m]
adalah bahwa kedua jenis secara implisit dapat dikonversi menjadiT*
, dan hasil konversi ini adalah penunjuk ke elemen pertama dari array. Artinya, di mana sajaT*
diperlukan, Anda dapat memberikanT[n]
, dan kompiler akan secara diam-diam memberikan pointer itu:Konversi ini dikenal sebagai "peluruhan array-ke-pointer", dan merupakan sumber utama kebingungan. Ukuran array hilang dalam proses ini, karena bukan lagi bagian dari tipe (
T*
). Pro: Melupakan ukuran array pada level tipe memungkinkan penunjuk untuk menunjuk ke elemen pertama array ukuran apa pun . Con: Diberikan pointer ke elemen array pertama (atau lainnya), tidak ada cara untuk mendeteksi seberapa besar array itu atau di mana tepatnya pointer menunjuk ke relatif terhadap batas-batas array. Pointer sangat bodoh .Array bukan pointer
Compiler akan secara diam-diam menghasilkan pointer ke elemen pertama dari array kapan pun dianggap berguna, yaitu, setiap kali operasi akan gagal pada array tetapi berhasil pada pointer. Konversi ini dari array ke pointer adalah sepele, karena pointer yang dihasilkan nilai hanya alamat dari array. Perhatikan bahwa pointer tidak disimpan sebagai bagian dari array itu sendiri (atau tempat lain di memori). Array bukan pointer.
Satu konteks penting di mana array tidak membusuk menjadi pointer ke elemen pertamanya adalah ketika
&
operator diterapkan padanya. Dalam hal ini,&
operator menghasilkan pointer ke seluruh array, bukan hanya pointer ke elemen pertamanya. Meskipun dalam hal ini nilai - nilai (alamat) adalah sama, sebuah penunjuk ke elemen pertama dari sebuah array dan sebuah penunjuk ke seluruh array adalah tipe yang sama sekali berbeda:Seni ASCII berikut menjelaskan perbedaan ini:
Perhatikan bagaimana pointer ke elemen pertama hanya menunjuk ke integer tunggal (digambarkan sebagai kotak kecil), sedangkan pointer ke seluruh array menunjuk ke array 8 integer (digambarkan sebagai kotak besar).
Situasi yang sama muncul di kelas dan mungkin lebih jelas. Sebuah pointer ke objek dan pointer ke data anggota pertama memiliki yang sama nilai (alamat yang sama), namun mereka benar-benar jenis yang berbeda.
Jika Anda tidak terbiasa dengan sintaks deklarator C, tanda kurung dalam jenis
int(*)[8]
ini penting:int(*)[8]
adalah pointer ke array 8 bilangan bulat.int*[8]
adalah array 8 pointer, masing-masing elemen tipeint*
.Mengakses elemen
C ++ menyediakan dua variasi sintaksis untuk mengakses elemen individual dari sebuah array. Tak satu pun dari mereka lebih unggul dari yang lain, dan Anda harus membiasakan diri dengan keduanya.
Aritmatika petunjuk
Diberikan pointer
p
ke elemen pertama array, ekspresip+i
menghasilkan pointer ke elemen ke-i dari array. Dengan mendereferensi pointer itu sesudahnya, seseorang dapat mengakses elemen individual:Jika
x
menunjukkan sebuah array , maka peluruhan array-to-pointer akan muncul, karena menambahkan array dan integer tidak ada artinya (tidak ada operasi plus pada array), tetapi menambahkan pointer dan integer masuk akal:(Perhatikan bahwa pointer yang dihasilkan secara implisit tidak memiliki nama, jadi saya menulis
x+0
untuk mengidentifikasinya.)Jika, di lain pihak,
x
menunjukkan sebuah pointer ke elemen pertama (atau elemen lainnya) dari sebuah array, maka peluruhan array-to-pointer tidak diperlukan, karena pointer yangi
akan ditambahkan sudah ada:Perhatikan bahwa dalam kasus yang digambarkan,
x
adalah variabel pointer (dapat dilihat oleh kotak kecil di sebelahx
), tetapi bisa juga hasil dari fungsi yang mengembalikan pointer (atau ekspresi tipe lainnyaT*
).Operator pengindeksan
Karena sintaksnya
*(x+i)
agak canggung, C ++ menyediakan sintaksis alternatifx[i]
:Karena fakta bahwa penambahan bersifat komutatif, kode berikut tidak persis sama:
Definisi operator pengindeksan mengarah pada kesetaraan menarik berikut:
Namun,
&x[0]
umumnya tidak setara denganx
. Yang pertama adalah pointer, yang terakhir adalah array. Hanya ketika konteks memicu peluruhan array-ke-pointer dapatx
dan&x[0]
digunakan secara bergantian. Sebagai contoh:Pada baris pertama, kompiler mendeteksi tugas dari pointer ke pointer, yang berhasil. Pada baris kedua, ini mendeteksi tugas dari array ke pointer. Karena ini adalah berarti (tapi pointer ke pointer tugas masuk akal), array-to-pointer pembusukan tendangan seperti biasa.
Kisaran
Array tipe
T[n]
memilikin
elemen, diindeks dari0
ken-1
; tidak ada elemenn
. Namun, untuk mendukung rentang setengah terbuka (di mana permulaan inklusif dan ujungnya eksklusif ), C ++ memungkinkan perhitungan pointer ke elemen ke-n (tidak ada), tetapi ilegal untuk meringkas pointer itu:Misalnya, jika Anda ingin mengurutkan array, kedua hal berikut ini akan berfungsi sama baiknya:
Perhatikan bahwa memberikan
&x[n]
argumen kedua adalah ilegal karena hal ini setara dengan&*(x+n)
, dan sub-ekspresi secara*(x+n)
teknis memanggil perilaku yang tidak terdefinisi dalam C ++ (tetapi tidak dalam C99).Perhatikan juga bahwa Anda cukup memberikan
x
argumen pertama. Itu agak terlalu singkat untuk seleraku, dan itu juga membuat pengurangan argumen template sedikit lebih sulit untuk kompiler, karena dalam kasus itu argumen pertama adalah sebuah array tetapi argumen kedua adalah sebuah pointer. (Sekali lagi, peluruhan array-ke-pointer mulai.)sumber
Programmer sering membingungkan array multidimensi dengan array pointer.
Array multidimensi
Sebagian besar programmer akrab dengan array multidimensi bernama, tetapi banyak yang tidak menyadari fakta bahwa array multidimensi juga dapat dibuat secara anonim. Array multidimensi sering disebut sebagai "array array" atau " array multidimensi sejati ".
Disebut array multidimensi
Saat menggunakan array multidimensi bernama, semua dimensi harus diketahui pada waktu kompilasi:
Beginilah bentuk array multidimensi terlihat di memori:
Perhatikan bahwa kisi 2D seperti di atas hanyalah visualisasi yang bermanfaat. Dari sudut pandang C ++, memori adalah urutan "flat" dari byte. Elemen-elemen dari array multidimensi disimpan dalam urutan baris-utama. Yaitu,
connect_four[0][6]
danconnect_four[1][0]
tetangga dalam ingatan. Bahkan,connect_four[0][7]
danconnect_four[1][0]
menunjukkan elemen yang sama! Ini berarti Anda dapat mengambil array multi dimensi dan memperlakukannya sebagai array besar satu dimensi:Array multidimensi anonim
Dengan array multidimensi anonim, semua dimensi kecuali yang pertama harus diketahui pada waktu kompilasi:
Beginilah tampilan array multidimensi anonim dalam memori:
Perhatikan bahwa array itu sendiri masih dialokasikan sebagai satu blok di memori.
Array pointer
Anda dapat mengatasi pembatasan lebar tetap dengan memperkenalkan tingkat tipuan lainnya.
Bernama array pointer
Berikut adalah array bernama dari lima pointer yang diinisialisasi dengan array anonim dengan panjang yang berbeda:
Dan inilah tampilannya di memori:
Karena setiap baris dialokasikan secara individual sekarang, melihat array 2D sebagai array 1D tidak berfungsi lagi.
Array pointer anonim
Berikut adalah array anonim dari 5 (atau jumlah lainnya) pointer yang diinisialisasi dengan array anonim dengan panjang berbeda:
Dan inilah tampilannya di memori:
Konversi
Array-to-pointer decay secara alami meluas ke array array dan array pointer:
Namun, tidak ada konversi implisit dari
T[h][w]
keT**
. Jika konversi implisit seperti itu memang ada, hasilnya akan menjadi pointer ke elemen pertama dari arrayh
pointer keT
(masing-masing menunjuk ke elemen pertama dari sebuah garis dalam array 2D asli), tetapi array pointer tidak ada di mana pun di memori belum. Jika Anda ingin konversi seperti itu, Anda harus membuat dan mengisi array pointer yang diperlukan secara manual:Perhatikan bahwa ini menghasilkan tampilan array multidimensi asli. Jika Anda memerlukan salinan, Anda harus membuat array tambahan dan menyalin data sendiri:
sumber
int connect_four[H][7];
,int connect_four[6][W];
int connect_four[H][W];
sertaint (*p)[W] = new int[6][W];
danint (*p)[W] = new int[H][W];
merupakan pernyataan yang valid, kapanH
danW
diketahui pada saat kompilasi.Tugas
Tanpa alasan tertentu, array tidak dapat ditugaskan satu sama lain. Gunakan
std::copy
sebaliknya:Ini lebih fleksibel daripada yang diberikan oleh penugasan array yang sebenarnya karena dimungkinkan untuk menyalin irisan array yang lebih besar ke dalam array yang lebih kecil.
std::copy
biasanya dikhususkan untuk tipe primitif untuk memberikan kinerja maksimal. Kecil kemungkinannyastd::memcpy
berkinerja lebih baik. Jika ragu, ukurlah.Meskipun Anda tidak dapat menetapkan array secara langsung, Anda dapat menetapkan struct dan kelas yang berisi anggota array. Itu karena anggota array disalin secara anggota oleh operator penugasan yang disediakan sebagai default oleh kompiler. Jika Anda menetapkan operator penugasan secara manual untuk jenis struct atau kelas Anda sendiri, Anda harus kembali ke menyalin manual untuk anggota array.
Melewati parameter
Array tidak bisa dilewati oleh nilai. Anda dapat melewati mereka dengan pointer atau dengan referensi.
Lewati dengan pointer
Karena array itu sendiri tidak dapat dilewati oleh nilai, biasanya pointer ke elemen pertama dilewatkan oleh nilai. Ini sering disebut "pass by pointer". Karena ukuran array tidak dapat diambil melalui pointer itu, Anda harus melewatkan parameter kedua yang menunjukkan ukuran array (solusi C klasik) atau pointer kedua yang menunjuk setelah elemen terakhir array (solusi C ++ iterator) :
Sebagai alternatif sintaksis, Anda juga dapat mendeklarasikan parameter sebagai
T p[]
, dan itu berarti hal yang sama persis sepertiT* p
dalam konteks daftar parameter saja :Anda dapat menganggap compiler sebagai menulis ulang
T p[]
untukT *p
dalam konteks daftar parameter hanya . Aturan khusus ini sebagian bertanggung jawab atas seluruh kebingungan tentang array dan pointer. Dalam setiap konteks lain, mendeklarasikan sesuatu sebagai array atau sebagai pointer membuat perbedaan besar .Sayangnya, Anda juga bisa memberikan ukuran dalam parameter array yang diabaikan oleh kompiler secara diam-diam. Yaitu, tiga tanda tangan berikut ini persis sama, seperti yang ditunjukkan oleh kesalahan kompilator:
Lewati dengan referensi
Array juga dapat dilewatkan dengan referensi:
Dalam hal ini, ukuran array signifikan. Karena menulis fungsi yang hanya menerima array dengan tepat 8 elemen tidak banyak berguna, programmer biasanya menulis fungsi seperti templat:
Perhatikan bahwa Anda hanya dapat memanggil templat fungsi tersebut dengan array integer yang sebenarnya, bukan dengan pointer ke integer. Ukuran array secara otomatis disimpulkan, dan untuk setiap ukuran
n
, fungsi yang berbeda dipakai dari template. Anda juga dapat menulis templat fungsi yang cukup berguna yang abstrak dari jenis elemen dan dari ukuran.sumber
void foo(int a[3])
a
itu terlihat seperti seseorang sedang melewati nilai, memodifikasia
bagian dalamfoo
akan mengubah array asli. Ini harus jelas karena array tidak dapat disalin, tetapi mungkin layak untuk memperkuatnya.ranges::copy(a, b)
int sum( int size_, int a[size_]);
- dari (saya pikir) C99 dan seterusnya5. Kesalahan umum saat menggunakan array.
5.1 Jebakan: Mempercayai tautan jenis tidak aman.
OK, Anda telah diberitahu, atau telah mengetahui sendiri, bahwa global (variabel lingkup namespace yang dapat diakses di luar unit terjemahan) adalah Evil ™. Tapi apakah Anda tahu betapa sebenarnya Evil ™ mereka? Pertimbangkan program di bawah ini, yang terdiri dari dua file [main.cpp] dan [angka.cpp]:
Pada Windows 7 ini mengkompilasi dan menghubungkan dengan baik dengan MinGW g ++ 4.4.1 dan Visual C ++ 10.0.
Karena tipe tidak cocok, program macet ketika Anda menjalankannya.
Penjelasan di dalam-formal: program ini memiliki Perilaku Tidak Terdefinisi (UB), dan alih-alih menabraknya, itu hanya dapat hang, atau mungkin tidak melakukan apa-apa, atau dapat mengirim threating email ke presiden Amerika Serikat, Rusia, India, Cina dan Swiss, dan membuat Nasal Daemon terbang keluar dari hidung Anda.
Dalam prakteknya penjelasan: dalam
main.cpp
array diperlakukan sebagai pointer, ditempatkan pada alamat yang sama dengan array. Untuk 32-bit yang dapat dieksekusi ini berarti bahwa nilai pertamaint
dalam array, diperlakukan sebagai pointer. Yaitu, dimain.cpp
dalamnumbers
variabel mengandung, atau muncul untuk mengandung,(int*)1
. Ini menyebabkan program mengakses memori di bagian paling bawah ruang alamat, yang secara konvensional disediakan dan menyebabkan jebakan. Hasil: Anda mengalami kerusakan.Para penyusun sepenuhnya dalam hak mereka untuk tidak mendiagnosis kesalahan ini, karena C ++ 11 §3.5 / 10 mengatakan, tentang persyaratan jenis yang kompatibel untuk deklarasi,
Paragraf yang sama merinci variasi yang diizinkan:
Variasi yang dibolehkan ini tidak termasuk mendeklarasikan nama sebagai array dalam satu unit terjemahan, dan sebagai penunjuk dalam unit terjemahan lain.
5.2 Jebakan: Melakukan optimasi prematur (
memset
& teman).Belum ditulis
5.3 Pitfall: Menggunakan idiom C untuk mendapatkan sejumlah elemen.
Dengan pengalaman C yang dalam, wajar untuk menulis ...
Karena
array
peluruhan untuk menunjuk ke elemen pertama di mana diperlukan, ekspresisizeof(a)/sizeof(a[0])
juga dapat ditulis sebagaisizeof(a)/sizeof(*a)
. Artinya sama, dan tidak peduli bagaimana ditulisnya, ini adalah ungkapan C untuk menemukan elemen-elemen bilangan array.Perangkap utama: idiom C tidak aman untuk huruf. Misalnya, kode ...
meneruskan pointer ke
N_ITEMS
, dan karena itu kemungkinan besar menghasilkan hasil yang salah. Dikompilasi sebagai executable 32-bit pada Windows 7 yang dihasilkannya ...int const a[7]
menjadi adilint const a[]
.int const a[]
untukint const* a
.N_ITEMS
Oleh karena itu dipanggil dengan pointer.sizeof(array)
(ukuran pointer) maka 4.sizeof(*array)
setara dengansizeof(int)
, yang untuk executable 32-bit juga 4.Untuk mendeteksi kesalahan ini pada saat dijalankan Anda dapat melakukan ...
Deteksi kesalahan runtime lebih baik daripada tidak ada deteksi, tetapi membuang-buang sedikit waktu prosesor, dan mungkin lebih banyak waktu programmer. Lebih baik dengan deteksi pada waktu kompilasi! Dan jika Anda senang tidak mendukung array tipe lokal dengan C ++ 98, maka Anda dapat melakukannya:
Kompilasi definisi ini diganti dengan program lengkap pertama, dengan g ++, saya dapat…
Cara kerjanya: array dilewatkan dengan referensi untuk
n_items
, dan sehingga tidak membusuk untuk pointer ke elemen pertama, dan fungsi hanya bisa mengembalikan jumlah elemen yang ditentukan oleh jenis.Dengan C ++ 11 Anda dapat menggunakan ini juga untuk larik tipe lokal, dan ini adalah tipe aman C ++ idiom untuk menemukan jumlah elemen array.
5.4 C ++ 11 & C ++ 14 pitfall: Menggunakan
constexpr
fungsi ukuran array.Dengan C ++ 11 dan kemudian itu wajar, tetapi karena Anda akan melihat berbahaya !, untuk menggantikan fungsi C ++ 03
dengan
di mana perubahan signifikan adalah penggunaan
constexpr
, yang memungkinkan fungsi ini menghasilkan konstanta waktu kompilasi .Misalnya, berbeda dengan fungsi C ++ 03, konstanta waktu kompilasi seperti itu dapat digunakan untuk mendeklarasikan array dengan ukuran yang sama dengan yang lain:
Tetapi pertimbangkan kode ini menggunakan
constexpr
versi:Perangkap: pada Juli 2015 di atas mengkompilasi dengan MinGW-64 5.1.0 dengan
C ++ 11 C ++ 14 $ 5,19 / 2 dasbor ke sembilan-pedantic-errors
, dan, pengujian dengan kompiler online di gcc.godbolt.org/ , juga dengan dentang 3.0 dan dentang 3.2, tetapi tidak dengan dentang 3.3, 3.4. 1, 3.5.0, 3.5.1, 3.6 (rc1) atau 3.7 (percobaan). Dan penting untuk platform Windows, itu tidak dikompilasi dengan Visual C ++ 2015. Alasannya adalah pernyataan C ++ 11 / C ++ 14 tentang penggunaan referensi dalamconstexpr
ekspresi:Seseorang selalu dapat menulis lebih banyak verbose
... tapi ini gagal ketika
Collection
bukan array mentah.Untuk menangani koleksi yang bisa berupa non-array kita perlu kelebihan
n_items
fungsi, tetapi juga, untuk waktu kompilasi, kita perlu representasi waktu kompilasi dari ukuran array. Dan solusi klasik C ++ 03, yang berfungsi dengan baik juga di C ++ 11 dan C ++ 14, adalah membiarkan fungsi melaporkan hasilnya bukan sebagai nilai melainkan melalui tipe hasil fungsinya . Misalnya seperti ini:Tentang pilihan jenis pengembalian untuk
static_n_items
: kode ini tidak digunakanstd::integral_constant
karena denganstd::integral_constant
hasilnya direpresentasikan secara langsung sebagaiconstexpr
nilai, memperkenalkan kembali masalah asli. Alih-alihSize_carrier
kelas satu dapat membiarkan fungsi langsung mengembalikan referensi ke array. Namun, tidak semua orang akrab dengan sintaksis itu.Tentang penamaan: bagian dari solusi ini untuk masalah
constexpr
-invalid-karena-referensi adalah membuat pilihan waktu kompilasi konstan.Semoga oops-ada-ada-referensi-yang terlibat-dalam-
constexpr
masalah Anda akan diperbaiki dengan C ++ 17, tetapi sampai saat itu makro sepertiSTATIC_N_ITEMS
portabilitas menghasilkan di atas, misalnya untuk dentang dan kompiler Visual C ++, tipe penahan keamanan.Terkait: makro tidak menghormati cakupan, jadi untuk menghindari tabrakan nama, sebaiknya menggunakan awalan nama, mis
MYLIB_STATIC_N_ITEMS
.sumber
Segmentation fault
... Saya akhirnya menemukan / mengerti setelah membaca penjelasan Anda! Silakan tulis bagian §5.2 Anda :-) Cheerssize_t
, itu tidak memiliki kelebihan yang saya tahu untuk platform modern, tetapi memiliki sejumlah masalah karena aturan konversi tipe implisit dari C dan C ++. Artinya,ptrdiff_t
digunakan dengan sangat sengaja, untuk menghindari masalah dengansize_t
. Namun orang harus menyadari bahwa g ++ memiliki masalah dengan ukuran array yang cocok dengan parameter templat kecuali jika itusize_t
(saya tidak berpikir masalah khusus kompiler ini dengan yang tidaksize_t
penting, tetapi YMMV).size_t
untuk menunjukkan ukuran array, tentu saja tidak.Array pembuatan dan inisialisasi
Seperti halnya objek C ++ lainnya, array dapat disimpan secara langsung dalam variabel bernama (maka ukurannya harus berupa konstanta waktu kompilasi; C ++ tidak mendukung VLA ), atau array dapat disimpan secara anonim di heap dan diakses secara tidak langsung melalui pointer (hanya kemudian ukurannya dapat dihitung pada saat runtime).
Array otomatis
Array otomatis (array yang hidup "pada tumpukan") dibuat setiap kali aliran kontrol melewati definisi variabel array lokal non-statis:
Inisialisasi dilakukan dalam urutan menaik. Perhatikan bahwa nilai awal tergantung pada jenis elemen
T
:T
adalah POD (sepertiint
dalam contoh di atas), tidak ada inisialisasi berlangsung.T
menginisialisasi semua elemen.T
tidak menyediakan konstruktor default yang dapat diakses, program tidak dapat dikompilasi.Atau, nilai awal dapat secara eksplisit ditentukan dalam penginisialisasi array , daftar yang dipisahkan koma yang dikelilingi oleh kurung keriting:
Karena dalam hal ini jumlah elemen dalam penginisialisasi array sama dengan ukuran array, menentukan ukuran secara manual berlebihan. Secara otomatis dapat disimpulkan oleh kompiler:
Dimungkinkan juga untuk menentukan ukuran dan menyediakan penginisialisasi array yang lebih pendek:
Dalam hal ini, elemen yang tersisa diinisialisasi nol . Perhatikan bahwa C ++ memungkinkan penginisialisasi array kosong (semua elemen diinisialisasi nol), sedangkan C89 tidak (setidaknya diperlukan satu nilai). Perhatikan juga bahwa inisialisasi array hanya dapat digunakan untuk menginisialisasi array; nanti tidak bisa digunakan dalam penugasan.
Array statis
Array statis (array yang hidup "di segmen data") adalah variabel array lokal yang didefinisikan dengan
static
kata kunci dan variabel array pada lingkup namespace ("variabel global"):(Perhatikan bahwa variabel di lingkup namespace secara implisit statis. Menambahkan
static
kata kunci ke definisi mereka memiliki arti yang sama sekali berbeda, usang .)Berikut adalah bagaimana array statis berperilaku berbeda dari array otomatis:
(Tidak ada satu pun di atas yang khusus untuk array. Aturan-aturan ini berlaku juga untuk jenis objek statis lainnya.)
Array anggota data
Anggota data array dibuat ketika objek mereka dibuat. Sayangnya, C ++ 03 tidak menyediakan sarana untuk menginisialisasi array dalam daftar penginisialisasi anggota , jadi inisialisasi harus dipalsukan dengan tugas:
Sebagai alternatif, Anda dapat menetapkan larik otomatis di badan konstruktor dan menyalin elemen-elemennya:
Dalam C ++ 0x, array dapat diinisialisasi dalam daftar penginisialisasi anggota berkat inisialisasi seragam :
Ini adalah satu-satunya solusi yang berfungsi dengan tipe elemen yang tidak memiliki konstruktor default.
Array dinamis
Array dinamis tidak memiliki nama, karenanya satu-satunya cara mengaksesnya adalah melalui pointer. Karena mereka tidak memiliki nama, saya akan menyebutnya sebagai "array anonim" mulai sekarang.
Di C, array anonim dibuat via
malloc
dan teman. Di C ++, array anonim dibuat menggunakannew T[size]
sintaks yang mengembalikan pointer ke elemen pertama dari array anonim:Seni ASCII berikut menggambarkan tata letak memori jika ukurannya dihitung sebagai 8 pada saat runtime:
Jelas, array anonim membutuhkan lebih banyak memori daripada array bernama karena pointer tambahan yang harus disimpan secara terpisah. (Ada juga beberapa overhead tambahan di toko gratis.)
Perhatikan bahwa tidak ada peluruhan array-ke-pointer yang terjadi di sini. Meskipun mengevaluasi
new int[size]
apakah sebenarnya membuat berbagai bilangan bulat, hasil dari ekspresinew int[size]
adalah sudah pointer ke bilangan bulat (elemen pertama), tidak array bilangan bulat atau pointer ke array bilangan bulat ukuran yang tidak diketahui. Itu tidak mungkin, karena sistem tipe statis memerlukan ukuran array untuk menjadi konstanta kompilasi-waktu. (Oleh karena itu, saya tidak membubuhi keterangan anonim array dengan jenis informasi statis dalam gambar.)Mengenai nilai default untuk elemen, array anonim berperilaku mirip dengan array otomatis. Biasanya, array POD anonim tidak diinisialisasi, tetapi ada sintaks khusus yang memicu inisialisasi nilai:
(Perhatikan pasangan tanda kurung tepat sebelum tanda titik koma.) Sekali lagi, C ++ 0x menyederhanakan aturan dan memungkinkan menentukan nilai awal untuk array anonim berkat inisialisasi seragam:
Jika Anda selesai menggunakan array anonim, Anda harus melepaskannya kembali ke sistem:
Anda harus melepaskan setiap array anonim tepat sekali dan kemudian tidak pernah menyentuhnya lagi sesudahnya. Tidak melepaskannya sama sekali menghasilkan kebocoran memori (atau lebih umum, tergantung pada jenis elemen, kebocoran sumber daya), dan mencoba melepaskannya berkali-kali menghasilkan perilaku yang tidak terdefinisi. Menggunakan bentuk non-array
delete
(ataufree
) alih-alihdelete[]
melepaskan array juga perilaku yang tidak terdefinisi .sumber
static
penggunaan dalam lingkup namespace telah dihapus di C ++ 11.new
saya operator, tentu saja dapat mengembalikan array yang diberi alokasi dengan referensi. Tidak ada gunanya ...new
jauh lebih tua daripada referensi.int a[10]; int (&r)[] = a;