Function definition adalah tempat kita benar-benar menulis implementasi sebuah fungsi—mulai dari header (return type, nama, daftar parameter) hingga body { } yang berisi kode yang akan dijalankan saat fungsi dipanggil. Bila function declaration hanya memberi tahu compiler signature sebuah fungsi, function definition memberikan behavior atau perilaku konkretnya. Setiap fungsi yang dipanggil di program harus terdefinisi tepat satu kali di seluruh program (One Definition Rule). Pada chapter ini kita akan menelusuri anatomi function definition, penggunaan multiple return statement, serta pola early return yang membuat kode lebih mudah dibaca.
Anatomi Function Definition #
Sebuah function definition terdiri dari dua bagian utama:
- Function header:
return_type nama(parameter_list)—mirip dengan deklarasi, tetapi tanpa titik koma di akhir. - Function body: blok
{ }yang berisi statement-statement yang dijalankan saat fungsi dipanggil.
Saat compiler membaca sebuah definition, compiler menghasilkan kode mesin untuk body fungsi tersebut dan menyimpannya di text segment dari executable. Mari kita lihat contoh definition yang menghitung Body Mass Index (BMI).
#include <stdio.h>
/* Function definition: menghitung BMI dari berat (kg) dan tinggi (m) */
double hitung_bmi(double berat, double tinggi) {
return berat / (tinggi * tinggi);
}
/* Definition dengan const parameter - kontrak tidak mengubah input */
void cetak_status_bmi(double bmi) {
if (bmi < 18.5) {
printf("BMI %.2f: berat badan kurang\n", bmi);
} else if (bmi < 25.0) {
printf("BMI %.2f: berat badan normal\n", bmi);
} else if (bmi < 30.0) {
printf("BMI %.2f: berat badan berlebih\n", bmi);
} else {
printf("BMI %.2f: obesitas\n", bmi);
}
}
int main(void) {
double berat = 60.0; /* kg */
double tinggi = 1.70; /* meter */
double bmi = hitung_bmi(berat, tinggi);
cetak_status_bmi(bmi);
return 0;
}Output yang Dihasilkan:
BMI 20.76: berat badan normalMari kita telaah baris-baris kode di atas:
- Baris 4 (
double hitung_bmi(double berat, double tinggi)): function header tanpa titik koma. Tipe kembaliandoublemenandakan hasil berupa bilangan pecahan. - Baris 5 (
return berat / (tinggi * tinggi);): body fungsi yang berisi satu statementreturn. Ekspresiberat / (tinggi * tinggi)dievaluasi, lalu hasilnya dikirim balik ke pemanggil. Setelahreturn, eksekusi fungsi selesai—tidak ada statement lain yang bisa berjalan setelahnya dalam pemanggilan tersebut. - Baris 8 (
void cetak_status_bmi(double bmi)): definition fungsivoid(tidak mengembalikan nilai). Parameterbmimenerima nilai yang dilewatkan pemanggil. - Baris 9-19: body fungsi
cetak_status_bmiberisi rangkaianif-else if-elseuntuk mengategorikan BMI. Tidak adareturnkarena fungsivoid—body berakhir setelah statement terakhir dijalankan. - Baris 21 (
double bmi = hitung_bmi(berat, tinggi);): pemanggilanhitung_bmimengembalikandouble, yang ditugaskan ke variabel lokalbmi. - Baris 22 (
cetak_status_bmi(bmi);): nilaibmidilewatkan ke parameterbmidi fungsicetak_status_bmi(meskipun namanya sama, keduanya adalah variabel berbeda di scope berbeda—kita akan bahas ini di chapter Scope Variabel).
Multiple Return Statement #
Sebuah fungsi dapat memiliki lebih dari satu return statement. Saat salah satu return dieksekusi, fungsi segera berakhir dan mengembalikan nilai tersebut. Pola ini disebut early return: kita keluar dari fungsi secepat mungkin bila kondisi tertentu sudah terpenuhi, sehingga body utama menjadi lebih ringkas.
#include <stdio.h>
#include <stdbool.h>
/* Definition dengan multiple return (early return) */
bool adalah_tahun_kabisat(int tahun) {
if (tahun % 400 == 0) {
return true; /* Tahun kelipatan 400 selalu kabisat */
}
if (tahun % 100 == 0) {
return false; /* Kelipatan 100 (bukan 400) bukan kabisat */
}
if (tahun % 4 == 0) {
return true; /* Kelipatan 4 (bukan 100) kabisat */
}
return false; /* Sisanya bukan kabisat */
}
int main(void) {
int tahun2[] = {1900, 2000, 2020, 2023, 2024};
int n = sizeof(tahun2) / sizeof(tahun2[0]);
for (int i = 0; i < n; i++) {
bool kabisat = adalah_tahun_kabisat(tahun2[i]);
printf("%d: %s\n", tahun2[i], kabisat ? "kabisat" : "bukan kabisat");
}
return 0;
}Output yang Dihasilkan:
1900: bukan kabisat
2000: kabisat
2020: kabisat
2023: bukan kabisat
2024: kabisatFungsi adalah_tahun_kabisat mengandung empat return statement. Untuk tahun 2000, kondisi pertama tahun % 400 == 0 langsung terpenuhi, sehingga fungsi segera mengembalikan true tanpa memeriksa kondisi-kondisi lain. Untuk tahun 1900, kondisi pertama tidak terpenuhi (1900 % 400 = 275), kondisi kedua terpenuhi (1900 % 100 = 0), sehingga fungsi mengembalikan false. Aturan kelipatan 400 menimpa kelipatan 100, dan kelipatan 100 menimpa kelipatan 4—sangat penting bagi kalender Gregorian.
Mengembalikan Sinyal Error dari Definition #
Kadang kita perlu menandai bahwa sebuah input tidak valid atau array kosong. Konvensi umum di C adalah mengembalikan nilai sentinel (misalnya -1 untuk integer, atau NULL untuk pointer) yang menandakan kondisi error.
#include <stdio.h>
/* Definition: mencari nilai maksimum dalam array */
int cari_maks(const int arr[], int n) {
if (n <= 0) {
return -1; /* Sinyal error: array kosong */
}
int maks = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] > maks) {
maks = arr[i];
}
}
return maks;
}
int main(void) {
int data[] = {12, 5, 27, 8, 19, 3, 45};
int n = sizeof(data) / sizeof(data[0]);
int maks = cari_maks(data, n);
printf("Nilai maksimum: %d\n", maks);
printf("Maksimum array kosong: %d\n", cari_maks(NULL, 0));
return 0;
}Output yang Dihasilkan:
Nilai maksimum: 45
Maksimum array kosong: -1Pada contoh di atas, parameter arr diberi kwalifier const karena fungsi cari_maks hanya membaca elemen array, tidak mengubahnya. Bila n <= 0, fungsi segera mengembalikan -1 sebagai sinyal error. Pemanggil bertanggung jawab memeriksa nilai kembalian tersebut sebelum menggunakannya. Pola ini sederhana tetapi rapuh—-1 bisa juga merupakan nilai maksimum yang valid pada array berisi bilangan negatif. Untuk kasus seperti itu, mekanisme yang lebih aman adalah melewatkan pointer output dan mengembalikan kode status, sebuah pola yang akan kita bahas pada chapter Return Value.
Setelah memahami anatomi definition, kita siap melangkah ke chapter berikutnya yang membahas function prototype lebih dalam—termasuk kapan prototype wajib hadir dan manfaatnya bagi type checking lintas-file.