Penggunaan array standar dalam C dengan peluruhan tipe alami dari array ke ptr
@Bo Persson dengan benar menyatakan dalam jawaban hebatnya di sini :
Saat mengoper array sebagai parameter, this
void arraytest(int a[])
artinya sama persis dengan
void arraytest(int *a)
Namun, izinkan saya menambahkan juga bahwa kedua bentuk di atas juga:
artinya sama persis dengan
void arraytest(int a[0])
yang artinya sama persis dengan
void arraytest(int a[1])
yang artinya sama persis dengan
void arraytest(int a[2])
yang artinya sama persis dengan
void arraytest(int a[1000])
dll.
Dalam setiap contoh larik di atas, jenis parameter input meluruh menjadiint *
, dan dapat dipanggil tanpa peringatan dan tanpa kesalahan, bahkan dengan opsi build -Wall -Wextra -Werror
diaktifkan (lihat repo saya di sini untuk detail tentang 3 opsi build ini), seperti ini:
int array1[2];
int * array2 = array1;
arraytest(array1);
arraytest(array2);
Sebagai soal fakta, "ukuran" nilai ( [0]
, [1]
, [2]
, [1000]
, dll) dalam parameter array di sini adalah ternyata hanya untuk tujuan / estetika diri dokumentasi, dan dapat setiap bilangan bulat positif ( size_t
tipe saya pikir) yang Anda inginkan!
Namun, dalam praktiknya, Anda harus menggunakannya untuk menentukan ukuran minimum larik yang Anda harapkan akan diterima oleh fungsi tersebut, sehingga saat menulis kode, Anda dapat dengan mudah melacak dan memverifikasi. Standar MISRA-C-2012 ( beli / unduh standar PDF versi 236-pg 2012 seharga £ 15,00 di sini ) sejauh menyatakan (penekanan ditambahkan):
Aturan 17.5 Argumen fungsi yang sesuai dengan parameter yang dideklarasikan memiliki tipe array harus memiliki jumlah elemen yang sesuai.
...
Jika parameter dideklarasikan sebagai array dengan ukuran yang ditentukan, argumen yang sesuai di setiap panggilan fungsi harus mengarah ke objek yang memiliki setidaknya sebanyak array.
...
Penggunaan deklarator larik untuk parameter fungsi menentukan antarmuka fungsi dengan lebih jelas daripada menggunakan penunjuk. Jumlah minimum elemen yang diharapkan oleh fungsi tersebut secara eksplisit dinyatakan, sedangkan ini tidak dimungkinkan dengan pointer.
Dengan kata lain, mereka merekomendasikan penggunaan format ukuran eksplisit, meskipun standar C secara teknis tidak memberlakukannya-- setidaknya membantu menjelaskan kepada Anda sebagai pengembang, dan kepada orang lain yang menggunakan kode, larik ukuran apa yang diharapkan fungsi tersebut. Anda untuk lulus.
Memaksakan keamanan tipe pada larik di C
Seperti yang ditunjukkan @Winger Sendon dalam komentar di bawah jawaban saya, kami dapat memaksa C untuk memperlakukan tipe array agar berbeda berdasarkan ukuran array !
Pertama, Anda harus menyadari bahwa dalam contoh saya di atas, menggunakan int array1[2];
seperti ini: arraytest(array1);
menyebabkan array1
membusuk secara otomatis menjadi file int *
. NAMUN, jika Anda mengambil alamat array1
alih - alih dan menelepon arraytest(&array1)
, Anda mendapatkan perilaku yang sama sekali berbeda! Sekarang, TIDAK membusuk menjadi int *
! Sebaliknya, tipe &array1
is int (*)[2]
, yang berarti "penunjuk ke larik berukuran 2 dari int" , atau "penunjuk ke larik berukuran 2 jenis int" . Jadi, Anda dapat FORCE C untuk memeriksa keamanan tipe pada array, seperti ini:
void arraytest(int (*a)[2])
{
}
Sintaks ini sulit dibaca, tetapi mirip dengan fungsi penunjuk . Alat online, cdecl , memberitahu kita bahwa itu int (*a)[2]
berarti: "mendeklarasikan a sebagai penunjuk ke larik 2 dari int" (penunjuk ke larik 2 int
s). JANGAN bingung dengan versi ini dengan tanda kurung OUT:, int * a[2]
yang berarti: "deklarasikan sebagai array 2 pointer ke int" (array 2 pointer ke int
).
Sekarang, fungsi ini MEMBUTUHKAN Anda untuk memanggilnya dengan operator alamat ( &
) seperti ini, menggunakan sebagai parameter masukan sebuah POINTER KE ARRAY DARI UKURAN YANG BENAR !:
int array1[2];
arraytest(&array1);
Namun, ini akan menghasilkan peringatan:
int array1[2];
arraytest(array1);
Anda dapat menguji kode ini di sini .
Untuk memaksa compiler C mengubah peringatan ini menjadi error, sehingga Anda HARUS selalu memanggil arraytest(&array1);
hanya menggunakan larik input dengan ukuran dan jenis yang benar ( int array1[2];
dalam kasus ini), tambahkan -Werror
ke opsi build Anda. Jika menjalankan kode tes di atas pada onlinegdb.com, lakukan ini dengan mengklik ikon roda gigi di kanan atas dan klik pada "Tanda Kompilator Tambahan" untuk mengetikkan opsi ini. Sekarang, peringatan ini:
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
akan berubah menjadi kesalahan versi ini:
main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
arraytest(array1);
^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
void arraytest(int (*a)[2])
^~~~~~~~~
cc1: all warnings being treated as errors
Perhatikan bahwa Anda juga dapat membuat pointer "type safe" ke array dengan ukuran tertentu, seperti ini:
int array[2];
int (*array_p)[2] = &array;
... tapi saya tidak selalu merekomendasikan ini, karena ini mengingatkan saya pada banyak kejenakaan C ++ yang digunakan untuk memaksa keamanan tipe di mana-mana, dengan biaya yang sangat tinggi dari kompleksitas sintaks bahasa, verbositas, dan kesulitan merancang kode, dan yang saya tidak suka dan telah mengoceh berkali-kali sebelumnya (mis .: lihat "My Thoughts on C ++" di sini ).
Untuk pengujian dan eksperimen tambahan, lihat juga tautan di bawah.
Referensi
Lihat tautan di atas. Juga:
- Percobaan kode saya online: https://onlinegdb.com/B1RsrBDFD