Sabit Boyut
1. referans ile geçmek
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;
}
}
C ++ 'da, boyut bilgisini kaybetmeden diziyi referans olarak geçirme, muhtemelen en güvenli olanıdır, çünkü arayanın yanlış bir boyut geçirmesi hakkında endişelenmenize gerek yoktur (uyuşmazken derleyici bayrakları). Ancak, dinamik (freestore) dizilerle bu mümkün değildir; yalnızca otomatik ( genellikle yığın-yaşam ) diziler için çalışır, yani boyutlandırma derleme zamanında bilinmelidir.
2. İşaretçi ile geçin
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;
}
}
Önceki yöntemin C eşdeğeri diziyi işaretçiyle geçiriyor. Bu, dizinin çürümüş işaretçi türünden (3) geçmemekle karıştırılmamalıdır , bu yaygın olan popüler yöntemdir, ancak bundan daha az güvenli ancak daha esnektir. Gibi (1) bir dizinin tüm boyutlar sabit ve derleme zamanında bilindiği zaman, bu yöntemi kullanır. İşlevi çağırırken, dizinin adresinin process_2d_array_pointer(&a)
bozulma yoluyla ilk öğenin adresini değil, geçirilmesi gerektiğini unutmayınprocess_2d_array_pointer(a)
.
Değişken Boyut
Bunlar C'den miras alınır, ancak daha az güvenlidir, derleyicinin kontrol etme yolu yoktur, arayanın gerekli boyutları geçtiğini garanti eder. İşlev yalnızca arayanın boyut (lar) olarak geçtiği şeyleri belirler. Bunlar, farklı uzunluklardaki diziler her zaman onlara geçirilebildiğinden, yukarıdakilerden daha esnektir.
Unutulmamalıdır ki, bir diziyi doğrudan C'deki bir işleve geçirmek gibi bir şey yoktur [C ++ 'da referans (1) olarak geçirilebilirler ]; (2) dizinin kendisine değil diziye bir işaretçi geçiriyor. Bir diziyi her zaman olduğu gibi iletmek, dizinin bir işaretçiye bozunmasının doğasıyla kolaylaştırılan bir işaretçi kopyalama işlemi haline gelir .
3. Çürümüş tipe bir işaretçi geçirin (değer verin)
// 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;
}
}
Her ne kadar int array[][10]
izin verilir Yukarıdaki söz dizimi o tanımlayıcı olduğunu temizlemek yapar çünkü, yukarıdaki sözdizimi üzerine bunu tavsiye ederim array
10 sayı dizisi için tek işaretçisi bu sözdizimi ederken, bakışlar bir 2D dizi ama aynı işaretçisi gibi 10 tamsayıdan oluşan bir dizi. Burada tek bir satırdaki elemanların sayısını biliyoruz (yani sütun boyutu, burada 10), ancak satırların sayısı bilinmiyor ve bu nedenle bir argüman olarak iletilecek. Bu durumda, ikinci boyut 10'a eşit olmayan bir diziye bir işaretçi geçirildiğinde derleyici işaretleyebileceğinden, bazı güvenlikler vardır. İlk boyut değişen kısımdır ve atlanabilir. Sadece ilk boyutun neden atlanmasına izin verildiğinin mantığı için buraya bakın .
4. İşaretçiyle işaretçiye geçin
// 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;
}
}
Yine bununla int *array[10]
aynı olan alternatif bir sözdizimi vardır int **array
. Bu sözdiziminde, [10]
bir işaretçiye dönüştüğü için yok sayılır ve böylece olur int **array
. Belki de geçilen dizinin en az 10 sütuna sahip olması, arayan için bir ipucudur, hatta satır sayısı gereklidir. Her durumda, derleyici herhangi bir uzunluk / boyut ihlali için işaretlemez (yalnızca geçirilen türün işaretçiye bir işaretçi olup olmadığını kontrol eder), bu nedenle parametre burada mantıklı olduğundan hem satır hem de sütun sayıları gerektirir.
Not: (4), herhangi bir tip kontrolü ve en rahatsız edici olması nedeniyle en güvenli seçenektir . Bu işleve yasal olarak bir 2D dizi geçirilemez; C-SSS kınadı yapmanın olağan geçici çözümü int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
o kadar potansiyel istenmeyen davranışlara yol açabilir nedeniyle dizi düzleşme. Bu yöntemde bir diziyi geçirmenin doğru yolu bizi rahatsız edici kısma getirir; yani, her bir öğesinin gerçek, geçilecek dizinin ilgili satırına işaret ettiği ek bir (yedek) işaretçi dizisine ihtiyacımız vardır; bu vekil daha sonra fonksiyona aktarılır (aşağıya bakınız); tüm bunlar, daha güvenli, daha temiz ve belki de daha hızlı olan yukarıdaki yöntemlerle aynı işi yapmak için.
Yukarıdaki işlevleri test etmek için bir sürücü programı:
#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**
}