Dasar Fungsi

Mendeklarasikan, mendefinisikan, dan memanggil fungsi beserta alasan prototype diperlukan.

Daftar isi

Fungsi adalah blok kode bernama yang menerima masukan, mengerjakan satu tugas tertentu, dan dapat dipanggil berulang kali dari bagian lain program. Topik ini membahas cara mendefinisikan fungsi, memanggilnya, serta mendeklarasikannya lebih dahulu sebelum dipakai. Pemahaman ini menjadi dasar untuk memecah program yang panjang menjadi bagian-bagian kecil yang mudah diuji.

Mendefinisikan dan memanggil fungsi#

Definisi fungsi (function definition) memuat empat bagian, yaitu tipe nilai kembali, nama fungsi, daftar parameter, dan tubuh fungsi yang diapit kurung kurawal. Tipe nilai kembali menyatakan jenis nilai yang diserahkan fungsi kepada pemanggilnya melalui pernyataan return, sedangkan daftar parameter menampung masukan dalam bentuk variabel lokal fungsi. Berikut bentuk umumnya.

c Anatomi definisi fungsi
// tidak-dijalankan
double luas_persegi(double sisi)
{
    return sisi * sisi;
}

Fungsi luas_persegi menerima satu parameter bertipe double, menghitung hasil kalinya, lalu mengembalikan nilai dengan tipe yang sama. Fungsi dijalankan dengan menuliskan namanya diikuti argumen di dalam kurung, dan nilai hasilnya dapat disimpan ke variabel maupun langsung diteruskan ke fungsi lain. Program berikut menunjukkan dua pemanggilan dengan pemanfaatan hasil yang berbeda.

c luas-persegi.c
#include <stdio.h>

double luas_persegi(double sisi)
{
    return sisi * sisi;
}

int main(void)
{
    double luas = luas_persegi(2.5);

    printf("Luas persegi 2.5 x 2.5 : %.2f\n", luas);
    printf("Luas persegi 3.0 x 3.0 : %.2f\n", luas_persegi(3.0));
    return 0;
}
text Keluaran
Luas persegi 2.5 x 2.5 : 6.25
Luas persegi 3.0 x 3.0 : 9.00

Pemanggilan pertama menyimpan hasil perhitungan ke variabel luas, sedangkan pemanggilan kedua langsung mengoper hasilnya ke printf. Satu definisi fungsi melayani pemanggilan berapa kali pun, sehingga logika perhitungan cukup ditulis dan diuji sekali. Nama parameter hanya hidup di dalam fungsi masing-masing, sehingga pemilihan namanya bebas sepanjang tetap bermakna.

Fungsi boleh dipanggil dari fungsi mana pun, bukan hanya dari main. Rantai pemanggilan semacam ini membentuk tulang punggung program C yang utuh. Satu fungsi juga boleh memanggil dirinya sendiri, dan pola ini menjadi inti dari rekursi. Sebutan argumen dan parameter sering dipertukarkan, tetapi keduanya berbeda peran. Argumen adalah nilai yang dituliskan pada pemanggilan, sedangkan parameter adalah variabel yang menampungnya di dalam definisi fungsi.

Prototype dan urutan deklarasi#

Kompilator C membaca berkas dari atas ke bawah, sehingga pada baris pemanggilan ia harus sudah mengenal nama fungsi beserta tipe parameternya. Definisi yang diletakkan setelah main belum dikenali saat main memanggilnya, dan kompilasi langsung berhenti. Program berikut sengaja dibuat demikian, lalu dikompilasi untuk memperlihatkan pesan errornya.

c tanpa-prototype.c
// tidak-dijalankan
#include <stdio.h>

int main(void)
{
    printf("Luas: %.2f\n", luas_persegi(2.5));
    return 0;
}

double luas_persegi(double sisi)
{
    return sisi * sisi;
}
bash
# mengompilasi berkas yang memanggil fungsi sebelum dideklarasikan
gcc tanpa-prototype.c -o tanpa-prototype
text Keluaran
tanpa-prototype.c: In function ‘main’:
tanpa-prototype.c:6:28: error: implicit declaration of function ‘luas_persegi’ [-Wimplicit-function-declaration]
    6 |     printf("Luas: %.2f\n", luas_persegi(2.5));
      |                            ^~~~~~~~~~~~
tanpa-prototype.c: At top level:
tanpa-prototype.c:10:8: error: conflicting types for ‘luas_persegi’; have ‘double(double)’
   10 | double luas_persegi(double sisi)
      |        ^~~~~~~~~~~~
tanpa-prototype.c:6:28: note: previous implicit declaration of ‘luas_persegi’ with type ‘int()’
    6 |     printf("Luas: %.2f\n", luas_persegi(2.5));
      |                            ^~~~~~~~~~~~

Pesan implicit declaration of function muncul karena kompilator tidak menemukan deklarasi luas_persegi sebelum pemanggilannya. Sejak GCC 14 dan standar C23, keadaan ini dianggap error dan bukan lagi peringatan yang dapat diabaikan. Perbaikannya bukan memindahkan definisi ke atas, melainkan menambahkan prototype. Prototype adalah deklarasi fungsi tanpa tubuh, yaitu baris yang hanya memuat tipe kembali, nama, dan daftar tipe parameter diakhiri titik koma. Dengan prototype di bagian atas berkas, urutan definisi menjadi bebas dan setiap pemanggilan tetap diperiksa kesesuaiannya terhadap tanda tangan yang dijanjikan.

c dengan-prototype.c
#include <stdio.h>

/* Prototype: deklarasi tanpa tubuh fungsi, diakhiri titik koma. */
double luas_persegi(double sisi);

int main(void)
{
    printf("Luas: %.2f\n", luas_persegi(2.5));
    return 0;
}

/* Definisi lengkap boleh berada setelah main. */
double luas_persegi(double sisi)
{
    return sisi * sisi;
}
text Keluaran
Luas: 6.25

Prototype dan definisi kini terpisah, tetapi keduanya harus berbagi tanda tangan yang sama persis. Perbedaan satu tipe saja, misalnya parameter yang satu double dan yang lain int, memicu error conflicting types saat definisinya ditemukan. Kebiasaan yang lazim adalah menumpuk seluruh prototype di bagian atas berkas, tepat setelah arahan #include. Urutan di antara prototype pun bebas, karena yang penting hanya posisinya sebelum pemanggilan pertama.

Fungsi tanpa nilai kembali#

Belum semua pekerjaan menghasilkan nilai, sehingga C menyediakan tipe kembali void untuk fungsi yang hanya beraksi, misalnya mencetak keluaran ke layar. Fungsi void dipanggil sebagai pernyataan tunggal, dan hasilnya tidak dapat disimpan karena memang tidak ada. Pernyataan return tanpa nilai boleh ditulis di dalamnya untuk mengakhiri fungsi lebih awal.

c cetak-garis.c
#include <stdio.h>

void cetak_garis(int panjang)
{
    int i;

    for (i = 0; i < panjang; i = i + 1) {
        printf("=");
    }
    printf("\n");
}

int main(void)
{
    cetak_garis(20);
    printf("Laporan suhu ruangan\n");
    cetak_garis(20);
    return 0;
}
text Keluaran
====================
Laporan suhu ruangan
====================

Fungsi cetak_garis dipanggil dua kali dengan panjang berbeda tanpa perlu menyalin perulangannya ke dua tempat. Daftar parameter int panjang menyatakan masukan wajib. Fungsi tanpa masukan sama sekali ditulis dengan (void) pada daftar parameternya, sebagaimana tampak pada main. Bentuk (void) ini bukan sekadar gaya, melainkan cara baku untuk menyatakan bahwa fungsi tidak menerima parameter apa pun. Nama fungsi C lazim ditulis dengan huruf kecil dan garis bawah sebagai pemisah, sebagaimana luas_persegi dan cetak_garis pada topik ini.

Nilai kembali fungsi main punya peran tersendiri, yaitu melaporkan status berakhirnya program kepada sistem operasi. Angka nol menyatakan program selesai dengan lancar, sedangkan nilai lain lazim dipakai sebagai tanda kegagalan. Konvensi inilah alasan kerangka int main(void) dipakai pada hampir semua program C.

Kesalahan umum#

Empat kesalahan berikut paling sering muncul ketika fungsi pertama kali didefinisikan, dan semuanya terdeteksi oleh kompilator sebelum program berjalan.

  • Memanggil fungsi sebelum dideklarasikan. Kompilator melaporkan implicit declaration of function dan kompilasi berhenti. Tambahkan prototype sebelum pemanggilan pertama, atau pindahkan definisi ke atas main.
  • Membuat prototype yang tidak sama dengan definisinya. Tipe kembali atau tipe parameter yang berbeda memicu error conflicting types. Salin baris definisi, tempel di atas berkas, lalu tambahkan titik koma agar keduanya terjamin sama.
  • Membiarkan jalur eksekusi tanpa return pada fungsi non-void. GCC menandainya dengan peringatan control reaches end of non-void function, dan nilai yang diterima pemanggil menjadi tidak dapat dipercaya. Pastikan setiap jalur eksekusi berakhir dengan return.
  • Menuliskan titik koma setelah tanda kurung definisi. Baris double luas_persegi(double sisi); yang langsung diikuti kurung kurawal membuat kompilator membaca dua pernyataan yang tidak tersambung. Tanda titik koma hanya muncul pada prototype, sedangkan definisi langsung diikuti tubuh fungsinya.

Ringkasan#

  • Definisi fungsi memuat tipe nilai kembali, nama, daftar parameter, dan tubuhnya, sedangkan pemanggilan menggantikan ekspresi dengan nilai yang dikembalikan return.
  • Prototype menyatakan tanda tangan fungsi tanpa tubuhnya, sehingga definisi boleh berada di mana saja dan setiap pemanggilan tetap diperiksa.
  • Sejak GCC 14 dan C23, pemanggilan fungsi yang belum dideklarasikan berhenti sebagai error kompilasi, bukan lagi peringatan.
  • Fungsi tanpa nilai kembali bertipe void, dipanggil sebagai pernyataan, dan menuliskan (void) apabila tidak menerima parameter.

Referensi#