Ada pola ketika berhadapan dengan array dan fungsi; awalnya agak sulit dilihat.
Ketika berhadapan dengan array, ada baiknya untuk mengingat hal-hal berikut: ketika ekspresi array muncul di sebagian besar konteks, jenis ekspresi secara implisit dikonversi dari "N-element array T" ke "pointer ke T", dan nilainya diatur untuk menunjuk ke elemen pertama dalam array. Pengecualian untuk aturan ini adalah ketika ekspresi array muncul sebagai operan dari &
atausizeof
operator, atau ketika itu adalah string literal digunakan sebagai initializer dalam deklarasi.
Jadi, ketika Anda memanggil fungsi dengan ekspresi array sebagai argumen, fungsi tersebut akan menerima pointer, bukan array:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Inilah sebabnya mengapa Anda tidak menggunakan &
operator untuk argumen yang terkait dengan "% s" di scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
Karena konversi tersirat, scanf()
menerima char *
nilai yang menunjuk ke awal str
array. Ini berlaku untuk setiap fungsi yang disebut dengan ekspresi array sebagai argumen (hampir semua str*
fungsi, *scanf
dan *printf
fungsi, dll.).
Dalam praktiknya, Anda mungkin tidak akan pernah memanggil fungsi dengan ekspresi array menggunakan &
operator, seperti pada:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Kode seperti itu sangat tidak umum; Anda harus mengetahui ukuran array dalam deklarasi fungsi, dan fungsi hanya bekerja dengan pointer ke array ukuran tertentu (pointer ke array 10-elemen T adalah jenis yang berbeda dari pointer ke array 11-elemen dari T).
Ketika ekspresi array muncul sebagai operan ke &
operator, jenis ekspresi yang dihasilkan adalah "pointer ke array elemen-N dari T", atau T (*)[N]
, yang berbeda dari array pointer ( T *[N]
) dan pointer ke tipe dasar (T *
).
Ketika berhadapan dengan fungsi dan pointer, aturan yang harus diingat adalah: jika Anda ingin mengubah nilai argumen dan memilikinya tercermin dalam kode panggilan, Anda harus meneruskan pointer ke hal yang ingin Anda modifikasi. Sekali lagi, array melemparkan sedikit kunci pas ke dalam karya, tetapi kita akan berurusan dengan kasus normal terlebih dahulu.
Ingatlah bahwa C lewat semua argumen fungsi dengan nilai; parameter formal menerima salinan nilai dalam parameter aktual, dan setiap perubahan pada parameter formal tidak tercermin dalam parameter aktual. Contoh umum adalah fungsi swap:
void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
Anda akan mendapatkan output berikut:
sebelum swap: a = 1, b = 2
setelah swap: a = 1, b = 2
Parameter formal x
dan y
objek berbeda dari a
dan b
, sehingga berubah menjadi x
dan y
tidak tercermin dalam a
dan b
. Karena kami ingin memodifikasi nilai a
dan b
, kami harus meneruskan pointer ke fungsi swap:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);
Sekarang output Anda akan menjadi
sebelum swap: a = 1, b = 2
setelah swap: a = 2, b = 1
Perhatikan bahwa, dalam fungsi swap, kami tidak mengubah nilai x
dan y
, tetapi nilai apa x
dan y
menunjuk ke . Menulis ke *x
berbeda dari menulis ke x
; kami tidak memperbarui nilai x
itu sendiri, kami mendapatkan lokasi dari x
dan memperbarui nilai di lokasi itu.
Ini sama benarnya jika kita ingin memodifikasi nilai pointer; jika kita menulis
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
maka kita memodifikasi nilai parameter input stream
, bukan stream
menunjuk ke apa , jadi mengubah stream
tidak berpengaruh pada nilai in
; agar ini berfungsi, kita harus meneruskan sebuah pointer ke pointer:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Sekali lagi, array melemparkan sedikit kunci pas ke dalam karya. Saat Anda meneruskan ekspresi array ke suatu fungsi, fungsi yang diterima adalah sebuah pointer. Karena bagaimana array subscript didefinisikan, Anda bisa menggunakan operator subskrip pada pointer dengan cara yang sama Anda bisa menggunakannya pada array:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
Perhatikan bahwa objek array mungkin tidak ditugaskan; yaitu, Anda tidak dapat melakukan sesuatu seperti
int a[10], b[10];
...
a = b;
jadi Anda ingin berhati-hati ketika berhadapan dengan pointer ke array; sesuatu seperti
void (int (*foo)[N])
{
...
*foo = ...;
}
tidak akan bekerja