Ukuran tetap
1. Lulus dengan referensi
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Dalam C ++ melewatkan array dengan referensi tanpa kehilangan informasi dimensi mungkin yang paling aman, karena orang tidak perlu khawatir pemanggil melewati dimensi yang salah (flag compiler ketika ketidakcocokan). Namun, ini tidak dimungkinkan dengan array dinamis (freestore); ini bekerja untuk otomatis ( array biasanya stack-living ) yaitu dimensi harus diketahui pada waktu kompilasi.
2. Lewati dengan pointer
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
Setara C dari metode sebelumnya melewati array dengan pointer. Ini tidak boleh disalahartikan dengan melewati tipe pointer yang rusak (3) , yang merupakan metode umum dan populer, meskipun kurang aman daripada yang satu ini tetapi lebih fleksibel. Seperti (1) , gunakan metode ini ketika semua dimensi array diperbaiki dan diketahui pada waktu kompilasi. Perhatikan bahwa saat memanggil fungsi, alamat array harus dikirimkan process_2d_array_pointer(&a)
dan bukan alamat elemen pertama dengan pembusukan process_2d_array_pointer(a)
.
Ukuran Variabel
Ini diwarisi dari C tetapi kurang aman, kompiler tidak memiliki cara untuk memeriksa, menjamin bahwa pemanggil melewati dimensi yang diperlukan. Fungsi hanya bank pada apa yang penelepon masuk sebagai dimensi. Ini lebih fleksibel daripada yang di atas karena array dengan panjang yang berbeda dapat diteruskan ke mereka selalu.
Harus diingat bahwa tidak ada yang lewat array langsung ke fungsi dalam C [sementara di C + + mereka dapat dilewatkan sebagai referensi (1) ]; (2) meneruskan pointer ke array dan bukan array itu sendiri. Selalu melewati array apa adanya menjadi operasi pointer-copy yang difasilitasi oleh sifat array yang membusuk menjadi pointer .
3. Lewati (nilai) sebuah pointer ke tipe yang sudah membusuk
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Meskipun int array[][10]
diperbolehkan, saya tidak akan merekomendasikan ini di atas sintaks di atas karena sintaks di atas menjelaskan bahwa pengenal array
adalah pointer tunggal ke array 10 integer, sementara sintaks ini terlihat seperti array 2D tetapi adalah pointer yang sama untuk sebuah array 10 bilangan bulat. Di sini kita tahu jumlah elemen dalam satu baris (yaitu ukuran kolom, 10 di sini) tetapi jumlah baris tidak diketahui dan karenanya dilewatkan sebagai argumen. Dalam hal ini ada beberapa keamanan karena kompiler dapat menandai ketika pointer ke array dengan dimensi kedua tidak sama dengan 10 dilewatkan. Dimensi pertama adalah bagian yang bervariasi dan dapat dihilangkan. Lihat di sini untuk alasan mengapa hanya dimensi pertama yang boleh dihilangkan.
4. Lewati pointer ke pointer
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Sekali lagi ada sintaks alternatif int *array[10]
yang sama dengan int **array
. Dalam sintaksis [10]
ini diabaikan karena meluruh menjadi pointer sehingga menjadi int **array
. Mungkin itu hanya isyarat kepada pemanggil bahwa array yang lewat harus memiliki setidaknya 10 kolom, bahkan kemudian diperlukan jumlah baris. Dalam kasus apa pun kompilator tidak menandai pelanggaran panjang / ukuran (hanya memeriksa apakah tipe yang dilewati adalah pointer ke pointer), maka memerlukan jumlah baris dan kolom sebagai parameter masuk akal di sini.
Catatan: (4) adalah opsi yang paling tidak aman karena hampir tidak memiliki pemeriksaan tipe apa pun dan yang paling tidak nyaman. Seseorang tidak dapat secara sah melewatkan array 2D ke fungsi ini; C-FAQ mengutuk solusi yang biasa dilakukan int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
karena berpotensi menyebabkan perilaku yang tidak terdefinisi karena perataan array. Cara yang benar untuk melewatkan array dalam metode ini membawa kita ke bagian yang tidak nyaman, yaitu kita membutuhkan array pointer tambahan (dengan pengganti) dengan masing-masing elemennya menunjuk ke masing-masing baris dari array aktual yang akan dilewati; pengganti ini kemudian diteruskan ke fungsi (lihat di bawah); semua ini untuk mendapatkan pekerjaan yang sama dilakukan sebagai metode di atas yang lebih aman, bersih dan mungkin lebih cepat.
Inilah program driver untuk menguji fungsi-fungsi di atas:
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}