Friday, December 23, 2016

Bab 4. Pemrograman C Belajar Dari Contoh



Bab. 4 Fungsi

Tujuan Instruksional
      ·         Fungsi.
      ·         Definisi fungsi.
      ·         Prototipe fungsi.
      ·         Rekaman aktivasi dan tumpukan pemanggilan fungsi.
      ·         Pemanggilan fungsi dengan nilai dan dengan referensi.
    ·         Pembangkitan bilangan acak.
    ·         Kelas penyimpanan.
    ·         Aturan skop.
    ·         Rekursi.
    ·         Rekursi versus iterasi.




4.1 Introduksi

Kebanyakan program komputer yang menyelesaikan masalah-masalah dunia nyata jauh lebih besar dari program-program yang disajikan pada beberapa bab terdahulu. Pengalaman membuktikan bahwa cara terbaik untuk mengembangkan dan merawat suatu program yang besar adalah dengan mengkonstruksinya dari potongan-potongan atau modul-modul kecil, yang masing-masing lebih mudah dikelola daripada program yang asli. Teknik ini dinamakan dengan divide and conquer. Bab ini akan menjelaskan beberapa fitur bahasa C yang memfasilitas perancangan, implementasi, operasi, dan pemeliharaan program besar.

4.2 Modul Program Dalam C
Modul di dalam C disebut dengan fungsi. Program C umumnya ditulis dengan menggabungkan fungsi baru yang Anda tulis dengan fungsi paket yang tersedia di dalam pustaka standar C. Akan didiskusikan kedua jenis fungsi tersebut dalam bab ini. Pustaka standar C menyediakan koleksi fungsi yang kaya untuk melakukan operasi kalkulasi matametik, manipulasi string, masukan/keluaran, dan banyak operasi lainnya yang berguna. Modul berguna untuk mempermudah pekerjaan Anda, karena fungsi menyediakan banyak kapabilitas yang Anda butuhkan.

Meskipun fungsi-fungsi pustaka standar secara teknis bukan merupakan bagian dari bahasa C, tetapi semuanya disediakan di dalam sistem C standar. Fungsi printf, scanf, dan pow yang telah digunakan merupakan fungsi pustaka standar.

Anda dapat menulis fungsi untuk mendefinisikan beberapa tugas spesifik yang dapat dipakai di banyak tempat di dalam suatu program. Fungsi yang Anda tulis sendiri disebut pula dengan fungsi terdefinisi-programer. Statemen-statemen aktual yang mendefinisikan fungsi tersebut ditulis hanya sekali dan tersembunyi dari fungsi lain.

Fungsi dapat dipanggil melalui pemanggilan fungsi, yang menspesifikasi nama fungsi dan menyediakan informasi (sebagai argumen) yang dibutuhkan oleh fungsi yang dipanggil untuk melakukan pekerjaan yang ditugaskan. Analogi yang umum untuk hal ini adalah suatu hirarki suatu manajemen. Seorang boss (fungsi pemanggil atau pemanggil) meminta seorang pekerja (fungsi terpanggil) untuk melakukan suatu pekerjaan dan melaporkan kembali ketika pekerjaan selesai dilakukan (Gambar 4.1). Sebagai contoh, sebuah fungsi yang akan menampilkan informasi di layar memanggil fungsi pekerja printf untuk melakukan tugas tersebut, kemudian printf menampilkan informasi dan melaporkan kembali, atau mengembalikan hasil, kepada fungsi pemanggil ketika pekerjaan tersebut selesai dilakukan. Fungsi boss tidak mengetahui bagaimana fungsi pekerja melakukan pekerjaan yang ditugaskan. Pekerja dibolehkan untuk memanggil fungsi pekerja lainnya, dan boss tidak mengetahui hal ini. Akan Anda lihat sebentar lagi bagaimana penyembunyian detil implementasi ini merupakan praktek rekayasa perangkat lunak yanag baik. Gambar 4.1 menunjukkan fungsi main yang berkomunikasi dengan beberapa fungsi pekerja di dalam suatu hirarki. Perhatikan bahwa pekerja1 berperan sebagai sebuah fungsi boss kepada pekerja4 dan pekerja5.


Gambar 4.1 | Hirarki relasi fungsi boss/fungsi pekerja


4.3 Fungsi Pustaka Matematika
Fungsi-fungsi pustaka matematika memampukan Anda untuk melakukan beberapa kalkulasi matematik umum. Akan digunakan beberapa fungsi pustaka matematika di sini untuk mengenalkan konsep fungsi. Berikutnya dalam buku ini, akan didiskusikan juga banyak fungsi lain dalam pustaka standar C. Fungsi umumnya dipakai di dalam suatu program dengan menuliskan nama fungsi diikuti dengan sebuah kurung kiri diikuti dengan argumen fungsi (atau daftar argumen yang dipisahkan koma) yang diikuti dengan sebuah kurung kanan. Sebagai contoh, seorang programer yang ingin menghitung dan menampilkan akar kuadrat dari 900.0 akan menuliskan

printf( "%.2f", sqrt( 900.0 ) );

Ketika statemen ini dieksekusi, fungsi pustaka matematika sqrt dipanggil untuk menghitung akar kuadrat dari angka yang diapit kurung (900.0). Angka 900.0 merupakan argumen dari fungsi sqrt. Statemen tersebut akan menampilkan 30.00. Fungsi sqrt mengambil sebuah argumen bertipe double dan mengembalikan suatu hasil bertipe double. Semua fungsi di dalam pustaka matematika, yang menghasilkan nilai pecahan, mengembalikan hasil tipe data double. Perhatikan bahwa nilai double, seperti nilai float, dapat ditampilkan menggunakan spesifikasi konversi %f.

Argumen fungsi bisa berupa konstanta, variabel, atau ekspresi. Jika c1 = 13.0, d = 3.0, dan f = 4.0, maka statemen

printf( "%.2f", sqrt( c1 + d * f ) );
menghitung dan menampilkan akar kuadrat dari 13.0 + 3.0 * 4.0 = 25.0, menjadi 5.00. Beberapa fungsi pustaka matematika C disimpulkan pada Gambar 4.2. Pada gambar tersebut, variabel x dan y keduanya bertipe double.

Fungsi
Deskripsi
Contoh
sqrt(x)


exp(x)


log(x)


log10(x)



fabs(x)



ceil(x)


floor(x)


pow(x,y)


fmod(x,y)


sin(x)


cos(x)


tan(x)
akar kuadrat dari x


fungsi pemangkatan


logaritma natural dari x (basis e)


logaritma dari x (basis 10)



nilai absolut dari x



membulatkan x ke integer terkecil tidak kurang dari x

membulatkan x ke integer terbesar tidak lebih dari x

x dipangkatkan dengan y


sisa dari x/y


sinus trigonometri dari x (x dalam radian)

kosinus trigonometri dari x (x dalam radian)

tangent trigonometri dari x (x dalam radian)
sqrt(900.0) adalah 30.0
sqrt( 9.0 ) adalah 3.0

exp(1.0) adalah 2.718282
exp(2.0) adalah 7.389056

log(2.718282) adalah 1
log(7.389056) adalah 2

log10(1.0) adalah 0.0
log10(10.0) adalah 1.0
log10(100.0) adalah 2.0

fabs(13.5) adalah 13.5
fabs(0.0) adalah 0.0
fabs(-13.5) adalah 13.5

ceil(9.2) adalah 10.0
ceil(-9.8) adalah -9.0

floor(9.2) adalah 9.0
floor(-9.8) adalah -10.0

pow(2,7) adalah 128.0
pow(9,.5) adalah 3.0

fmod(13.657,2.333) adalah 1.992

sin(0.0) adalah 0.0


cos(0.0) adalah 1.0


tan(0.0) adalah 0.0

Gambar 4.2 | Beberapa fungsi pustaka matematika yang umum digunakan

4.4 Fungsi
Fungsi membantu Anda untuk memodularisasi suatu program. Semua variabel yang didefinisikan di dalam definisi fungsi adalah variabel lokal, yang hanya dikenal di dalam fungsi yang di dalamnya variabel tersebut didefinisikan. Kebanyakan fungsi memiliki daftar parameter yang menyediakan cara untuk mengkomunikasikan informasi di antara fungsi. Sebuah parameter fungsi juga merupakan variabel lokal dari fungsi tersebut.

Ada beberapa motivasi dalam memfungsionalisasi suatu program. Pendekatan divide-and-conquer membuat pengembangan program menjadi lebih mudah dikelola. Motivasi lainnya adalah pendaur-ulangan kode, menggunakan fungsi-fungsi yang sudah ada sebagai blok-blok pembangun untuk menciptakan kode baru. Pendaur-ulangan kode merupakan faktor utama dalam gerakan pemrograman berorientasi objek, seperti C++, Java, dan C# (C sharp).

4.5 Definisi Fungsi
Setiap program yang telah disajikan memuat sebuah fungsi yang dinamakan main, yang memanggil fungsi pustaka standar untuk mengerjakan tugasnya. Sekarang akan dipelajari bagaimana menulis fungsi sendiri. Perhatikan suatu program yang menggunakan fungsi kuadrat untuk menghitung dan menampilkan kuadrat dari integer dari 1 sampai 10 (Gambar 4.3).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Gambar4.3: gambar04_03.c
   Menciptakan dan menggunakan fungsi terdefinisi-pengguna */
#include <stdio.h>

int kuadrat( int y ); /* prototipe fungsi */

/* fungsi main memulai eksekusi */
int main( void )
{
  int x; /* kounter */

  /* loop 10 kali dan menghitung dan menampilkan kuadrat dari x */
  for ( x = 1; x <= 10; x++ ) {
    printf( "%d ", kuadrat( x )); /* pemanggilan fungsi */
  } /* akhir for */

  printf( "\n" );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* definisi fungsi kuadrat menghasilkan kuadrat dari parameter */
int kuadrat( int y ) /* y adalah salinan dari argumen fungsi */
{
  return y * y; /* menghasilkan kuadrat dari y sebagai int */
} /* akhir fungsi kuadrat */


1 4 9 16 25 36 49 64 81 100


Gambar 4.3 | Penggunaan suatu fungsi terdefinisi-programer

Fungsi kuadrat dipanggil pada main di dalam statemen printf (baris 14)

printf( "%d ", kuadrat( x )); /* pemanggilan fungsi */
Fungsi kuadrat menerima sebuah salinan dari nilai x di dalam parameter y (baris 22). Kemudian kuadrat menghitung y * y (baris 24). Hasilnya dilewatkan kembali kepada fungsi printf di dalam main dimana kuadrat dipanggil (baris 14), dan printf menampilkan hasilnya. Proses ini diulangi 10 kali menggunakan statemen repetisi for.

Definisi fungsi kuadrat menunjukkan bahwa kuadrat mengharapkan sebuah parameter integer y. Katakunci int sebelum nama fungsi (baris 22) mengindikasikan bahwa kuadrat menghasilkan nilai balik berupa suatu integer. Statemen return di dalam kuadrat melewatkan kembali hasil perhitungan kepada fungsi pemanggil.

Baris 5

int kuadrat( int y ); /* prototipe fungsi */

merupakan suatu prototipe fungsi. Katakunci int yang diapit kurung menginformasikan kompiler bahwa kuadrat berharap untuk menerima suatu nilai integer dari pemanggil. Katakunci int di sebelah kiri nama fungsi menginformasikan kompiler bahwa kuadrat menghasilkan nilai balik, berupa suatu integer, yang diberikan kepada pemanggil. Kompiler merujuk kepada prototipe fungsi untuk memeriksa pemanggilan terhadap kuadrat (baris 14) apakah memuat tipe nilai balik, jumlah argumen yang tepat, tipe data argumen yang sesuai, dan apakah argumen memiliki urutan yang benar. Prototipe fungsi didiskusikan secara detil pada Bagian 4.6.

Format suatu definisi fungsi adalah

tipe-nilai-balik  nama-fungsi( daftar-parameter )
{
   definisi-definisi
   statemen-statemen
}

nama-fungsi adalah sembarang pengenal yang sah. tipe-nilai-balik adalah tipe data dari hasil yang dikembalikan kepada pemanggil. tipe-nilai-balik void mengindikasikan bahwa sebuah fungsi tidak menghasilkan suatu nilai. Semuanya bila digabungkan, tipe-nilai-balik, nama-fungsi, dan daftar-parameter disebut pula dengan header fungsi.

daftar-parameter merupakan suatu daftar parameter yang dipisahkan dengan koma yang menspesifikasi parameter-parameter yang diterima oleh fungsi ketika dipanggil. Jika sebuah fungsi tidak menerima sembarang nilai, daftar-parameter berupa void. Suatu tipe data harus dicantumkan secara eksplisit untuk setiap parameter.

definisi-definisi dan statemen-statemen yang diapit kurung kurawal membentuk tubuh fungsi. Tubuh fungsi dikenal pula dengan blok. Variabel dapat di dideklarasikan di dalam sembarang blok, dan blok dapat dibuat menjadi bersarang. Fungsi tidak dapat didefinisikan di dalam fungsi lain.

Ada tiga cara untuk mengembalikan kendali program dari suatu fungsi terpanggil ke titik dimana fungsi dipanggil. Jika fungsi tidak menghasilkan suatu nilai, kendali program dikembalikan ketika kurung kurawal dari fungsi terpanggil dicapai, atau dengan mengeksekusi statemen
return;

Jika fungsi menghasilkan suatu nilai balik, statemen

return ekspresi;

menghasilkan nilai balik kepada pemanggil berupa nilai dari ekspresi.

Fungsi maksimum
Contoh kedua berikut menggunakan suatu fungsi maksimum yang didefinisikan sendiri untuk menentukan dan menghasilkan nilai balik berupa integer terbesar dari tiga integer (Gambar 4.4). Ketiga integer dientrikan dengan scanf (baris 15). Berikutnya, ketiga integer tersebut dilewatkan kepada maksimum (baris 19), yang menentukan integer terbesar. Nilai ini dikembalikan kepada main melalui statemen return di dalam maksimum (baris 37). Nilai balik yang dikembalikan kemudian ditampilkan di dalam statemen printf (baris 19).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* Gambar 4.4: gambar04_04.c
   Mencari nilai maksimum dari tiga integer */
#include <stdio.h>

int maksimum( int x, int y, int z ); /* prototipe fungsi */

/* fungsi main memulai eksekusi */
int main( void )
{
  int angka1; /* integer pertama */
  int angka2; /* integer kedua */
  int angka3; /* integer ketiga */

  printf( "Masukkan tiga integer: " );
  scanf( "%d%d%d", &angka1, &angka2, &angka3 );

  /* angka1, angka12 dan angka3 adalah argumen
     pada pemanggilan fungsi maksimum */
  printf( "Nilai maksimum : %d\n", maksimum( angka1, angka2, angka3 ));
  return 0; /* indikasi terminasi sukses */
} /* akhir dari main */

/* Definisi fungsi maksimum */
/* x, y dan z adalah parameter */
int maksimum( int x, int y, int z )
{
  int maks = x; /* diasumsikan x adalah terbesar */
 
  if ( y > maks ) { /* jika y lebih besar dari maks, tugaskan y kepada maks */
    maks = y;
  } /* akhir if */

  if ( z > maks ) { /* jika z lebih besar dari maks, tugaskan z kepada maks */
    maks = z;
  } /* akhir if */

  return maks; /* maks adalah nilai terbesar */
} /* akhir fungsi maksimum */


Masukkan tiga integer: 22 85 17
Nilai maksimum : 85


Masukkan tiga integer: 85 22 17
Nilai maksimum : 85


Masukkan tiga integer: 22 17 85
Nilai maksimum : 85

Gambar 4.4 | Pencarian nilai maksimum di antara tiga integer

4.6 Prototipe Fungsi
Salah satu fitur yang penting dalam C adalah prototipe fungsi. Fitur ini dipinjam oleh komite standar C dari para pengembang C++. Prototipe fungsi memberitahu kompiler tentang tipe data nilai balik fungsi, jumlah parameter yang diterima fungsi, tipe data tiap parameter, dan urutan parameter. Kompiler menggunakan prototipe fungsi untuk memvalidasi pemanggilan fungsi.

Versi awal C tidak melakukan jenis pemeriksaan seperti ini, jadi sangat dimungkinkan bahwa pemanggilan fungsi berakhir dengan error. Pemanggilan semacam itu bisa berakibat error yang fatal atau error yang tidak fatal seperti error logika. Prototipe fungsi mengatasi masalah seperti ini.

Prototipe fungsi untuk maksimum pada Gambar 4.4 (baris 5) adalah

int maksimum( int x, int y, int z ); /* prototipe fungsi */

Prototipe fungsi ini menyatakan bahwa maksimum mengambil tiga argumen bertipe int dan menghasilkan nilai balik bertipe int. Perhatikan bahwa prototipe fungsi sama seperti baris pertama pada definisi fungsi maksimum.

Suatu pemanggilan fungsi yang tidak cocok dengan prototipe fungsi menyebabkan error kompilasi. Error tersebut dibangkitkan jika prototipe fungsi dan definisi fungsi tidak sesuai. Sebagai contoh, pada Gambar 4.4, jika prototipe fungsi dituliskan menjadi

void maksimum( int x, int y, int z );

maka kompiler akan membangkitkan suatu error karena tipe data nilai balik void di dalam protipe fungsi berbeda dari tipe nilai balik int pada header fungsi.

Fitur penting lainnya dari prototipe fungsi adalah pemaksaan argumen, yaitu memaksa argumen menjadi tipe yang sesuai. Sebagai contoh, fungsi pustaka matematika sqrt dapat dipanggil dengan suatu argumen integer meskipun prototipe fungsi di dalam <math.h> menspesifikasi suatu argumen double, dan fungsi tersebut masih bisa bekerja dengan benar. Statemen

printf( "%.3f\n", sqrt( 4 ) );

secara benar mengevaluasi sqrt(4), dan menampilkan nilai 2.000. Prototipe fungsi menyebabkan kompiler untuk mengkonversi nilai integer 4 menjadi nilai double 4.0 sebelum nilai tersebut dilewatkan kepada sqrt. Secara umum, nilai argumen yang tidak persis sama dengan tipe parameter di dalam prototipe fungsi akan dikonversi menjadi tipe yang sesuai sebelum fungsi tersebut dipangil. Konversi ini dapat menyebabkan hasil yang tidak tepat jika aturan promosi C tidak diikuti. Aturan promosi mengatur bagaimana suatu tipe dapat dikonversi menjadi tipe lain tanpa harus kehilangan data. Pada contoh sqrt tersebut, sebuah int secara otomatis dikonversi menjadi sebuah double tanpa terjadi pengubahan nilai. Namun, konversi sebuah double menjadi int akan menyebabkan pemotongan bagian pecahan (fraksional) dari nilai double. Konversi tipe integer yang lebih besar menjadi tipe integer yang lebih kecil (misalnya, long menjadi short) juga dapat mengakibatkan pengubahan nilai.


Gambar 4.5 | Hirarki promosi untuk semua tipe data


Aturan promosi secara otomatis diterapkan terhadap ekspresi yang memuat nilai dari dua atau lebih tipe data (yang dikenal juga sebagai ekspresi tipe-gabungan). Tipe data dari setiap nilai di dalam suatu ekspresi tipe-gabungan secara otomatis dipromosikan menjadi tipe tertinggi di dalam ekspresi tersebut (sebenarnya sebuah versi temporer dari setiap nilai yang diciptakan dan digunakan dalam ekspresi, dimana nilai-nilai awal tetap tidak berubah). Gambar 4.5 mencantumkan semua tipe data dengan urutan dari tipe tertinggi ke tipe terendah.

Konversi nilai menjadi tipe lebih rendah biasanya menghasilkan nilai yang tidak tepat. Oleh karena itu, sebuah nilai dapat dikonversi menjadi tipe yang lebih rendah hanya melalui penugasan nilai tersebut secara eksplisit kepada suatu variabel bertipe rendah, atau dengan menggunakan operator cast. Nilai argumen fungsi dikonversi menjadi tipe parameter di dalam suatu prototipe fungsi, yang sama halnya dengan menugaskan nilai tersebut secara langsung kapada variabel di dalam prototipe fungsi. Jika fungsi kuadrat yang menggunakan sebuah parameter integer (Gambar 4.3) dipanggil dengan sebuah argumen titik-mengambang (misalnya, double atau float), maka argumen tersebut dikonversi menjadi int (tipe yang lebih rendah), dan kuadrat akan menghasilkan hasil yang tidak tepat. Sebagai contoh, kuadrat(4.5) akan menghasilkan 16, bukan 20.25.

4.7 Tumpukan Pemanggilan Fungsi dan Rekaman Aktivasi
Untuk memahami bagaimana C melakukan pemanggilan fungsi, Anda terlebih dahulu perlu mempelajari struktur data, yang dikenal sebagai tumpukan (stack). Anda dapat menganalogikan tumpukan sebagai tumpukan piring. Ketika sebuah piring diletakkan pada tumpukan, normalnya piring tersebut ditempatkan di atas tumpukan (yang dikenal juga sebagai operasi push). Sama halnya, ketika sebuah piring diambil dari tumpukan, normalnya piring tersebut diambil dari atas tumpukan (yang dikenal juga dengan operasi pop). Tumpukan dikenal sebagai struktur data LIFO (last-in, first-out), dimana item terakhir yang ditempatkan (disisipkan) pada tumpukan merupakan item pertama yang diambil (dibuang) dari tumpukan.

Ketika program memanggil suatu fungsi, fungsi terpanggil harus mengetahui bagaimana kembali (mengembalikan nilai balik, jika ada) ke pemanggil, jadi alamat kembali dari fungsi pemanggil ditempatkan pada tumpukan eksekusi program (dikenal pula sebagai tumpukan pemanggilan fungsi). Jika sederet pemanggilan fungsi dilakukan, alamat kembali yang berurutan ditempatkan pada tumpukan secara LIFO, sehingga setiap fungsi dapat kembali ke pemanggilnya.

Tumpukan eksekusi program juga memuat memori untuk variabel lokal yang digunakan di dalam setiap pemanggilan fungsi. Data ini, disimpan sebagai suatu potongan tumpukan eksekusi program, yang dikenal sebagai rekaman aktivasi atau rekaman frame dari pemanggilan fungsi. Ketika suatu pemanggilan fungsi dilakukan, rekaman aktivasi untuk pemanggilan fungsi tersebut ditempatkan pada tumpukan eksekusi program. Ketika fungsi kembali kepada pemanggilnya, rekaman aktivasi untuk fungsi ini dihapus atau dibuang dari tumpukan dan variabel lokalnya tidak lagi dikenali oleh program.

4.8 Header
Setiap pustaka standar memiliki header yang memuat prototipe fungsi untuk semua fungsi yang ada di dalam pustaka tersebut dan definisi atas berbagai tipe data dan konstanta yang dibutuhkan untuk semua fungsi tersebut. Gambar 4.6 mencantumkan secara alfabetikal beberapa header pustaka standar. Istilah “macros” yang digunakan beberapa kali pada Gambar 4.6 akan didiskusikan secara detil pada Bab 12.

Anda dapat menciptakan header sendiri. Header yang didefinisikan sendiri juga harus menggunakan ekstensi nama file. Header tersebut dapat disertakan menggunakan direktif preprosesor #include. Sebagai contoh, jika prototipe dari fungsi kuadrat ditempatkan di dalam header kuadrat.h, maka  Anda menyertakan header tersebut di dalam program Anda menggunakan direktif yang berada di atas program:

#include "kuadrat.h"

Fungsi
Deskripsi
<assert.h>


<ctype.h>



<errno.h>

<float.h>

<limits.h>

<locale.h>



<math.h>

<setjmp.h>


<signal.h>


<stdarg.h>


<stddef.h>


<stdio.h>


<stdlib.h>



<string.h>

<time.h>

Memuat macro dan informasi untuk membantu melakukan debugging program.

Memuat prototipe fungsi untuk fungsi-fungsi yang menguji karakter dan untuk fungsi-fungsi yang dapat dipakai untuk mengkonversi huruf kecil menjadi huruf besar dan sebaliknya.

Mendefinisikan macro yang berguna untuk melaporkan kesalahan.

Memuat ukuran titik-mengambang dari sistem.

Memuat ukuran integral suatu sistem.

Memuat prototipe fungsi dan informasi lainnya yang memampukan suatu program untuk dimodifikasi pada sistem tertentu, seperti tanggal, jam, dan lainnya.

Memuat prototipe fungsi untuk fungsi-fungsi pustaka matematika.

Memuat prototipe fungsi untuk fungsi yang melakukan bypassing pemanggilan fungsi dan runtun pengembalian.

Memuat prototipe fungsi dan macros untuk menangani berbagai kondisi yang timbul selama eksekusi program.

Mendefinisikan macro untuk menangani daftar argumen suatu fungsi yang memiliki jumlah dan tipe yang tidak diketahui.

Memuat definisi-definisi tipe yang digunakan C untuk melakukan perhitungan.

Memuat prototipe fungsi untuk fungsi-fungsi pustaka masukan/keluaran, dan informasi yang digunakan.

Memuat prototipe fungsi untuk konversi angka menjadi teks dan teks menjadi angka, alokasi memori, bilangan acak, dan fungsi utilitas lainnya.

Memuat prototipe fungsi untuk fungsi-fungsi pemrosesan string.

Memuat prototipe fungsi dan tipe untuk memanipulasi waktu dan tanggal.

Gambar 4.6 | Beberapa header pustaka standar

4.9 Pemanggilan Fungsi Dengan Nilai dan Dengan Referensi
Ada dua cara untuk memanggil fungsi dalam banyak bahasa pemrograman, pemanggilan-dengan-nilai dan pemanggilan-dengan-referensi. Ketika argumen dilewatkan dengan nilai, nilai argumen disalin dan dilewatkan kepada fungsi terpanggil. Perubahan terhadap salinan tersebut tidak mempengaruhi nilai variabel asli di dalam pemanggil. Ketika argumen dilewatkan dengan referensi, pemanggil membolehkan fungsi terpanggil untuk memodifikasi nilai variabel asli.

Pemanggilan-dengan-nilai harus digunakan ketika fungsi terpanggil tidak perlu memodifikasi nilai dari variabel asli pemanggil. Hal ini mencegah efek samping yang tak sengaja dilakukan (modifikasi variabel). Pemanggilan-dengan-referensi harus digunakan hanya dengan fungsi terpanggil yang dapat dipercaya untuk memodifikasi variabel asli.

Dalam C, semua pemanggilan dilakukan dengan nilai. Seperti yang akan Anda lihat pada Bab 6, adalah hal yang mungkin untuk mensimulasikan pemanggilan-dengan-referensi dengan menggunakan operator alamat dan operator indireksi. Pada Bab 5, akan Anda lihat bahwa array secara otomatis dilewatkan dengan referensi.

4.10 Pembangkitan Bilangan Acak
Akan dikembangkan suatu program game sederhana yang memuat banyak fungsi. Program menggunakan beberapa struktur kendali yang telah dipelajari. Elemen peluang yang dipakai dalam aplikasi komputer menggunakan fungsi pustaka standar C rand dari header <stdlib.h>. Perhatikan statemen berikut:

i = rand();

Fungsi rand membangkitkan integer antara 0 dan RAND_MAX (suatu konstanta simbolik yang didefinisikan dalam header <stdlib.h>). C standar menyatakan bahwa nilai RAND_MAX sedikitnya bernilai 32767, yang merupakan nilai maksimum untuk integer dua-byte (16 bit). Program pada bagian ini diuji pada sistem C dengan nilai maksimum 32767 untuk RAND_MAX. Jika rand benar-benar menghasilkan integer secara acak, maka setiap angka antara 0 dan RAND_MAX memiliki probabilitas yang sama.

Rentang nilai yang dihasilkan secara langsung menggunakan rand seringkali berbeda dari apa yang dibutuhkan pada aplikasi tertentu. Sebagai contoh, suatu program yang mensimulasikan pelemparan koin hanya memerlukan 9 untuk “kepala” dan 1 untuk “ekor”. Program pelemparan dadu yang mensimulasikan pelemparan dadu enam-sisi hanya memerlukan integer acak dari 1 sampai 6.

Pelemparan Dadu Enam-Sisi
Untuk mendemonstrasikan rand, akan dikembangkan suatu program untuk mensimulasikan 20 kali pelemparan suatu dadu enam-sisi dan menampilkan nilai setiap lemparan. Prototipe fungsi untuk rand berada dalam <stdlib.h>. Akan digunakan operator sisa (%) sebagai berikut

rand() % 6

untuk menghasilkan integer dalam rentang 0 sampai 5. Ini disebut dengan penskalaan. Angka 6 dikatakan sebagai faktor penskala. Rentang angka yang dihasilkan kemudian digeser dengan menambahkan 1 pada  hasil sebelumnya. Keluaran pada Gambar 4.7 memastikan bahwa hasil berada dalam rentang 1 sampai 6.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Gambar 4.7: gambar04_07.c
   Menggeser integer terskala dengan 1 + rand() % 6 */
#include <stdio.h>
#include <stdlib.h>

/* fungsi main memulai eksekusi program */
int main( void )
{
  int i; /* kounter */

  /* loop 20 kali */
  for ( i = 1; i <= 20; i++ ) {

    /* memilih angka acak dari 1 sampai 6 dan menampilkannya */
    printf( "%10d", 1 + ( rand() % 6 ));

    /* jika kounter dapat dibagi 5, mulai garis baru */
    if ( i % 5 == 0 ) {
      printf( "\n" );
    } /* akhir dari if */
  } /* akhir dari for */

  return 0; /* indikasi terminasi sukses */
} /* akhir main */


         6         6         5         5         6
         5         1         1         5         3
         6         6         2         4         2
         6         2         3         4         1

Gambar 4.7 | Menggeser dan menskalakan integer menggunakan 1 + rand() % 6

Pelemparan Dadu Enam-Sisi Sebanyak 6000 Kali
Untuk menunjukkan bahwa semua angka acak yang dibangkitkan memiliki peluang yang (mendekati) sama, berikut akan disimulasikan 6000 kali pelemparan dadu pada program Gambar 4.8. Setiap integer dari 1 sampai 6 harus muncul berkisar 1000 kali. Seperti yang ditampilkan pada keluaran program, simulasi pelemparan dadu enam-sisi dilakukan dengan menskalakan dan menggeser fungsi rand. Tidak diperlukan kasus default di dalam statemen switch. Perhatikan pula kegunaan penspesifikasi konversi %s untuk menampilkan string karakter “Muka” dan “Frekuensi” sebagai kepala kolom (baris 53). Setelah Array dipelajari pada Bab 5, akan ditunjukkan bagaimana mengganti statemen switch ini dengan satu-baris statemen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* Gambar 4.8: gambar04_08.c
   Pelemparan dadu enam-sisi sebanyak 6000 kali */
#include <stdio.h>
#include <stdlib.h>

/* fungsi main memulai eksekusi program */
int main( void )
{
  int frekuensi1 = 0; /* kounter 1 */
  int frekuensi2 = 0; /* kounter 2 */
  int frekuensi3 = 0; /* kounter 3 */
  int frekuensi4 = 0; /* kounter 4 */
  int frekuensi5 = 0; /* kounter 5 */
  int frekuensi6 = 0; /* kounter 6 */

  int pelemparan; /* kounter pelemparan, nilai 1 sampai 6000 */
  int muka; /* merepresentasikan satu kali pelemparan dadu, nilai 1 sampai 6 */

  /* loop 6000 kali dan menyimpulkan hasil */
  for ( pelemparan = 1; pelemparan <= 6000; pelemparan++ ) {
    muka = 1 + rand() % 6; /* angka acak dari 1 sampai 6 */

    /* menentukan nilai muka dan menginkremen kounter yang sesuai */
    switch ( muka ) {

      case 1: /* muka 1 */
        ++frekuensi1;
        break;

      case 2: /* muka 2 */
        ++frekuensi2;
        break;

      case 3: /* muka 3 */
        ++frekuensi3;
        break;

      case 4: /* muka 4 */
        ++frekuensi4;
        break;

      case 5: /* muka 5 */
        ++frekuensi5;
        break;

      case 6: /* muka 6 */
        ++frekuensi6;
        break; /* opsional */
    } /* akhir dari switch */
  } /* akhir dari for */

  /* menampilkan hasil dalam format tabular */
  printf( "%s%13s\n", "Muka", "Frekuensi" );
  printf( " 1%15d\n", frekuensi1 );
  printf( " 2%15d\n", frekuensi2 );
  printf( " 3%15d\n", frekuensi3 );
  printf( " 4%15d\n", frekuensi4 );
  printf( " 5%15d\n", frekuensi5 );
  printf( " 6%15d\n", frekuensi6 );
  return 0; /* indikasi terminasi sukses */
} /* akhir dari main */


Muka    Frekuensi
 1           1003
 2           1017
 3            983
 4            994
 5           1004
 6            999

Gambar 4.8 | Pelemparan dadu enam-sisi sebanyak 6000 kali

Mengacak Pembangkit Bilangan Acak
Eksekusi kembali terhadap program pada Gambar 4.7 menghasilkan


         6         6         5         5         6
         5         1         1         5         3
         6         6         2         4         2
         6         2         3         4         1

Perhatikan bahwa runtun nilai yang sama persis yang ditampilkan. Bagaimana hal ini dikatakan angka acak? ironisnya, pengulangan ini merupakan karakteristik penting dari fungsi rand. Ketika mendebug suatu program, perulangan ini penting untuk membuktikan bahwa koreksi pada suatu program berjalan dengan benar.

Fungsi rand sebenarnya membangkitkan bilangan semi-acak (pseudorandom). Pemanggilan rand secara berulang menghasilkan runtun angka yang terlihat seperti acak. Tetapi, runtun tersebut berulang setiap kali program dieksekusi. Begitu suatu program didebug, program tersebut dapat dikondisikan untuk menghasilkan runtun acak yang berbeda pada tiap eksekusinya. Ini dikatakan dengan pengacakan atau randomizing dan dilakukan menggunakan fungsi pustaka standar srand. Fungsi srand memerlukan sebuah argumen integer unsigned yang akan menghasilkan runtun acak yang berbeda pada tiap eksekusinya.

Akan didemonstrasikan srand pada Gambar 4.9. Pada program, digunakan tipe data unsigned, yang merupakan singkatan dari unsigned int. Sebuah int disimpan sedikitnya dua byte di dalam memori dan bisa bernilai positif atau negatif. Variabel bertipe unsigned juga dapat disimpan sedikitnya dua-byte memori. Tipe data unsigned int dua-byte hanya bisa memuat nilai positif dalam rentang dari 0 sampai 65535. Tipe data empat-byte unsigned int hanya bisa memuat nilai positif dalam rentang dari 0 sampai 4294967295. Fungsi srand mengambil sebuah nilai unsigned sebagai argumen. Penspesifikasi konversi %u digunakan untuk membaca nilai unsigned dengan scanf. Prototipe fungsi untuk srand berada di dalam <stdlib.h>.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* Gambar 4.9: gambar04_09.c
   Pengacakan program pelemparan-dadu */
#include <stdlib.h>
#include <stdio.h>

/* fungsi main memulai eksekusi program */
int main( void )
{
  int i; /* kounter */
  unsigned benih; /* angka yang dipakai sebagai benih pembangkit acak */

  printf( "Masukkan benih: " );
  scanf( "%u", &benih ); /* perhatikan %u untuk unsigned */

  srand( benih ); /* benih dari pembangkit angka acak */

  /* loop 10 kali */
  for ( i = 1; i <= 10; i++ ) {

    /* pilih suatu angka acak dari 1 dan 6 dan menampilkannya */
    printf( "%10d", 1 + ( rand() % 6 ) );

    /* jika kounter dapat dibagi 5, maka mulai garis baru */
    if ( i % 5 == 0 ) {
      printf( "\n" );
    } /* akhir if */
  } /* akhir for */

  return 0; /* indikasi terminasi sukses */
 } /* akhir main */


Masukkan benih: 67
         6         1         4         6         2
         1         6         1         6         4



Masukkan benih: 867
         2         4         6         1         6
         1         1         3         6         2


Masukkan benih: 67
         6         1         4         6         2
         1         6         1         6         4

Gambar 4.9 | Pengacakan program pelemparan dadu enam-sisi


Akan dijalankan program tersebut beberapa kali dan diamati hasilnya. Perhatikan bahwa runtun angka acak yang berbeda dihasilkan setiap kali dijalankan dengan benih yang berbeda.

Untuk mengacak tanpa perlu menyuplai benih setiap kali, gunakan statemen seperti

srand( time( NULL ) );

Ini menyebabkan komputer untuk membaca waktu dalam mendapatkan nilai untuk benih secara otomatis. Fungsi time menghasilkan nilai balik berupa jumlah detik (setelah tengah malam pada 1 Januari 1970). Nilai ini dikonversi menjadi sebuah integer tak-bertanda dan digunakan sebagai benih untuk pembangkit bilangan acak. Fungsi time mengambil NULL sebagai argumen (time mampu menyediakan kapabilitas berupa string untuk merepresentasikan sebuah nilai yang dijadikan nilai balik; NULL menon-aktifkan kapabilitas ini). Prototipe fungsi time disediakan di dalam <time.h>.

Generalisasi Penskalaan dan Penggeseran Bilangan Acak
Nilai-nilai yang dihasilkan secara langsung dari rand selalui berada dalam rentang:

0  rand()  RAND_MAX

Seperti Anda ketahui, statemen berikut mensimulasikan pelemparan dadu enam-sisi:

muka = 1 + rand() % 6;

Statemen ini selalu menugaskan nilai integer (secara acak) kepada variabel muka dalam rentang 1  muka  6. Lebar rentang ini (jumlah integer berurutan di dalam rentang) adalah 6 dan angka awal dalam rentang adalah 1. Hasil ini dapat digeneralisir sebagai berikut

n = a + rand() % b;

dimana a adalah nilai penggeser (yang sama dengan angka pertama di dalam rentang yang diinginkan) dan b adalah faktor penskala (yang sama dengan lebar rentang yang diinginkan). 

4.11 Contoh: Permainan Peluang
Salah satu permainan (game) peluang yang paling populer dikenal sebagai “craps”, yang dimainkan di kasino di seluruh dunia. Aturan permainan ini adalah:

Seorang pemain melempar dua dadu. Setiap dadu mempunyai enam muka. Keenam muka ini memuat titik bundar 1, 2, 3, 4, 5, dan 6. Setelah dadu berhenti, jumlah titik-bundar pada dua muka yang menghadap ke atas dijumlahkan. Jika penjumlahan sebesar 7 atau 11 pada pelemparan pertama, pemain menang. Jika penjumlahannya adalah 2, 3, atau 12 pada pelemparan pertama (disebut dengan “craps”), maka pemain kalah. Jika penjumlahannya adalah 4, 5, 6, 8, 9, atau 10 pada pelemparan pertama, maka penjumlahan tersebut menjadi poin untuk pemain. Untuk memenangkan permainan, Anda harus terus melemparkan dadu sampai Anda “mencetak poin”. Pemain akan kalah bila mendapatkan nilai lemparan 7 sebelum mencetak poin.

Gambar 4.10 mensimulasikan permainan craps dan Gambar 4.11 menunjukkan beberapa contoh keluaran program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* Gambar 4.10: gambar04_10.c
   Permainan Craps */
#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* memuat prototipe fungsi time */

/* enumerasi merepresentasikan status permainan */
enum Status { LANJUT, MENANG, KALAH };

int lemparDadu( void ); /* prototipe fungsi */

/* fungsi main memulai eksekusi program */
int main( void )
{
  int jum; /* jumlah dadu yang dilempar */
  int poinKu; /* poin yang didapatkan */

  enum Status gameStatus; /* dapat memuat LANJUT, MENANG, atau KALAH */

  /* mengacak pembangkit bilangan acak menggunakan waktu sekarang */
  srand( time( NULL ) );

  jum = lemparDadu(); /* lemparan pertama dadu */

  /* menentukan status game berdasarkan pada jumlah dadu */
  switch( jum ) {

    /* menang pada pelemparan pertama */
    case 7:
    case 11:
      gameStatus = MENANG;
      break;

    /* kalah pada pelemparan pertama */
    case 2:
    case 3:
    case 12:
      gameStatus = KALAH;
      break;

    /* mengingat poin */
    default:
      gameStatus = LANJUT;
      poinKu = jum;
      printf( "Poin adalah %d\n", poinKu );
      break; /* opsional */
  } /* end switch */

  /* jika game belum selesai */
  while ( gameStatus == LANJUT ) {
    jum = lemparDadu(); /* melempar dadu kembali */

    /* menentukan status game */
    if ( jum == poinKu ) { /* menang dengan mencetak poin */
      gameStatus = MENANG; /* game selesai, pemain menang */
    } /* akhir if */
    else {
      if ( jum == 7 ) { /* kalah karena pelemparan 7 */
        gameStatus = KALAH; /* game selesai, pemain kalah */
      } /* akhir if */
    } /* akhir else */
  } /* akhir while */

 /* menampilkan pesan menang atau kalah */
 if ( gameStatus == MENANG ) { /* apakah pemain menang? */
   printf( "Pemain menang\n" );
 } /* akhir if */
 else { /* pemain kalah */
   printf( "Pemain kalah\n" );
 } /* akhir else */

 return 0; /* indikasi terminasi sukses */
 } /* akhir main */

/* melempar dadu, menghitung dan menampilkan hasil */
int lemparDadu( void )
{
  int dadu1; /* dadu pertama */
  int dadu2; /* dadu kedua */
  int jumDadu; /* jumlah dadu */

  dadu1 = 1 + ( rand() % 6 ); /* memilih nilai dadu1 */
  dadu2 = 1 + ( rand() % 6 ); /* memilih nilai dadu2 */
  jumDadu = dadu1 + dadu2; /* jumlah dadu1 dan dadu2 */

  /* menampilkan hasil dari pelemparan ini */
  printf( "Pemain melemparkan %d + %d = %d\n", dadu1, dadu2, jumDadu );
  return jumDadu; /* menghasilkan jumlah dadu */
} /* akhir funsi lemparDadu */

Gambar 4.10 | Program untuk mensimulasikan permainan craps


Pemain melemparkan 3 + 1 = 4
Poin adalah 4
Pemain melemparkan 3 + 6 = 9
Pemain melemparkan 2 + 5 = 7
Pemain kalah





Pemain melemparkan 2 + 5 = 7
Pemain menang


Pemain melemparkan 3 + 2 = 5
Poin adalah 5
Pemain melemparkan 3 + 2 = 5
Pemain menang



Pemain melemparkan 3 + 1 = 4
Poin adalah 4
Pemain melemparkan 5 + 3 = 8
Pemain melemparkan 5 + 6 = 11
Pemain melemparkan 3 + 6 = 9
Pemain melemparkan 6 + 3 = 9
Pemain melemparkan 4 + 6 = 10
Pemain melemparkan 4 + 2 = 6
Pemain melemparkan 5 + 2 = 7
Pemain kalah

Gambar 4.11 | Contoh keluaran program pada Gambar 4.10

Dalam aturan game, perhatikan bahwa pemain harus melemparkan dua dadu pada pelemparan pertama, dan harus melakukan hal yang sama pada pelemparan berikutnya. Anda telah mendefinisikan suatu fungsi lemparDadu untuk melemparkan dadu dan menghitung dan menampilkan penjumlahannya. Fungsi lemparDadu didefinisikan sekali, tetapi dipanggil dari dua tempat di dalam program (baris 23 dan 51). Menariknya adalah lemparDadu tidak memerlukan argumen, seperti diindikasikan dengan void di dalam daftar parameter (baris 76). Fungsi lemparDadu mengembalikan nilai balik berupa penjumlahan dua dadu, sehingga tipe nilai balik adalah int yang diindikasikan di dalam header fungsi.

Pemain dapat menang atau kalah pada lemparan pertama, atau dapat atau menang pada lemparan berikutnya. Variabel gameStatus, yang didefinisikan menjadi tipe baru (enum Status), menyimpan status sekarang. Baris 8 menciptakan sebuah tipe yang didefinisikan sendiri yang dinamakan dengan enumerasi. Suatu enumerasi, yang diawali dengan katakunci enum, merupakan sehimpunan konstanta integer yang direpresentasikan oleh pengenal. Konstanta enumerasi kadangkala disebut pula dengan konstanta simbolik. Nilai di dalam suatu enum dimulai dari 0 dan diinkremen sebesar 1.  Pada baris 8, konstanta LANJUT memiliki nilai 0, MENANG memiliki nilai 1, dan KALAH memiliki nilai 2. Adalah hal yang memungkinkan untuk menugaskan suatu nilai integer kepada setiap pengenal di dalam enum (lihat Bab 9). Pengenal yang ada di dalam enumerasi harus unik, tetapi nilainya dapat diduplikasi.





Ketika permainan dimenangkan, baik pada lemparan pertama atau pada lemparan sesudahnya, gameStatus ditetapkan menjadi MENANG. Ketika permainan kalah, baik pada lemparan pertama atau pada lemparan sesudahnya, gameStatus ditetapkan menjadi KALAH. Sebaliknya, gameStatus ditetapkan menjadi LANJUT dan permainan berlanjut.

Setelah lemparan pertama, jika permainan selesai, statemen while (baris 50) dilompati karena gameStatus tidak LANJUT. Program berlanjut ke statemen if...else pada baris 65, yang akan menampilkan “Pemain menang” jika gameStatus adalah MENANG dan “Pemain kalah” jika sebaliknya.

Setelah pelemparan pertama, jika permainan belum selesai, maka jum akan disimpan di dalam poinKu. Eksekusi berlanjut ke statemen while (baris 50) karena gameStatus adalah LANJUT. Setiap kali melalui while, lemparDadu dipanggil untuk menghasilkan jum baru. Jika jum cocok dengan poinKu, maka gameStatus ditetapkan menjadi MENANG untuk mengindikasikan bahwa pemain menang, sedangkan jika uji pada while gagal, maka statemen if...else (baris 65) akan menampilkan “Pemain menang” dan eksekusi berhenti. Jika jum sama dengan 7 (baris 58), maka gameStatus ditetapkan menjadi KALAH untuk mengindikasikan bahwa pemain kalah, sedangkan jika uji pada while gagal, maka statemen if...else (baris 65) akan menampilkan “Pemain kalah” dan eksekusi berhenti.

Perhatikan arsitektur kendali program yang menarik. Anda telah menggunakan dua fungsi, main dan lemparDadu, statemen switch, while, if...else bersarang, dan if bersarang.

4.12 Aturan Skop
Skop suatu pengenal adalah bagian program dimana di dalamnya pengenal dapat direferensi. Sebagai contoh, ketika sebuah variabel lokal didefinisikan di dalam suatu blok, ia dapat direferensi hanya di dalam blok tersebut atau di dalam blok yang bersarang di dalam blok tersebut. Empat jenis skop pengenal adalah skop fungsi, skop file, skop blok, dan skop prototipe-fungsi.

Label (sebuah pengenal yang ditempatkan setelah titik dua seperti mulai:) adalah pengenal dengan skop fungsi. Label dapat digunakan dimana saja di dalam fungsi, tetapi tidak dapat direferensi di luar tubuh fungsi. Label digunakan di dalam statemen switch (seperti label dari case) dan di dalam statemen goto (lihat Bab 13). Label merupakan detil implementasi yang disembunyikan fungsi dari fungsi lainnya.

Pengenal yang dideklarasikan di luar sembarang fungsi disebut pula dengan skop. Pengenal semacam itu “dikenal” (dapat diakses) di dalam semua fungsi mulai dari titik dimana pengenal tersebut dideklarasikan sampai akhir dari file. Variabel global, definisi fungsi, dan prototipe fungsi yang ditempatkan di luar suatu fungsi memiliki skop file.

Pengenal yang didefinisikan di dalam sebuah blok memiliki skop blok. Skop blok berakhir pada kurung kurawal kanan dari blok. Variabel lokal yang didefinisikan di awal suatu fungsi memiliki skop blok, sama seperti parameter fungsi yang dipandang sebagai variabel lokal oleh fungsi tersebut. Sembarang blok bisa memuat definisi fungsi. Ketika blok tersebut bersarang, dan sebuah pengenal yang didefinisikan di dalam blok sebelah luar memiliki nama sama dengan pengenal yang berada di blok sebelah dalam, maka blok sebelah luar “tersembunyi” sampai blok sebelah dalam berhenti. Ini berarti bahwa ketika blok sebelah dalam dieksekusi, blok tersebut melihat nilai dari pengenal lokalnya sendiri dan bukan nilai dari pengenal (dengan nama sama) yang didefinisikan di dalam blok sebelah luar.

Pengenal dengan skop prototipe-fungsi adalah yang digunakan di dalam daftar parameter suatu prototipe fungsi. Seperti disebutkan sebelumnya, prototipe fungsi tidak memerlukan nama di dalam daftar parameter, karena hanya tipe data saja yang diperlukan. Jika sebuah nama digunakan di dalam daftar parameter suatu prototipe fungsi, kompiler akan mengabaikan nama tersebut. Pengenal yang digunakan di dalam prototipe fungsi dapat digunakan kembali dimana saja di dalam program tanpa mengalami ambiguitas.

Gambar 4.12 mendemonstrasikan isu skop dengan variabel global, variabal lokal otomatis, dan variabel lokal statis. Variabel global x didefinisikan dan diinisialisasi dengan 1 (baris 9). Variabel global ini tidak dikenal di dalam sembarang blok (atau fungsi). Di dalam main, variabel lokal x didefinisikan dan diinisialisasi dengan 5 (baris 14). Variabel ini kemudian ditampilkan untuk menunjukkan bahwa variabel global x tidak dikenali di dalam main. Berikutnya, blok baru didefinisikan di dalam main dengan variabel lokal lainnya x yang diinisialisasi dengan 7 (baris 19). Variabel ini ditampilkan untuk menunjukkan bahwa ia menyembunyikan x yang berada di blok sebelah luar dari main. Variabel x dengan nilai 7 secara otomatis dihancurkan ketika ekskusi keluar dari blok tersebut, dan variabel lokal x yang berada di blok sebelah luar dari main yang ditampilkan kembali.

Program mendefinisikan tiga fungsi yang masing-masing tidak memerlukan argumen dan tidak mengembalikan informasi apapun. Fungsi gunakanLokal mendefinisikan sebuah variabel otomatis x dan menginisialisasinya dengan 25 (baris 40). Ketika gunakanLokal dipanggil, variabel tersebut ditampilkan, diinkremen, dan ditampilkan kembali sebelum keluar dari fungsi. Setiap kali fungsi ini dipanggil, variabel otomatis x diinisialisasi-ulang dengan 25. Fungsi gunakanLokalStatis mendefinisikan sebuah variabel statis x dan menginisialisasinya dengan 50 (baris 53). Variabel lokal yang didefinisikan static mempertahankan nilainya meskipun berada di luar skopnya. Ketika gunakanLokalStatis dipanggil, x akan ditampilkan, diinkremen, dan ditampilkan kembali sebelum keluar dari fungsi. Dalam pemanggilan berikutnya terhadap fungsi ini, variabel lokal statis x akan memuat nilai 51. Fungsi gunakanGlobal tidak mendefinisikan variabel apapun. Oleh karena itu, ketika ia merujuk ke variabel x, x global (baris 9) yang digunakan. Ketika gunakanGlobal dipanggil, maka variabel global ditampilkan, dikalikan dengan 10, dan ditampilkan kembali sebelum keluar dari fungsi. Pada pemanggilan kembali atas fungsi gunakanGlobal, variabel global masih memiliki nilai termodifikasinya, 10. Terakhir, program menampilkan variabel lokal x di dalam main kembali (baris 33) untuk menunjukkan bahwa tidak ada satupun pemanggilan fungsi yang dilakukan memodifikasi nilai x karena semua fungsi tersebut memanipulasi variabel di dalam skopnya masing-masing.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/* Gambar 4.12: gambar04_12.c
   Contoh aturan skop */
#include <stdio.h>

void gunakanLokal( void ); /* prototipe fungsi */
void gunakanLokalStatis( void ); /* prototipe fungsi */
void gunakanGlobal( void ); /* prototipe fungsi */

int x = 1; /* variabel global */

/* fungsi main memulai eksekusi program */
int main( void )
{
  int x = 5; /* variabel lokal main */

  printf("x lokal di skop sebelar luar main adalah %d\n", x );

  { /* mulai skop baru */
    int x = 7; /* variabel lokal dalam skop baru */
   
    printf( "x lokal di dalam skop sebelah dalam dari main adalah %d\n", x );
  } /* akhir dari skop baru */

  printf( "x lokal di skop sebelah luar dari main adalah %d\n", x );

  gunakanLokal(); /* gunakanLokal memuat lokal otomatis x */
  gunakanLokalStatis(); /* gunakanLokalStatis memuat lokal statis x */
  gunakanGlobal(); /* gunakanGlobal menggunakan x global */
  gunakanLokal(); /* gunakanLokal menginisialisasi-ulang lokal otomatis x */
  gunakanLokalStatis(); /* lokal statis x mempertahankan nilai sebelumnya */
  gunakanGlobal(); /* x global mempertahankan nilainya */

  printf( "\nx lokal di dalam main adalah %d\n", x );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* gunakanLokal menginisialisasi-ulang variabel lokal x pada tiap pemanggilan */
void gunakanLokal( void )
{
 int x = 25; /* menginisialisasi setiap gunakanLokal dipanggil */

 printf("\nx lokal di dalam gunakanLokal adalah %d setelah memasuki gunakanLokal\n", x);
 x++;
 printf("x lokal di dalam gunakanLokal adalah %d sebelum keluar dari gunakanLokal\n", x);
 } /* akhir fungsi gunakanLokal */

/* gunakanLokalStatis menginisialisasi variabel lokal statis x hanya saat pertama
   kali fungsi dipanggil; nilai dari x disimpan di antara pemanggilan terhadap
   fungsi ini */
void gunakanLokalStatis( void )
{
  /* menginisialisasi hanya saat pertama kali gunakanLokalStatis dipanggil */
  static int x = 50;

  printf("\nlokal statis x adalah %d pada saat memasuki gunakanLokalStatis\n", x);
  x++;
  printf("lokal statis x adalah %d pada saat keluar dari gunakanLokalStatis\n", x);
} /* akhir dari fungsi gunakanLokalStatis */

/*fungsi  gunakanGlobal memodifikasi variabel global x selama tiap pemanggilan*/
void gunakanGlobal( void )
{
  printf("\nglobal x adalah %d pada saat memasuki gunakanGlobal\n", x);
  x *= 10;
  printf("global x adalah %d pada saat keluar dari gunakanGlobal\n", x);
} /* akhir dari fungsi gunakanGlobal */


x lokal di skop sebelar luar main adalah 5
x lokal di dalam skop sebelah dalam dari main adalah 7
x lokal di skop sebelah luar dari main adalah 5

x lokal di dalam gunakanLokal adalah 25 setelah memasuki gunakanLokal
x lokal di dalam gunakanLokal adalah 26 sebelum keluar dari gunakanLokal

lokal statis x adalah 50 pada saat memasuki gunakanLokalStatis
lokal statis x adalah 51 pada saat keluar dari gunakanLokalStatis

global x adalah 1 pada saat memasuki gunakanGlobal
global x adalah 10 pada saat keluar dari gunakanGlobal

x lokal di dalam gunakanLokal adalah 25 setelah memasuki gunakanLokal
x lokal di dalam gunakanLokal adalah 26 sebelum keluar dari gunakanLokal

lokal statis x adalah 51 pada saat memasuki gunakanLokalStatis
lokal statis x adalah 52 pada saat keluar dari gunakanLokalStatis

global x adalah 10 pada saat memasuki gunakanGlobal
global x adalah 100 pada saat keluar dari gunakanGlobal

x lokal di dalam main adalah 5

Gambar 4.12 | Program untuk mendemonstrasikan aturan skop

4.13 Rekursi
Faktorial atas suatu integer tak-negatif n, ditulis n! (dan diucapkan “n faktorial”), adalah perkalian dari

n · (n –1) · (n – 2) · … · 1


dengan 1! sama dengan 1, dan 0! didefinisikan menjadi 1. Sebagai contoh, 5! adalah perkalian dari 5 * 4 * 3 * 2 * 1, yang bernilai sama dengan 120.

Faktorial atas sebuah integer, angka, yang lebih besar dari atau sama dengan 0, dapat dihitung secara iteratif (tak-rekursif) menggunakan statemen for sebagai berikut:

faktorial = 1;
for ( kounter = angka; kounter >= 1; kounter-- )
  faktorial *= kounter;

Definisi rekursif dari fungsi faktorial didapatkan dari relasi berikut:

n! = n · (n – 1)!

Sebagai contoh, 5! sama dengan 5 * 4! seperti ditunjukkan berikut:

5! = 5 · 4 · 3 · 2 · 1
5! = 5 · (4 · 3 · 2 · 1)
5! = 5 · (4!)

Evaluasi terhadap 5! akan berlangsung seperti pada Gambar 4.13. Gambar 4.13a menunjukkan bagaimana pemanggilan rekursif dilakukan sampai 1!, yang menghentikan rekursi. Gambar 4.13b menunjukkan nilai-nilai yang dijadikan nilai balik dari setiap pemanggilan rekursif kepada pemanggilnya.


Gambar 4.13 | Evaluasi rekursif dari 5!

Gambar 4.14 menggunakan rekursi untuk menghitung dan menampilkan faktorial integer dari 0 sampai 10. Fungsi faktorial rekursif pertama-tama menguji apakah kondisi penghenti bernilai true, yaitu apakah jumlah kurang dari atau sama dengan 1. Jika jumlah kurang dari atau sama dengan 1, maka faktorial akan menghasilkan nilai balik 1, dan tidak perlu rekursi lebih lanjut dan program berhenti. Jika jumlah lebih besar dari 1, maka

return jumlah * faktorial( angka - 1 );

mengekspresikan permasalahan sebagai perkalian dari angka dengan suatu pemanggilan rekursif terhadap faktorial(angka – 1). Pemanggilan terhadap faktorial(angka – 1) sedikit lebih sederhana dari perhitungan awal faktorial(angka).

Fungsi faktorial (baris 22) dideklarasikan untuk menerima suatu parameter bertipe long dan mengembalikan nilai balik bertipe long. Tipe data long merupakan kependekan dari long int. Standar C menspesifikasi bahwa variabel bertipe long int disimpan sedikitnya pada 4 byte memori, jadi dapat menampung nilai maksimum sebesar +2147483647. Seperti terlihat pada Gambar 4.14, nilai-nilai faktorial menjadi besar dengan cepat. Alasan dipilihnya tipe data long adalah agar program dapat menghitung faktorial yang lebih besar dari 7! pada komputer. Penspesifikasi konversi %ld digunakan untuk menampilkan nilai long.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* Gambar 4.14: gambar04_14.c
   Fungsi faktorial rekursif */
#include <stdio.h>

long faktorial( long angka ); /* prototipe fungsi */

/* fungsi main memulai eksekusi */
int main( void )
{
  int i; /* kounter */

  /* loop 11 kali; selama tiap iterasi, menghitung
     faktorial( i ) dan menampilkan hasilnya */
  for ( i = 0; i <= 10; i++ ) {
    printf( "%2d! = %ld\n", i, faktorial( i ));
  } /* akhir for */

  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* definisi rekursif atas fungsi faktorial */
long faktorial( long angka )
{
  /* kasus basis */
  if ( angka <= 1 ) {
    return 1;
  } /* akhir if */

  else { /* langkah rekursif */
    return ( angka * faktorial( angka - 1 ) );
  } /* akhir else */
} /* akhir fungsi faktorial */


0! = 1
 1! = 1
 2! = 2
 3! = 6
 4! = 24
 5! = 120
 6! = 720
 7! = 5040
 8! = 40320
 9! = 362880
10! = 3628800

Gambar 4.14 | Penghitungan faktorial dengan suatu fungsi rekursif

4.14 Contoh Penggunaan Rekursi: Deret Fibonacci
Deret Fibonacci

0, 1, 1, 2, 3, 5, 8, 13, 21, …

dimulai dengan 0 dan 1 dan memiliki watak bahwa setiap suku deret Fibonacci merupakan penjumlahan dari dua suku Fibonacci sebelumnya.

Deret ini terjadi di alam dan, secara khusus, mendeskripsikan suatu bentuk spiral. Rasio dari suku-suku Fibonacci yang berurutan kenvergen menjadi suatu angka konstanta 1.618.... Angka ini, juga, terjadi di alam dan telah dikenal sebagai rasio emas (golden ratio) atau rerata emas (golden rmean). Manusia cenderung merasakan secara estetika bahwa rasio emas menyenangkan. Para arsitek seringkali merancang jendela, kamar, dan bangunan yang memiliki panjang dan lebar dengan rasio emas. Bahkan kartu pos pun didesain dengan panjang/lebar rasio emas.

Deret Fibbonacci didefinisikan secara rekursif sebagai berikut:

fibonacci(0) = 0
fibonacci(1) = 1
fibonacci(n) = fibonacci(n – 1) + fibonacci(n – 2)

Gambar 4.15 menghitung suku Fibonacci ke-n secara rekursif menggunakan fungsi fibonacci. Perhatikan bahwa suku Fobonacci cenderung membesar dengan sangat cepat. Oleh karena itu, dipilih tipe data long untuk tipe parameter dan tipe nilai balik di dalam fungsi fibonacci. Pada Gambar 4.15, setiap pasang baris keluaran menunjukkan eksekusi program yang terpisah.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Gambar 4.15: gambar04_15.c
   Fungsi fibonacci rekursif */
#include <stdio.h>

long fibonacci( long n ); /* prototipe fungsi */

/* fungsi main memulai eksekusi program */
int main( void )
{
  long hasil; /* nilai fibonacci */
  long angka; /* angka yang dimasukkan pengguna */

  /* mendapatkan integer dari pengguna */
  printf( "Masukkan sebuah integer: " );
  scanf( "%ld", &angka );

  /* menghitung nilai fibonacci untuk angka dari pengguna */
  hasil = fibonacci( angka );

  /* menampilkan hasil */
  printf( "Fibonacci( %ld ) = %ld\n", angka, hasil );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* definisi rekursif atas fungsi fibonacci */
long fibonacci( long n )
{
  /* kasus basis */
  if ( n == 0 || n == 1 ) {
    return n;
  } /* akhir if */
  else { /* langkah rekursif */
    return fibonacci( n - 1 ) + fibonacci( n - 2 );
  } /* akhir else */
} /* akhir fungsi fibonacci */


Masukkan sebuah integer: 0
Fibonacci( 0 ) = 0


Masukkan sebuah integer: 1
Fibonacci( 1 ) = 1


Masukkan sebuah integer: 2
Fibonacci( 2 ) = 1


Masukkan sebuah integer: 3
Fibonacci( 3 ) = 2

Masukkan sebuah integer: 4
Fibonacci( 4 ) = 3


Masukkan sebuah integer: 5
Fibonacci( 5 ) = 5


Masukkan sebuah integer: 6
Fibonacci( 6 ) = 8


Masukkan sebuah integer: 10
Fibonacci( 10 ) = 55


Masukkan sebuah integer: 20
Fibonacci( 20 ) = 6765

Gambar 4.15 | Pembangkitan rekursif atas deret Fibonacci

Pemanggilan terhadap fibonacci dari main bukanlah pemanggilan rekursif (baris 18), tetapi semua pemanggilan rekursif terhadap fibonacci dilakukan pada baris 33. Setiap kali fibonacci dipanggil, ia menguji apakah merupakan kasus basis, yaitu apakah n sama dengan 0 atau 1. Jika bernilai true, maka n akan dijadikan nilai balik. Jika n lebih besar dari 1, langkah rekursif akan menghasilkan dua pemanggilan rekursif. Gambar 4.16 menunjukkan bagaimana fungsi fibonacci mengevaluasi fibonacci(3).


Gambar 4.16 | Himpunan pemanggilan untuk fibonacci(3)


Kesimpulan
§  Modul di dalam C disebut dengan fungsi. Pustaka standar C menyediakan koleksi fungsi yang kaya untuk melakukan operasi kalkulasi matametik, manipulasi string, masukan/keluaran, dan banyak operasi lainnya yang berguna. Modul berguna untuk mempermudah pekerjaan Anda, karena fungsi menyediakan banyak kapabilitas yang Anda butuhkan.

§  Fungsi dapat dipanggil melalui pemanggilan fungsi, yang menspesifikasi nama fungsi dan menyediakan informasi (sebagai argumen) yang dibutuhkan oleh fungsi yang dipanggil untuk melakukan pekerjaan yang ditugaskan. Analogi yang umum untuk hal ini adalah suatu hirarki suatu manajemen. Seorang boss (fungsi pemanggil atau pemanggil) meminta seorang pekerja (fungsi terpanggil) untuk melakukan suatu pekerjaan dan melaporkan kembali ketika pekerjaan selesai dilakukan.

§  Fungsi-fungsi pustaka matematika memampukan Anda untuk melakukan beberapa kalkulasi matematik umum.

§  Fungsi membantu Anda untuk memodularisasi suatu program. Semua variabel yang didefinisikan di dalam definisi fungsi adalah variabel lokal, yang hanya dikenal di dalam fungsi yang di dalamnya variabel tersebut didefinisikan. Kebanyakan fungsi memiliki daftar parameter yang menyediakan cara untuk mengkomunikasikan informasi di antara fungsi. Sebuah parameter fungsi juga merupakan variabel lokal dari fungsi tersebut.

§  Salah satu fitur yang penting dalam C adalah prototipe fungsi. Fitur ini dipinjam oleh komite standar C dari para pengembang C++. Prototipe fungsi memberitahu kompiler tentang tipe data nilai balik fungsi, jumlah parameter yang diterima fungsi, tipe data tiap parameter, dan urutan parameter. Kompiler menggunakan prototipe fungsi untuk memvalidasi pemanggilan fungsi.

§  Fitur penting lainnya dari prototipe fungsi adalah pemaksaan argumen, yaitu memaksa argumen menjadi tipe yang sesuai. Sebagai contoh, fungsi pustaka matematika sqrt dapat dipanggil dengan suatu argumen integer meskipun prototipe fungsi di dalam <math.h> menspesifikasi suatu argumen double, dan fungsi tersebut masih bisa bekerja dengan benar.

§  Aturan promosi secara otomatis diterapkan terhadap ekspresi yang memuat nilai dari dua atau lebih tipe data (yang dikenal juga sebagai ekspresi tipe-gabungan). Tipe data dari setiap nilai di dalam suatu ekspresi tipe-gabungan secara otomatis dipromosikan menjadi tipe tertinggi di dalam ekspresi tersebut (sebenarnya sebuah versi temporer dari setiap nilai yang diciptakan dan digunakan dalam ekspresi, dimana nilai-nilai awal tetap tidak berubah).

§  Ketika program memanggil suatu fungsi, fungsi terpanggil harus mengetahui bagaimana kembali (mengembalikan nilai balik, jika ada) ke pemanggil, jadi alamat kembali dari fungsi pemanggil ditempatkan pada tumpukan eksekusi program (dikenal pula sebagai tumpukan pemanggilan fungsi). Jika sederet pemanggilan fungsi dilakukan, alamat kembali yang berurutan ditempatkan pada tumpukan secara LIFO, sehingga setiap fungsi dapat kembali ke pemanggilnya.
§  Setiap pustaka standar memiliki header yang memuat prototipe fungsi untuk semua fungsi yang ada di dalam pustaka tersebut dan definisi atas berbagai tipe data dan konstanta yang dibutuhkan untuk semua fungsi tersebut.

§  Pemanggilan-dengan-nilai harus digunakan ketika fungsi terpanggil tidak perlu memodifikasi nilai dari variabel asli pemanggil. Hal ini mencegah efek samping yang tak sengaja dilakukan (modifikasi variabel). Pemanggilan-dengan-referensi harus digunakan hanya dengan fungsi terpanggil yang dapat dipercaya untuk memodifikasi variabel asli.

§  Skop suatu pengenal adalah bagian program dimana di dalamnya pengenal dapat direferensi. Sebagai contoh, ketika sebuah variabel lokal didefinisikan di dalam suatu blok, ia dapat direferensi hanya di dalam blok tersebut atau di dalam blok yang bersarang di dalam blok tersebut. Empat jenis skop pengenal adalah skop fungsi, skop file, skop blok, dan skop prototipe-fungsi.

Soal
1.       Tulislah suatu program untuk mengujia contoh-contoh pemanggilan fungsi pustakan matematika yang ditampilkan pada Gambar 4.2 dan buktikan hasilnya.

2.       Temukan kesalahan pada tiap potongan program berikut dan jelaskan bagaimana kesalahan tersebut dapat dikoreksi:
a)       int g( void )
{
  printf( "Di dalam fungsi g\n" );
  int h( void )
  {
    printf( "Di dalam fungsi h\n" );
  }
}

b)      int jum( int x, int y )
{
  int hasil;
  hasil = x + y;
}

c)       int jum( int n )
{
  if ( n == 0 ) {
    return 0;
  }
  else {
    n + jum( n - 1 );
  }
}

d)      void f( float a );
{
  float a;
  printf( "%f", a );
}

e)       void perkalian( void )
{
  int a, b, c, hasil;
  printf( "Masukkan tiga integer: " )
  scanf( "%d%d%d", &a, &b, &c );
  hasil = a * b * c;
  printf( "Hasil adalah %d", hasil);
  return hasil;
}

3.       Apakah yang dilakukan program berikut ini:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/* coba.c */
/* Tebak sendiri */
#include <stdio.h>
#include <math.h>

/* fungsi main memulai eksekusi program */
int main( void )
{
  /* menghitung dan menampilkan akar kuadrat */
  printf( "sqrt(%.1f) = %.1f\n", 900.0, sqrt( 900.0 ) );
  printf( "sqrt(%.1f) = %.1f\n", 9.0, sqrt( 9.0 ) );

  /* menghitung dan menampilkan fungsi eksponensial e */
  printf( "exp(%.1f) = %f\n", 1.0, exp( 1.0 ) );
  printf( "exp(%.1f) = %f\n", 2.0, exp( 2.0 ) );

  /* menghitung dan menampilkan logaritma (basis e) */
  printf( "log(%f) = %.1f\n", 2.718282, log( 2.718282 ) );
  printf( "log(%f) = %.1f\n", 7.389056, log( 7.389056 ) );

  /* menghitung dan menampilkan logaritma (basis 10) */
  printf( "log10(%.1f) = %.1f\n", 1.0, log10( 1.0 ) );
  printf( "log10(%.1f) = %.1f\n", 10.0, log10( 10.0 ) );
  printf( "log10(%.1f) = %.1f\n", 100.0, log10( 100.0 ) );

  /* menghitung dan menampilkan nilai absolut */
  printf( "fabs(%.1f) = %.1f\n", 13.5, fabs( 13.5 ) );
  printf( "fabs(%.1f) = %.1f\n", 0.0, fabs( 0.0 ) );
  printf( "fabs(%.1f) = %.1f\n", -13.5, fabs( -13.5 ) );

  /* menghitung dan menampilkan ceil( x ) */
  printf( "ceil(%.1f) = %.1f\n", 9.2, ceil( 9.2 ) );
  printf( "ceil(%.1f) = %.1f\n", -9.8, ceil( -9.8 ) );

  /* menghitung dan menampilkan floor( x ) */
  printf( "floor(%.1f) = %.1f\n", 9.2, floor( 9.2 ) );
  printf( "floor(%.1f) = %.1f\n", -9.8, floor( -9.8 ) );

  /* menghitung dan menampilkan pow( x, y ) */
  printf( "pow(%.1f, %.1f) = %.1f\n", 2.0, 7.0, pow( 2.0, 7.0 ) );
  printf( "pow(%.1f, %.1f) = %.1f\n", 9.0, 0.5, pow( 9.0, 0.5 ) );

  /* menghitung dan menampilkan fmod( x, y ) */
  printf( "fmod(%.3f/%.3f) = %.3f\n", 13.675, 2.333,
  fmod( 13.675, 2.333 ) );

  /* menghitung dan menampilkan sin( x ) */
  printf( "sin(%.1f) = %.1f\n", 0.0, sin( 0.0 ) );

  /* menghitung dan menampilkan cos( x ) */
  printf( "cos(%.1f) = %.1f\n", 0.0, cos( 0.0 ) );

  /* menghitung dan menampilkan tan( x ) */
  printf( "tan(%.1f) = %.1f\n", 0.0, tan( 0.0 ) );
 
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

4.       Tampilkan nilai dari x setelah setiap statemen berikut dieksekusi:
a)        x = fabs( 7.5 );
b)       x = floor( 7.5 );
c)        x = fabs( 0.0 );
d)       x = ceil( 0.0 );
e)        x = fabs( -6.4 );
f)        x = ceil( -6.4 );
g)       x = ceil( -fabs( -8 + floor( -5.5 ) ) );

5.       Tulislah suatu aplikasi dari fungsi floor untuk membulatkan sebuah nilai menjadi integer terdekat. Statemen

y = floor( x + .5 );

akan membulatan x menjadi integer terdekat dan menugaskan hasilnya kepada y. Tulislah suatu program yang membaca beberapa angka dan menggunakan statemen tersebut untuk membulatkan setiap angka yang dibaca menjadi integer terdekat. Untuk setiap angka yang diproses, tampilkan angka asli dan angka hasil pembulatan.

6.       Tulislah suatu fungsi kelipatan yang menentukan untuk sepasang integer yang diberikan apakah integer kedua merupakan kelipatan dari integer pertama. Fungsi tersebut mengambil dua argumen dan menghasilkan nilai balik 1 (true) jika integer kedua adalah kelipatan dari integer pertama, dan 0 (false) jika sebaliknya.

7.       Tulislah suatu program yang mengentrikan sederet integer dan melewatkannya satu demi satu kepada fungsi genap, yang menggunakan operator sisa dalam menentukan apakah suatu integer genap atau tidak. Fungsi ini mengambil sebuah argumen integer dan menghasilkan nilai balik 1 jika integer genap dan nilai balik 0 jika sebaliknya.
8.       Dapatkah main dipanggil secara rekursif? Tulislah suatu program yang memuat sebuah fungsi main. Sertakan sebuah variabel lokal statis, hitung, yang diinisialisasi dengan 1. Lakukan post-inkremen dan tampilkan nilai dari hitung setiap kali main dipanggil. Jalankan program Anda dan amati apa yang terjadi?

9.       Tulislah suatu fungsi jarak yang menghitung jarak antaran dua titik (x1,y1) dan (x2,y2). Semua angka dan nilai balik harus bertipe double.

10.    Deret Fibonacci didefinisikan sebagai

0, 1, 1, 2, 3, 5, 8, 13, 21, …

dimulai dengan suku 0 dan 1 dan memiliki watak bahwa setiap suku merupakan penjumlahan dari dua suku sebelumnya. a) Tulislah sebuah fungsi tak-rekursif fibonacci(n) yang menghitung suku Fibonacci ke-n. b) Tentukan suku Fibonacci terbesar yang dapat ditampilkan pada sistem Anda. Modifikasi program pada bagian a) untuk menggantikan int dengan double dalam menghitung deret Fibonacce. Biarkan program beriterasi sampai mengalami kegagalan akibat nilai yang terlalu tinggi.

11.    Apakah yang dilakukan program berikut ini?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

/* fungsi main memulai eksekusi program */
int main( void )
{
  int c; /* variabel untuk menampung masukan karakter dari pengguna */

  if ( ( c = getchar() ) != EOF ) {
    main();
    printf( "%c", c );
  } /* akhir if */

  return 0; /* indikasi terminasi sukses */
} /* akhir main */

12.    Apakah yang dilakukan program berikut ini?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>

int misteri( int a, int b ); /* prototipe fungsi */

/* fungsi main memulai eksekusi program */
int main( void )
{
  int x; /* integer pertama */
  int y; /* integer kedua */

  printf( "Masukkan dua integer: " );
  scanf( "%d%d", &x, &y );

  printf( "Hasilnya adalah %d\n", misteri( x, y ) );
  return 0; /* indikasi terminasi sukses */
} /* akhir main */

/* Parameter b harus integer positif
   untuk mencegah rekursi tak-terhingga */
int misteri( int a, int b )
{
  /* kasus basis */
  if ( b == 1 ) {
    return a;
  } /* akhir if */
  else { /* langkah rekursif */
    return a + misteri( a, b - 1 );
  } /* akhir else */
} /* akhir fungsi misteri */

13.    Temukan kesalahan pada tiap potongan program dan jelaskan bagaimana mengoreksinya:
a)       double kubik( float ); /* prototipe fungsi */
kubik ( float angka ) /* definisi fungsi */
{
  return angka * angka * angka;
}

b)      register auto int x = 7;

c)       int bilanganAcak = srand();

d)      double y = 123.45678;
int x;
x = y;
printf( "%f\n", (double) x );

e)       double kuadrat( double angka )
{
  double angka;
  return angka * angka;
}

f)        int sum( int n )
{
  if ( n == 0 ) {
    return 0;
  }
  else {
    return n + sum( n );
  }
}


14.    Tulislah suatu fungsi yang mengambil sebuah nilai integer dan menghasilkan nilai balik berupa angka dengan dijit-dijit terbalik. Sebagai contoh, jika diberikan angka 7823, maka fungsi akan menghasilkan nilai balik 3287.


No comments:

Post a Comment