Di C, fungsi bukan sekadar blok kode yang dijalankan—fungsi juga punya alamat di memori yang dapat ditunjuk oleh function pointer. Function pointer memungkinkan kita memperlakukan fungsi sebagai data: kita dapat menyimpannya dalam variabel, melewatkan sebagai parameter, atau memilih fungsi mana yang akan dipanggil saat runtime. Konsep ini adalah pondasi banyak pola lanjutan seperti callback, dispatch table, dan implementasi qsort di pustaka standar. Pada chapter pengantar ini kita akan menelusuri deklarasi function pointer, cara memanggil fungsi lewat pointer, serta contoh praktis dengan qsort.
Deklarasi Function Pointer #
Sintaks deklarasi function pointer cukup khas dan sering terlihat membingungkan pada pandangan pertama:
return_type (*nama_pointer)(tipe_parameter1, tipe_parameter2, ...);Tanda kurung di sekitar *nama_pointer wajib ada karena operator () memiliki precedence lebih tinggi daripada *. Tanpa tanda kurung, return_type *nama_pointer(...) akan dideklarasikan sebagai “fungsi yang mengembalikan pointer”, bukan “pointer ke fungsi”. Mari kita lihat contoh konkret.
#include <stdio.h>
/* Fungsi biasa yang akan ditunjuk pointer */
int tambah(int a, int b) { return a + b; }
int kurang(int a, int b) { return a - b; }
int kali(int a, int b) { return a * b; }
int main(void) {
/* Deklarasi function pointer */
int (*operasi)(int, int);
/* Assign fungsi ke pointer (nama fungsi otomatis menjadi alamat) */
operasi = tambah;
printf("10 + 3 = %d\n", operasi(10, 3));
operasi = kurang;
printf("10 - 3 = %d\n", operasi(10, 3));
operasi = kali;
printf("10 * 3 = %d\n", operasi(10, 3));
/* Cara alternatif: dereferensi eksplisit */
int (*operasi2)(int, int) = &kali;
printf("(alternatif) 5 * 4 = %d\n", (*operasi2)(5, 4));
return 0;
}Output yang Dihasilkan:
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
(alternatif) 5 * 4 = 20Mari kita telaah baris-baris kode di atas:
- Baris 9 (
int (*operasi)(int, int);): deklarasi variabeloperasisebagai pointer ke fungsi yang menerima duaintdan mengembalikanint. Tanda kurung(*operasi)wajib—tanpa itu,int *operasi(int, int)berarti “fungsi bernamaoperasiyang menerima duaintdan mengembalikanint *”. - Baris 12 (
operasi = tambah;): assign fungsitambahke pointeroperasi. Nama fungsi (sepertitambah) otomatis dikonversi menjadi alamat fungsi—tidak perlu&secara eksplisit, walaupun&tambahjuga valid. - Baris 13 (
operasi(10, 3)): pemanggilan fungsi melalui pointer. Sintaksoperasi(10, 3)setara dengan pemanggilan langsungtambah(10, 3). Compiler otomatis mendereferensi pointer dan memanggil fungsi yang ditunjuk. - Baris 16 (
operasi = kurang;): assign ulang pointer ke fungsi lain. Inilah inti dari function pointer: fungsi mana yang dipanggil dapat ditentukan saat runtime. - Baris 22 (
int (*operasi2)(int, int) = &kali;): inisialisasi langsung dengan&kali. Bentuk&kalidankalikeduanya menghasilkan alamat fungsi yang sama. - Baris 23 (
(*operasi2)(5, 4)): pemanggilan dengan dereferensi eksplisit. Bentuk ini setara denganoperasi2(5, 4)—keduanya valid, tetapi bentuk eksplisit lebih menonjolkan bahwaoperasi2adalah pointer.
Function Pointer sebagai Parameter #
Salah satu kegunaan utama function pointer adalah melewatkan fungsi sebagai callback ke fungsi lain. Pola ini memungkinkan kita menulis fungsi generik yang dapat menyesuaikan perilakunya berdasarkan fungsi yang dilewatkan pemanggil.
#include <stdio.h>
/* Operasi matematika sederhana */
int tambah(int a, int b) { return a + b; }
int kurang(int a, int b) { return a - b; }
int kali(int a, int b) { return a * b; }
/* Fungsi yang menerima function pointer sebagai parameter */
void apply(int (*op)(int, int), int x, int y) {
int hasil = op(x, y); /* Memanggil fungsi lewat pointer */
printf("Hasil operasi: %d\n", hasil);
}
int main(void) {
printf("Dengan tambah: ");
apply(tambah, 8, 5); /* Nama fungsi otomatis diconvert ke pointer */
printf("Dengan kurang: ");
apply(kurang, 8, 5);
printf("Dengan kali : ");
apply(kali, 8, 5);
return 0;
}Output yang Dihasilkan:
Dengan tambah: Hasil operasi: 13
Dengan kurang: Hasil operasi: 3
Dengan kali : Hasil operasi: 40Pada contoh di atas, parameter int (*op)(int, int) pada fungsi apply adalah function pointer. Pemanggil main melewatkan nama fungsi (tambah, kurang, kali) sebagai argument—nama fungsi otomatis dikonversi menjadi alamat. Di dalam apply, pemanggilan op(x, y) menjalankan fungsi yang ditunjuk. Fungsi apply tidak perlu tahu fungsi apa yang akan dipanggil—kontraknya hanya “fungsi yang menerima dua int dan mengembalikan int”. Pola ini disebut higher-order function di paradigma fungsional.
Studi Kasus: qsort dari Pustaka Standar #
Salah satu contoh function pointer paling terkenal di pustaka standar C adalah qsort di <stdlib.h>. Fungsi qsort menerima array, jumlah elemen, ukuran elemen, dan sebuah comparator berupa function pointer. Comparator menentukan urutan sorting—pemanggil bebas mendefinisikan urutan naik, turun, atau aturan kustom.
#include <stdio.h>
#include <stdlib.h>
/* Pembanding untuk qsort */
int banding_naik(const void *a, const void *b) {
int x = *(const int *)a;
int y = *(const int *)b;
return (x > y) - (x < y);
}
int banding_turun(const void *a, const void *b) {
int x = *(const int *)a;
int y = *(const int *)b;
return (y > x) - (y < x);
}
void cetak_arr(const int *arr, int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main(void) {
int data[] = {5, 2, 9, 1, 7, 3};
int n = sizeof(data) / sizeof(data[0]);
printf("Awal : ");
cetak_arr(data, n);
qsort(data, n, sizeof(int), banding_naik);
printf("Naik : ");
cetak_arr(data, n);
qsort(data, n, sizeof(int), banding_turun);
printf("Turun : ");
cetak_arr(data, n);
return 0;
}Output yang Dihasilkan:
Awal : 5 2 9 1 7 3
Naik : 1 2 3 5 7 9
Turun : 9 7 5 3 2 1 Pada contoh di atas, parameter banding_naik dan banding_turun adalah function pointer dengan signature int (*)(const void *, const void *). Parameter comparator menerima const void * (pointer generik) sehingga qsort dapat bekerja dengan tipe data apa pun—pemanggil bertanggung jawab meng-cast const void * ke tipe konkret di dalam comparator. Ekspresi (x > y) - (x < y) menghasilkan -1 bila x < y, 0 bila x == y, dan +1 bila x > y—idiot antisipasi overflow pada pengurangan langsung x - y untuk bilangan besar.
Function pointer adalah pintu gerbang menuju banyak pola lanjutan di C—callback event handler, dispatch table, plugin system, dan state machine. Pada chapter pengantar ini kita baru menyentuh permukaannya; chapter-chapter selanjutnya akan menggunakan function pointer sebagai building block untuk topik yang lebih kompleks.