C Programming – Foundation Level 1
C PROGRAMMING Foundation Level
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 2
DAFTAR ISI C Programming ......................................................................................................1 DAFTAR ISI..............................................................................................................2 Pengantar.................................................................................................................5 1. Perspektif.............................................................................................................6 Sejarah Bahasa C.................................................................................................6 Struktur Bahasa C ................................................................................................6 Titik koma atau semicolons (;)...........................................................................6 Free Form..........................................................................................................7 Case-sensitive...................................................................................................7 Variabel..............................................................................................................7 printf() dan scanf()..............................................................................................8 Program Entry Point..............................................................................................8 C Keywords...........................................................................................................9 2. Tipe Data............................................................................................................10 Tipe data Integer dalam C...................................................................................10 Tipe Bilangan Real..............................................................................................10 Konstanta.............................................................................................................11 Konstanta dengan tipe data.............................................................................11 Konstanta dengan preprocessor......................................................................11 3. Operator.............................................................................................................13 Operator Aritmetika..............................................................................................13 Casting Operator.................................................................................................14 Operator Increment dan Decrement....................................................................14 Prefix ++ dan –.................................................................................................14 Posfix ++ dan –................................................................................................15 Operator Komparasi............................................................................................15 Operator Logika...................................................................................................15 Bitwise Operator..................................................................................................16 Assignment Operators.........................................................................................17 Operator sizeof....................................................................................................18 Operator Kondisional...........................................................................................18 4. Control Flow (Alur Program)............................................................................19 Pengambilan keputusan dengan if – else...........................................................19 Pengujian kondisi dengan switch........................................................................20 while.....................................................................................................................22 do-while...............................................................................................................22 for.........................................................................................................................23 break....................................................................................................................24 continue...............................................................................................................24 5. Fungsi.................................................................................................................25 Nilai balik (return value).......................................................................................25 Nama fungsi.........................................................................................................25 Parameter............................................................................................................25 Pemanggilan fungsi.............................................................................................26 Penulisan Prototipe.............................................................................................26 Penulisan definisi fungsi......................................................................................26 Lebih lanjut tentang pemanggilan fungsi.............................................................27
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 3 C dan stack..........................................................................................................27 Code Segment.................................................................................................28 Stack Segment.................................................................................................28 Data Segment..................................................................................................28 Heap.................................................................................................................28 Variabel qualifier..................................................................................................28 auto..................................................................................................................28 static.................................................................................................................29 register.............................................................................................................29 6. Pointer................................................................................................................30 Deklarasi Pointer.................................................................................................30 Inisialisasi Pointer................................................................................................32 Melewatkan parameter dengan pointer...............................................................32 Pointer ke data konstan.......................................................................................34 Pointer ke pointer................................................................................................34 Pointer ke fungsi (function pointer)......................................................................35 7. Array...................................................................................................................39 Deklarasi array....................................................................................................39 Inisialisasi array...................................................................................................39 Mengakses elemen array....................................................................................39 Array sebagai paramater fungsi..........................................................................41 Array “Multidimensional”......................................................................................42 8. String..................................................................................................................43 Deklarasi..............................................................................................................43 Mencetak String...................................................................................................43 String Assignment................................................................................................43 char * strcpy(char * dest,const char * src);......................................................44 char * strncpy(char * dest,const char * src,size_t count);................................44 Manipulasi string..................................................................................................44 size_t strlen(const char* str);...........................................................................44 char * strrev(char * str);....................................................................................44 char *strcat(char * dest, const char * src);.......................................................45 char * strchr(const char* str,int c);....................................................................45 int strcmp(const char* str1,const char* str2);...................................................45 char *strstr(const char * str,const char * sub);.................................................45 size_t strspn(const char * str,const char * cset);..............................................46 char *strtok(char * str,const char * delim);.......................................................46 9. Struktur..............................................................................................................48 Deklarasi..............................................................................................................48 Penggunaan struktur...........................................................................................48 Struktur dalam struktur........................................................................................49 Mengakses struktur dengan pointer....................................................................49 Assignment antara struktur.................................................................................49 Melewatkan parameter non-primitive data..........................................................50 10. Operasi File......................................................................................................51 Stream.................................................................................................................51 File teks (text file)................................................................................................51 Penanganan kesalahan (error handling).............................................................52 File biner (binary file)...........................................................................................53
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 4 Pencarian dalam file biner (binary file)............................................................54 11. Memori Dinamis...............................................................................................58 Pointer dan Memori Dinamis...............................................................................58 void * malloc(size_t n);.....................................................................................58 void * calloc(size_t nelem, size_t elemsize);...................................................59 void * realloc(void * ptr, size_t n);....................................................................59 void free(void * ptr);..........................................................................................61 Lebih lanjut tentang realloc()...............................................................................61 Struktur data dinamis...........................................................................................61 12. Tanggal dan waktu..........................................................................................65 13. Union, tipe enumerasi dan preprocessor.....................................................69 Union...................................................................................................................69 Enumerasi............................................................................................................69 Preprocessor (“front end processor”)..................................................................70 Menyertakan file...............................................................................................70 Mendeklarasikan Konstanta............................................................................70 Mendefinisikan makro......................................................................................71 Debugging........................................................................................................71 Appendix................................................................................................................73 ANSI C Escape Sequences and Trigraph...........................................................73 ANSI Library Header Files...................................................................................73 Fungsi-fungsi untuk konversi...............................................................................74 double atof(const char* str);.............................................................................74 int atoi(const char * str);...................................................................................74 int atol(const char * str);...................................................................................74 int tolower(int c);...............................................................................................75 int toupper(int c);..............................................................................................75 int isalnum(int c);..............................................................................................75 int isalpha(int c);...............................................................................................75 int sprintf(char * str, const char * fmt,…);.........................................................75 Kepustakaan..........................................................................................................76 The C Programming Language 2nd Edition....................................................76 Thinking in C++2nd Edition .............................................................................76 The C Standard Library....................................................................................76 Microsoft C/C++ Developer’s Guide................................................................76 WHAT’s next….......................................................................................................77 Catatan...................................................................................................................78
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 5
PENGANTAR Tulisan (buku?) ini diharapkan dapat memberikan pengetahuan dasar bahasa pemrograman C dengan sedapat mungkin berpedoman pada Standard C. Dengan pendekatan ini kami berharap peserta dapat menulis program dalam bentuk yang murni yang dapat dikompilasi dengan semua jenis compiler C yang ada dengan penyesuaian yang seminimal mungkin. Karena C sendiri tidak tampil dengan bentuk yang sederhana dan cenderung rumit terutama bagi yang tidak memiliki latar belakang pemrograman sema sekali, maka pengalaman dalam bahasa pemrograman sebelumnya akan sangat membantu. Namun jika anda termasuk pemula dalam pemrograman, anda dapat mengikuti modul ini mulai dari awal sampai akhir dan secara aktif mencoba sebanyak mungkin latihan dan mencari sumber-sumber lain tentang pemrograman C. Dengan investasi anda di C, memudahkan anda mempelajari bahasa yang lebih lanjut seperti C++ yang merupakan “superset” dari C. Semua contoh program dalam modul ini menggunakan compiler Visual C++ 6 dengan tetap berpedoman pada Standard C, namun anda dapat menggunakan compiler C apa saja yang compatible.
Malang, Chipmunk - 2003
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 6
1. PERSPEKTIF Sejarah Bahasa C Bahasa C pertama kali dikembangkan oleh Brian Kernighan dan Dennis Ritchie di AT & T Bell Labs pada tahun 1972. Pada tahun 1980 C manjadi sangat populer dikalangan programmer dari berbagai komunitas sehingga dirasa diperlukan standarisasi. Di Amerika, yang bertugas untuk membuat standarisasi adalah American National Standards Institute (ANSI). ANSI membentuk komite X3J11 untuk mengembangkan standarisasi C yang selanjutnya dikenal dengan X3.159. Pada tingkat internasional, organisasi dunia yang bernama International Standards Organization (ISO) bertanggungjawab untuk membuat standarisasi bahasa komputer. ISO membentuk komite teknis JTC1/SC22/WG14 untuk meninjau hasil X3J11. Standarisasi C oleh ISO yaitu ISO 9889:1990 hampir sama dengan X3.159. Untuk selanjutnya standarisasi ini dikenal dengan C Standard.
Struktur Bahasa C LISTING 1.1. Hello.C #include<stdio.h> int main(void) { printf(“hello C !\n”) }
/*komentar*/
;
return 0;
Pernyataan #include memerintahkan preprocessor untuk mencari file stdio.h. Komentar untuk program ditulis di antara /* dan */ dan tidak akan ikut dikompilasi. Fungsi main sangat penting karena merupakan awal dimana program dimulai. Tanpa fungsi ini program anda tidak akan dapat dikompilasi. Tanda kurung “{“ dan “}” menandakan awal dan akhir. Fungsi printf() berfungsi untuk mencetak ke layar. Karakter “\n” berfungsi untuk pindah baris Kata kunci return yang dalam program ini ditulis return 0, menyebabkan nilai dalam hal ini 0 dikembalikan ke sistem operasi yang biasanya berarti proses berhasil dijalankan dengan baik. Jadi nilai ini lebih berguna bagi operating system itu sendiri.
Titik koma atau semicolons (;) Karakter ini sangat penting dalam C yang menunjukkan akhir dari sebuah pernyataan yang dimengerti oleh kompiler.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 7
Free Form C memiliki struktur program yang sangat bebas (free form). Kita dapat meletakkan semicolon di sembarang tempat. Tapi tentunya kita tidak akan menulis program yang selanjutnya sangat sulit untuk dibaca oleh kita sendiri apalagi oleh orang lain. Dengan kata lain kita harus mengikuti suatu tata cara penulisan yang baik dan selalu konsisten. Kalau tidak maka kita akan menyetujui bahwa C sering dujuluki sebagai “write only program”.
Case-sensitive Penulisan dalam C sangat sensitive yang membedakan huruf besar dengan huruf kecil. Jadi int sangat berbeda dengan INT atau dengan Int. Sebagai konvensi, nama-nama fungsi atau variabel biasanya ditulis dalam huruf kecil untuk memudahkan penulisan. Ketikkan program berikut : LISTING 1.2. Printf.C #include <stdio.h> int main(void) { int a,b; printf(“Masukkan dua buah bilangan : “); scanf(“%i %i”,&a,&b); printf(“Bilangan yang dimasukkan : %i dan %i\n”,a,b); return 0; }
Kata kunci int sebelum nama variabel a dan b adalah deklarasi variabel dengan dengan tipe integer. printf() digunakan untuk menuliskan teks ke layar sedangkan scanf() untuk membaca apa yang diketikkan dan dimasukkan ke dalam variabel a dan b. %i digunakan untuk memerintahkan scanf() atau printf() bahwa bilangan yang akan diproses adalah tipe integer.
Variabel Variabel berfungsi untuk menyimpan suatu data dengan tipe tertentu dengan ukuran tertentu pula. Variabel harus dideklarasikan sebelum digunakan biasanya setelah tanda “{“ (tanpa tanda kutip). Karakter yang diijinkan adalah huruf abjad, angka, dan karakter “_“. Karakter pertama tidak boleh angka. Nama variabel maksimal 31 karakter. Jika ditulis lebih maka kelebihannya akan diabaikan. Huruf besar dan kecil dianggap berbeda (case sensitive). int a; double d1,d2;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 8 Deklarasi variabel juga dapat sekaligus memberikan nilai awal atau inisialisasi seperti : int a = 0; double d1 = 12.5,d2 = 0.34;
printf() dan scanf() Fungsi-fungsi ini paling sering digunakan dalam program dalam mode text yang prototipenya dideklarasikan dalam stdio.h. Fungsi printf() digunakan untuk menulis ke layar dengan format tertentu. Jika format yang digunakan %i maka integer akan dituliskan ke layar. Sedangkan fungsi scanf() digunakan untuk membaca masukan dari keyboard. Jika scanf() menemukan format tertentu misalnya %i, maka ia akan menunggu bilangan integer diketikkan. Tanda & sangat penting dalam scanf() yang mengijinkan untuk mengubah variabel yang dilewatkan misalnya : scanf(“%i”,&a);
Penjelasan tentang & ada pada bagian selanjutnya dari modul ini yaitu pada bagian pointer.
Program Entry Point Dalam C program utama dimulai dari fungsi main() yang dapat mempunyai bentuk : int main(void) int main(int argc,char ** argv) int main(int argc,char *argv[])
Fungsi main() dengan parameter seperti bentuk kedua dan ketiga berguna kalau anda ingin mendapatkan program arguments yang disimpan dalam argv sebanyak argc. Index nol adalah nama program itu sendiri lengkap dengan nama direktorinya. Contoh : LISTING 1.3. Args.C #include <stdio.h> int main(int argc,char *argv[]) { int i; for (i = 0;i < argc ;i++) printf(“Arguments %i : %s\n”,argv[i]); return 0; }
Misalnya kita namakan program ini prog1.exe. Ketikkan : prog1 arg1 arg2, dan amati keluaran program.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 9
C Keywords ANSI C dan juga Standard C menggunakan kata-kata kunci (keywords) berikut : auto break case char const continue default do
double else enum extern float for goto if
int long register return short signed sizeof static
Copyright Chipmunk Personal Passion Lab © 2003
struct switch typedef union unsigned void volatile while
C Programming – Foundation Level 10
2. TIPE DATA Tipe data Integer dalam C C memiliki beberapa tipe data yang tergolong integer (bilangan bulat) dengan batas-batas minimal dan maksimal dideklarasikan dalam unit header limits.h. Tipe char signed char unsigned char short unsigned short int unsigned int long int unsigned long
Format %c %c %c %hi %hu %i %u %li %lu
Bytes 1 1 1 2 2 2 atau 4 2 atau 4 4 4
Minimum CHAR_MIN SCHAR_MIN 0 SHRT_MIN 0 INT_MIN 0 LONG_MIN 0
Maksimum CHAR_MAX SCHAR_MAX UCHAR_MAX SHRT_MAX USHRT_MAX INT_MAX UINT_MAX LONG_MAX ULONG_MAX
Kita dapat bekerja dengan tipe data integer dengan basis yang lain misalnya octal atau hexadesimal. Untuk bekerja dengan bilangan octal bilangan diawali dengan angka 0 jadi 08 akan berbeda dengan 8. Jika bekerja dengan bilangan hexadesimal, kita harus menambahkan 0x didepan sebuah angka dan selanjutnya huruf a,b,c,d,e,f bisa digunakan dalam bilangan. Untuk format penampilan dengan fungsi printf, kita gunakan %o untuk menampilkan dalam bilangan octal dan %x jika dikehendaki dalam bilangan hexadesimal dengan huruf abcdef (dalam huruf kecil). Sedangkan %X akan menampilkan dalam huruf besar jika bilangan yang ditampilkan mengandung huruf-huruf tersebut.
Tipe Bilangan Real Bahasa C mendukung secara luas tipe data real yang jangkauannya dideklarasikan dalam header file floats.h. Tipe data yang termasuk bilangan real dicantumkan dalam tabel Tipe float double long double
Format %f %e %g %lf %le %lg %Lf %Le %Lg
Bytes 4 8 10
Minimum FLT_MIN DBL_MIN LDBL_MIN
Maksimum FLT_MAX DBL_MAX LDBL_MAX
Tipe data float adalah tipe bilangan real yang paling kecil yang memerlukan ruang 4 bytes diikuti oleh double dan yang paling besar adalah long double. Program berikut adalah contoh penggunaan tipe data real dengan menggunakan fungsi printf() untuk menampilkan hasilnya : LISTING 2.1. Real.C #include<stdio.h> #include
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 11 int main(void) { double f = 3.14,g = 1.2e-5,h = 500000000.0; printf(“f=%lf\tg=%lf\th=%lf\n”,f,g,h); printf(“f=%le\tg=%le\th=%le\n”,f,g,h); printf(“f=%lg\tg=%lg\th=%lg\n”,f,g,h); printf(“f=%7.2lf\tg=%.2le\th=%.4lg\n”,f,g,h); }
return 0;
Output program adalah, f=3.140000 f=3.140000 f=3.140000e+00 f=3.14 f=3.14 f=3.140000 f=3.140000e+00 f=3.14 f=3.14
g=0.000012 g=0.000012 g=1.200000e-05 g=1.2e-05 g=1.20e-05 g=0.000012 g=1.200000e-05 g=1.2e-05 g=1.20e-05
g=50000000.000000 g=50000000.000000 g=5.000000e+07 g=5e+07 g=5e+07 g=50000000.000000 g=5.000000e+07 g=5e+07 g=5e+07
Konstanta Konstanta dengan tipe data Konstanta digunakan untuk membuat suatu nilai tidak bisa diubah atau konstan. Dengan kata lain menarik garis yang tegas antara apa yang boleh dan tidak untuk dimodifikasi. Dalam C, kontanta dideklarasikan dengan const tipe nama = inisialisasi; Contoh : const double f = 100.5;
Bilangan yang mengandung “.”, “e” (tanpa tanda kutip) adalah tipe double misalnya 1.2, 2e-3. Akhiran “F” mendeklarasikan konstanta sebagai float misalnya 12.5F. Akhiran “L” mendeklarasikan konstanta sebagai long double misalnya 1.29e15L. Bilangan yang tidak mengandung “.”,”e” atau “F” adalah tipe int, namun beberapa compiler akan mengubah menjadi long int jika tidak mencukupi sebagai int. Untuk kontanta long int, diakhiri dengan “L” misalnya 9000000L.
Konstanta dengan preprocessor Konstanta juga dapat dideklarasikan dengan preprocessor misalnya #define PI 3.1415925 #define DAYS_IN_WEEK
7
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 12 Biasanya konstanta preprocessor ditulis dengan huruf besar. Dalam melakukan tugasnya compiler tidak memproses apa yang anda ketikkan, namun hasil output dari preprocessor. Jadi pada saat sebuah unit dikompilasi, preprocessor akan dijalankan terlebih dahulu yang akan mengganti setiap simbol yang ditemukan sesuai dengan deklarasi tanpa memandang tipe data. Karena itu preprocessor seringkali disebut sebagai front end processor.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 13
3. OPERATOR Dalam setiap bahasa pemrograman selalu memiliki operator yang berguna untuk melakukan suatu operasi (sehingga dinamakan operator) dengan menggunakan simbol-simbol tertentu. Dalam bab ini akan dibahasa operator-operator dalam C yang dikelompokkan dalam katagori operasionalnya.
Operator Aritmetika C mendukung operator untuk operasi artimetika seperti dalam tabel : Operator + * / %
Deskripsi Untuk operasi penjumlahan Untuk operasi penguranga Untuk operasi perkalian Untuk operasi pembagian Untuk mendapatkan sisa hasil pembagian
Perhatikan cuplikan program berikut , LISTING 3.1. Oprs.C int main(void) { int i = 5, j = 4, k; double f = 5.0, g = 4.0 , h; k = i / j; h = f / g; h = i / j; return 0; }
Pada baris k = i / j, compiler akan menggunakan pembagian integer karena kedua operand adalah tipe integer. Pada baris h = f / g, compiler menggunakan pembagian double karena jelas kedua operand adalah tipe double. Pada baris h = i / j, compiler tetap menggunakan pembagian integer dengan mengabaikan bahwa variabel untuk menampung hasilnya adalah tipe double. Hasil yang diperoleh akan disimpan dalam bentuk double.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 14
Casting Operator Istilah casting sering diartikan sebagai berperilaku seperti sesuatu yang lain dan untuk tujuan tertentu. Perhatikan baris program berikut : LISTING 3.2. Cast.C int main(void) { int i = 5, j = 4, k; double f; f f f f }
= = = =
(double)i / j; i / (double)j; (double)i / (double)j; (double) (i / j);
return 0;
Pada baris f = (double)i / j, f = i / (double)j dan f = (double)i / (double)j, compiler menggunakan pembagian tipe double karena salah satu operand adalah tipe double yang secara otomatis operand yang berukuran lebih kecil akan diubah sementara menjadi double. Operasi ini disebut type promotion. Sedangkan pada f = (double) (i / j), compiler tetap menggunakan pembagian integer namun hasilnya diubah ke double.
Operator Increment dan Decrement C sebagai tersed-language (bahasa yang ringkas) memiliki operator khusus yang digunakan untuk menambah (increment) dan mengurangi (decrement) suatu variabel dengan bentuk yang unik namun sangat ringkas yaitu ++ dan --. Ada dua versi untuk masing-masing operator ini yang biasa disebut prefix dan postfix sesuai dengan letak penulisannya.
Prefix ++ dan – Dengan prefix operator, operator-operator ini ditempatkan sebelum sebuah variabel yang akan dioperasikan misalnya : int
x = 5;
y = ++x; z = --x;
Prefix operator ini bekerja dengan prinsip Tambahkan (untuk ++) atau kurangkan (untuk --) nilai sebuah variabel dengan satu dan simpan nilai itu dalam sebuah variabel yang diletakkan di sebelah kiri jika ada. Jadi untuk contoh ini, nilai x yang semula bernilai 5 akan ditambahkan dengan satu (menjadi 6) dan disimpan dalam y, selanjutnya dikurangi satu dan disimpan dalam z (nilai 5);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 15
Posfix ++ dan – Operator ini bekerja dengan mengambil data sebelum dilakukan operasi postfix. int x = 5; y = x++; z = x--;
Operator Komparasi Bahasa C dalam melakukan operasi logika menggunakan dua logika yaitu benar (true) atau salah (false) namun C tidak memiliki kata kunci khusus untuk true/false. Semua nilai yang tidak nol (non-zero) akan dianggap true dan nilai nol akan dianggap false. Logika benar dan salah ini digunakan untuk melakukan operasi perbandingan dengan berbagai kondisi yang dalam C dapat dilakukan dengan operator- operator seperti dalam tabel : Operator < <= > >= !=
Deskripsi Kurang dari Kurang atau sama dengan Lebih besar dari Lebih besar atausama dengan TIdak sama dengan
Perhatikan contoh program berikut , int i = 10, j, k; j = i > 5; k = i < 2;
Hasil dari baris program ini akan membuat j bernilai 1 (true) karena i memang lebih besar dari 5 dan k bernilai 0 (false) karena i lebih besar dari 2.
Operator Logika Dalam melakukan operasi pembandingan atau komparasi seringkali dilakukan untuk dua atau lebih pernyataan logika untuk mengambil sebuah keputusan. C menyediakan operator untuk melakukan pembandingan logika : Operator && || !
Deskripsi Dan (and) Atau (or) Tidak (not)
Operator-operator ini juga menganggap nilai tidak nol sebagai nilai yang benar (true) dan nol sebagai nilai yang salah (false). Beberapa hal yang perlu diketahui dari perilaku compiler dalam mengevaluasi sebuah pernyataan logika : Evaluasi dilakukan dari kiri ke kanan
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 16 Evaluasi dilakukan dengan berpedoman pada prinsip “short circuit”. int j = 5, k = 2; if (j > 10 && k <= 2)
Untuk baris program ini, compiler tidak akan mengevaluasi k <= 2 karena operator && (and) yang akan bernilai benar hanya jika kedua operand yang dibandingkan bernilai benar (tidak nol). Jadi untuk hal ini karena j > 10 bernilai salah maka compiler sudah yakin bahwa pernyataan ini bernilai salah (false). Mekanisme ini disebut short-circuit. Dengan mekanisme ini juga, compiler dapat menghasilkan program yang lebih efisien. Sebagai saran praktis, gunakan tanda kurung untuk memisahakan masing-masing kondisi agar alur program menjadi jelas.
Bitwise Operator Operator-operator ini digunakan untuk memanipulasi bit-bit (bitwise) dalam sebuah variabel yang sering digunakan dalam bahasa assembly. Keberadaan operator ini sangat masuk akal karena C pertama kali dirancang untuk membuat abstraksi dari assembly dan dijuluki sebagai high level assembly. Operator-operator yang disediakan antara lain : Operator & | ~ >> << ^
Deskripsi and or not (negasi) geser ke kiri geser ke kanan xor
Bagi anda yang tidak memiliki latar belakang pemrograman sama sekali, operatoroperator ini perlu mendapat penjelasan lebih lanjut. Untuk memahami operatoroperator ini perlu juga dijelaskan tentang tabel kebenaran untuk operasi-operasi and, or dan xor. Untuk operator-operator yang lain dapat dipahami dengan mudah sesuai dengan namanya. or 0 1
0 0 1
1 1 1
and 0 1
0 0 0
1 0 1
xor 0 1
0 0 1
1 1 0
Operator ~ akan mengubah sebuat bit menjadi kebalikannya yaitu 1 menjadi 0 dan 0 menjadi 1. Operator >> akan mengeser bit-bit dalam sebuah operand ke kiri sebanyak angka yang diletakkan di sebelah kanan operator ini. Misalnya,
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 17
int a = 2; a = 2 >> 1;
Assignment Operators Operator ini berfungsi untuk mentransfer suatu nilai antara dua operand. Bentuk dari assigment dalam C adalah : ekspresi1 (operator)= ekspresi2 yang ekuivalen dengan ekspresi1 = ekspresi1 (operator) ekspresi2 Jadi C menyedikan bentuk singkat untuk operasi assignment seperti dalam tabel : Operator op1 += op2 op1 -= op2 op1 *= op2 op1 /= op2 op1 %= op2 op1 &= op2 op1 |= op2 op1 ^= op2 op1 <<= op2 op1 >>= op2
Deskripsi op1 = op1 + op2 op1 = op1 – op2 op1 = op1 * op2 op1 = op1 / op2 op1 = op1 % op2 op1 = op1 & op2 op1 = op1 | op2 op1 = op1 ^ op2 op1 = op1 << op2 op1 = op1 >> op2
Contoh : int a = 10,b = 12.5; a += b; b /= 10;
Setelah program dijalankan akan membuat nilai-nilai variabel menjadi: a = 22.5 b = 1.35
Seringkali kesalahan timbul karena salah menuliskan assignment dengan komparasi, Ditulis, if (a = b) { }
yang sebenarnya dimaksud,
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 18 if (a == b) { }
Yang paling menyulitkan adalah dengan “kesalahan” itu compiler tidak akan menginformasikan sebagai kesalahan sintak karena dianggap kita mengerti apa yang kita lakukan. Jadi tergantung pada konteks, kalau yang kita maksud adalah memang assignment, pernyataan itu menjadi benar dan sebaliknya.
Operator sizeof Walaupun operator ini bukan termasuk dalam standar C namun hampir setiap compiler mengimplementasikannya.Operator ini mempunyai bentuk yang sangat mirip dengan sebuah fungsi yang memungkinkan kita mengetahui jumlah bytes yang diperlukan sebuah tipe data atau variabel. Penggunaan operator ini sangat mudah misalnya: sizeof(double) ;
dapat juga ditulis sizeof double;
Operator Kondisional Operator ini berguna untuk menguji suatu kondisi. Operator ini mempunyai bentuk kondisi ? ekspresi_jika_kondisi_benar : ekspresi_jika_kondisi_salah; yang sama jika ditulis, if (kondisi) ekspresi_jika_kondisi_benar; else ekspresi_jika_kondisi_salah; Contoh : int a,b = 20, c = -10; a = (b > c) ? b : c;
Baris perintah itu membuat nilai a menjadi 20; Operator ini biasa disebut ternary operator.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 19
4. CONTROL FLOW (ALUR PROGRAM) Program komputer ditulis untuk menyelesaikan suatu tugas. Dalam prosesnya sebuah program akan menerima masukan selanjutnya melakukan perbandingan, pengujian, penerapan algoritma tertentu dan menampilkan hasil proses itu dalam bentuk informasi yang berguna (opsional). Untuk memahami proses itu kita perlu mengetahui bagaimana masing-masing sub-proses itu dilakukan. Secara umum program melakukan proses itu dengan mengikuti suatu alur (flow) tertentu. Pada bab ini akan dibahas bagaimana alur itu diikuti dengan mengenalkan kepada anda tentang komparasi dan iterasi atau perulangan.
Pengambilan keputusan dengan if – else Bentuk umumnya dapat ditulis dalam bentuk : if (kondisi1) ekspresi1; else if (kondisi2) ekspresi2; else ekspresi3; atau multi baris harus disertakan tanda kurung { }, if (kondisi1) { ekspresi; …. } else if (kondisi2) { ekspresi; … } else { ekspresi; … } Pengujian dilakukan mulai dari kondisi1 berlanjut ke kondisi2 dan seterusnya. Jika semua tidak dipenuhi maka ekspresi terakhir setelah else akan dijalankan.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 20
Kesalahan yang sering terjadi adalah penulisan pernyataan if dengan diakhiri dengan semicolons (;) misalnya : if (a > b); ekspresi1; dengan adanya “;” setelah pengujian kondisi itu, maka akan dianggap sebagai akhir dari sebuah ekspresi sehingga baris expresi1 akan selalu dijalankan tanpa memandang hasil pengujian kondisi. Pernyatan if-else juga dapat nested yaitu berada dalam pernyataan if-else yang lain. Contoh : int a = 100; if (a > 0) { if (a > 100) printf(“a adalah besar\n”); else printf(“a adalah sedang\n”); }
Pengujian kondisi dengan switch Jika pengujian melibatkan banyak kondisi dengan tipe integer (bilangan bulat), maka penggunaan if – else menjadi kurang efisien. C mempunyai kata kunci switch untuk melakukan pengujian dengan banyak kondisi dengan bentuk : switch(nilai_integer) { case nilai1 : ekspresi1; break; case nilai2 : ekspresi2; break; …… default : ekspresi_default; break; } Kata kunci break berguna untuk segera keluar dari blok switch sehingga begitu setiap ekspresi dijalankan, maka kontrol akan dipindahkan keluar switch atau dengan kata lain untuk menjamin hanya satu ekspresi saja yang dijalankan. default berperan seperti else yaitu sebagai alternatif dari suatu kondisi yang tidak dipenuhi.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 21 Namun ada saatnya dimana break tidak digunakan, misalnya untuk menjalankan ekspresi yang sama untuk beberapa kondisi. Contoh penggunaan switch : LISTING 4.1. Switch.C #include<stdio.h> int main(void) { char n = 'E'; printf("Masukkan sebuah nilai : "); scanf("%c",&n); printf("%c",n); switch(n) { case 'A':case 'a': printf("Nilai antara 80-100\n"); break; case 'B':case 'b': printf("Nilai antara 70-80\n"); break; case 'C':case 'c': printf("Nilai antara 60-70\n"); break; case 'D':case 'd': printf("Nilai kurang dari 60\n"); break; default : printf("Kriteria nilai tidak ada\n"); } return 0; }
Perhatikan baris yang mengandung : case ‘A’:case ‘a’: printf("Nilai antara 80-100\n"); break;
Pernyataan itu dapat ditulis dengan : case ‘A’: case ‘a’: printf("Nilai antara 80-100\n"); break;
Dalam program ini berguna agar kita dapat memasukkan huruf besar ataupun huruf kecil (case insensitive).
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 22
while Seringkali dibutuhkan untuk melaksanakan tugas berulang sampai suatu kondisi tertentu tercapai (termination criteria). C memiliki tiga jenis loop atau iterasi atau perulangan, dan yang paling sederhana adalah while-do yang memiliki bentuk : while (kondisi) ekspresi; atau while (kondisi) { ekspresi; } Selama kondisi bernilai benar, maka ekspresi akan dijalankan terus menerus. Biasanya ekspresi itu sendiri mengandung perintah untuk membuat kondisi menjadi false sehingga loop berhenti. Contoh : int a = 10; printf(“mulai\n”); while (a > 0) { printf(“a = %i\n”,a--); } printf(“akhir\n”);
Program ini akan mencetak nilai a terus menerus sampai nilai a sama dengan 0 yang tidak akan ditampilkan. Seperti hal lainnya dalam C, kesalahan umum dalam penulisan loop ini misalnya dengan meletakkan semicolon (;) setelah while: while (kondisi); ekspresi; yang menyebabkan program akan terjebak dalam menjalankan loop tak berhingga (infinite loop) karena kondisi tidak pernah diperbaharui untuk menghentikan loop.
do-while Tidak seperti while yang mengevaluasi kondisi pada awal setiap iterasi, do-while akan melakukannya pada akhir setiap iterasi. Dengan kata lain paling tidak satu kali iterasi akan dilakukan. Contoh :
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 23 int a = -10; printf(“mulai\n”); do { printf(“a = %i\n”,a--); } while (a > 0); printf(“akhir\n”);
Program ini akan menjalankan perintah dalam blok { } sekali saja karena pada akhir iterasi pertama pengujian dilakukan yang menemukan bahwa a memang kurang dari 0 dan loop berhenti.
for Jenis loop ini memiliki bentuk : for (inisialisasi;kondisi;bagian_update) ekspresi; Yang perlu diperhatikan adalah tanda semicolon (;) yang memisahkan masingmasing bagian. Contoh : LISTING 4.2. Loop.C #include<stdio.h> #include<math.h> #define PI 3.14 int main(void) { double sudut; for (sudut = 0.0; sudut < PI;sudut += 0.5) printf(“Sudut %.2lf = %.2lf\n”,sudut,sin(sudut)); }
return 0;
Tidak seperti bahasa Pascal atau Ada yang hanya memungkinkan langkah penambahan atau pengurangan variabel loop (sudut) hanya sebesar satu, C memungkinkan semua jangkauan bilangan. Header file math.h diperlukan dalam program ini untuk menghitung nilai sinus dari sebuah sudut dalam radian. Perlu juga diketahui bahwa loop ini dapat melakukan inisialisasi lebih dari satu yang dipisahkan dengan koma (,) misalnya : int a,b,c; for (a = 0,b = 1,c = 20;a < 10;a++,b++,c--)
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 24 Atau bagian inisialisasi dan bagian update tidak mengandung pernyataan sama sekali : int a = 0,b,c; for ( ; a < 10;)
atau tidak mengandung sama sekali for (;;)
programmer biasa menulisnya dengan bentuk : #define
EVER
;;
for (EVER) { … }
break Kata kunci ini dapat anda gunakan untuk keluar dari suatu loop terdekat. Contoh : int a = 0; for (;;) { printf(“Masukkan sebuah angka : “); if ((scanf(“%i”,&a)==1) && (a==0)) break; }
continue Berfungsi untuk menjalankan iterasi berikutnya walaupun eksekusi program belum mencapai akhir sebuah iterasi. Misalnya program untuk melewati bilangan dengan kelipatan 3 : int a; for (a = 1;a < =10;a++) { if (a % 3 == 0) continue; printf(“%i\n”,a); }
akan menghasilkan 1,2,4,5,7,8,10.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 25
5. FUNGSI Pada awal penulisan program, kita jarang berpikir untuk masalah efisiensi misalnya kita membuat sebuah program yang melakukan operasi matrik (perkalian, inverse dan sebagainya), kita akan langsung menuliskan algoritma yang sesuai dengan program kita berjalan sesuai dengan rencana yaitu program untuk operasi matrik. Suatu saat kita diharuskan menambahkan fasilitas dalam program kita sehingga bisa melakukan penyelesaian persamaan linear. Kita tahu untuk menyelesaikan persamaan linear yang umum kita dapat menggunakan metode matrik. Masalah muncul karena kita telah membuat rutin-rutin untuk operasi matrik menjadi satu dengan program utama. Kita dapat melakukan dua hal untuk itu. Pertama kita dapat menduplikat rutin-rutin operasi matrik itu ke bagian lain dari program yang digunakan untuk menyelesaikan persamaan linear, jadi dua rutin yang identik akan ditulis dua kali dalam satu program. Kedua kita dapat mengorganisir rutin-rutin itu ke dalam bentuk yang disebut fungsi dan memanggil fungsi itu dengan parameter tertentu baik untuk melakukan operasi matrik atau penyelesaian persamaan linear, jadi kita hanya perlu sekali saja menuliskan rutin untuk operasi matrik. Pilihan kedua nampak lebih efisien ditinjau dari segi penulisan dan tentunya ukuran program. Untuk itu dalam bab ini kita akan membahas bagaimana fungsi itu dapat membuat program kita menjadi modular dan mudah dikembangkan. Kita sudah sering menggunakan fungsi seperti printf() yang dapat menerima masukan parameter yang tidak terbatas. Atau kita juga dapat membuat sebuah fungsi yang tidak menerima masukkan sama sekali misalnya dalam fungsi utama : int main(void)
Beberapa hal yang perlu diperhatikan dalam penulisan fungsi :
Nilai balik (return value) Jika sebuah fungsi menghasilkan nilai keluaran, maka nilai keluaran itu dideklarasikan dengan tipe data yang sesuai dan ditulis pertama misalnya int get_value(void);
Nama fungsi Penamaan fungsi harus unik (tidak boleh sama) yang membedakannya dengan fungsi lain dalam program.
Parameter Parameter adalah nilai yang kita lewatkan pada saat pemanggilan sebuah fungsi. Penulisan parameter harus diawali dengan tipe data dan diikuti dengan nama yang unik dengan parameter yang lain dalam satu fungsi.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 26 Masing-masing parameter dipisahkan dengan koma. Misalnya : int check_values(int parameter1, int parameter2);
Pemanggilan fungsi Fungsi dipanggil dengan menuliskan namanya dan diikuti dengan parameterparameter yang sesuai. Jika tidak menerima paramater, maka nama fungsi diakhiri dengan tanda kurung () Contoh berikut dengan asumsi fungsi get_value() sudah ada : int main(void) { int a,b; {fungsi tanpa parameter} a = get_value(); {dengan parameter} check_values(a,b); }
return 0;
Penulisan Prototipe Dalam C pembuatan fungsi diawali dengan penulisan prototipe atau deklarasi dan dilanjutkan dengan definisi. Prototipe menginformasikan compiler bagaimana fungsi ini digunakan dengan benar misalnya : int check_three_value(int,double, char);
Penulisan prototipe diakhiri dengan semicolon (;). Penulisan nama-nama parameter untuk prototipe adalah opsional dan diabaikan oleh compiler. Dengan bantuan prototipe ini, compiler akan menjamin fungsi yang dipanggil dilewatkan parameter dengan tipe yang benar. Karena pentingnya prototipe fungsi, maka kita mulai saat ini kita akan menganggap itu sebagai keharusan dalam pembuatan fungsi walaupun C sendiri menganggapnya opsional.
Penulisan definisi fungsi Setelah kita menuliskan prototipe, kita selanjutnya harus menuliskan fungsi itu sendiri yang biasa dikenal dengan definisi atau implementasi. Contoh :
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 27 LISTING 5.1. Fungsi.C #include <stdio.h> /* prototipe */ int is_negative(double); /* untuk menghitung luas segiempat */ double luas_segiempat(double,double); int main(void) { double P = 100,L = 10, luas; if (!is_negative(P) && !is_negative(L)) { luas = luas_segiempat(P,L); printf(“Luas = %.2lf\n”,luas); } else printf(“Nilai masukkan harus positif\n”); return 0; } /* definisi */ int is_negative(double value) { return value < 0; } double luas_segiempat(double panjang,double lebar) { return panjang * lebar; }
Perlu diingat bahwa semua variabel dalam fungsi adalah bersifat lokal dan hanya dapat digunakan oleh fungsi itu sendiri, jadi nama sebuah variabel lokal dalam suatu fungsi tidak akan konflik dengan nama yang sama dalam fungsi yang lain.
Lebih lanjut tentang pemanggilan fungsi Pada saat sebuah fungsi dipanggil, parameter-parameter yang dilewatkan akan dikopi sebelum digunakan atau dikenal dengan call by value. Dengan cara ini nampaknya sebuah fungsi tidak bisa memodifikasi sebuah variabel di luar fungsi. Pada bagian selanjutnya nanti yaitu pada topik pointer, kita akan membahas tentang melewatkan parameter yang berupa pointer sehingga kita dapat melakukan modifikasi terhadap variabel diluar fungsi.
C dan stack C menggunakan stack untuk menyimpan variabel lokal dan juga parameterparameter dalam pemanggilan fungsi. Pada saat pemanggilan fungsi proses – proses berikut akan dilakukan: Fungsi pemanggil akan menyimpan parameter-parameter ke dalam stack. Fungsi dipanggil. Fungsi yang dipanggil mengambil parameter-parameter dalam stack.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 28 Fungsi yang dipanggil mengalokasikan variabel-variabel lokal juga di dalam stack. Setelah proses dilakukan oleh fungsi yang dipanggil, semua variabel lokal akan dibersihkan dan kembali ke fungsi pemanggil (biasanya dengan memodifikasi nilai pada stack pointer misalnya register SP dalam processor Intel x86). Fungsi pemanggil membersihkan parameter-parameter yang sebelumnya disimpan dalam stack (poping up). Nilai balik disimpan dalam suatu register atau dalam stack. Anda dapat membayangkan stack itu sebagai sebuah tumpukkan buku. Setiap kita akan menambahkan buku ke tumpukan itu,kita akan meletakkannya di atas tumpukan. Demikian juga jika kita ingin mengambil salah satu buku maka kita harus mengambilnya mulai dari buku yang paling atas dari tumpukan itu. Jika kita mengambil buku yang ada ditengah-tengah maka tumpukan akan berantakan (last in first out atau LIFO). Dalam C setiap kita meletakkan sebuah variabel dalam stack, maka nilai itu akan diletakkan pada lokasi berikutnya dan penunjuk akan menunjuk ke lokasi berikutnya yang kosong (top of the stack). Secara umum C memiliki lokasi-lokasi penyimpanan yang dikelompokkan secara logis yaitu Code Segment, Stack Segment, Data Segment dan Heap (free store).
Code Segment Lokasi ini menyimpan semua kode program dan tentunya harus read-only.
Stack Segment Seperti telah disebutkan sebelumnya lokasi ini berguna untuk menyimpan variabel-variabel lokal dan parameter-parameter pada saat pemanggilan fungsi.
Data Segment Untuk menyimpan variabel-variabel global
Heap Lokasi ini untuk menyimpan data-data yang dialokasikan secara dinamis dengan fungsi-fungsi C malloc(), calloc(), realloc(), dan free().
Variabel qualifier Deklarasi sebuah variabel juga dapat diawali dengan menambahkan kata-kata kuci yang disebut qualifier yang memberikan arti lain kepada variabel itu. C memiliki beberapa qualifier untuk variabel.
auto Secara otomatis C akan menganggap sebuah variabel lokal sebagai auto jika kita tidak secara eksplisit menuliskannya yang sama dengan variabel dalam stack.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 29
static Walaupun kita mendeklarasikan variabel dalam sebuah fungsi (variabel lokal) namun jika kita awali dengan kata kunci static, maka variabel ini akan dialokasikan di data segment dan akan tetap berada di sana selama program berjalan. Variabel static dalam fungsi akan diinisialisasi sekali pada saat fungsi pertama kali dipanggil.
register Dengan kata kunci ini, kita menginstruksikan compiler untuk menggunakan register CPU untuk meletakkan variabel-variabel tertentu. Dengan dikembangkannya optimized compiler, kata kunci ini hampir tidak berpengaruh sama sekali karena compiler biasanya lebih bisa membuat kode program yang efisien dari pada secara manual. Untuk sebagian besar kegiatan pemrograman dengan C, anda tidak perlu mengetahui terlalu detail tentang peta memori yang digunakan, namun dengan memahami ini anda dapat memahami C dengan lebih baik.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 30
6. POINTER C kadang-kadang dikatakan sebagai high level assembly. Hal itu masuk akal karena pada awalnya C dirancang untuk memudahkan pemrograman yang sebelumnya menggunakan assembly sehingga C akhirnya dibuat sebagai abstraksi dari bahasa assembly, misalnya dalam hal indirection yang dalam C diimplementasikan dengan pointer yaitu sebuah variabel yang menyimpan alamat dari variabel atau lokasi data yang lain. Pointer seringkali dianggap salah satu topik yang paling sulit bagi pemula dalam C.
Deklarasi Pointer Pointer dalam C dideklarasikan sebagai : type *variabel [= initialisasi]; misalnya int n = 0; int * pn = &n;
Yang mendeklarasikan sebuah variabel n dengan tipe integer dan sebuah variabel dengan tipe pointer ke integer dengan nama pn yang diinisialisasi dengan alamat variabel n. Pointer ke suatu tipe ditandai dengan *, sehingga int *pn berarti pointer ke integer. Penempatan * sering menjadi perdebatan yang pada akhirnya menjadi masalah preferensi atau pilihan saja: int* pn,x; int *pn,x;
Bentuk yang pertama sering disalahartikan dengan melihat bahwa pn dan x adalah pointer ke integer namun pada kenyataannya hanya pn saja yang bertipe pointer sedangkan x adalah dengan tipe integer. Disinilah kerancuan muncul sehingga bentuk kedua lebih sering digunakan karena tanda pointer * ditulis berdekatan dengan variabel yang dimaksudkan sebagai pointer, sehingga lebih mudah untuk melihat bahwa pn adalah tipe pointer sedangkan x bukan. Dengan deklarasi ini kita dapat memanipulasi variabel n dengan menggunakan pn, misalnya : *pn = 20;
Perhatikan tanda * dalam pernyataan ini berarti dereference atau dapat diartikan sebagai nilai yang disimpan pada alamat yang berada pada pn. Atau dengan kata lain *pn berarti merujuk ke nilai yang disimpan pada alamat yang disimpan di pn. Kesalahan yang sering dilakukan dalam operasi pointer adalah dalam assignment (dengan operator = ).
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 31 int x1 = 12,x2 = 20; int *p1 = &x1; int *p2 = &x2;
Untuk memudahkan ilustrasi, kita akan mengandaikan x1 dan x2 secara berturutturut berada dalam memori dengan alamat : 0xFFF4 dan 0xFFF2. Karena pointer juga adalah variabel maka sudah tentu menempati suatu lokasi memori dan juga memiliki alamat, namun dalam ilustrasi ini kita tidak menganggap perlu untuk mengetahui alamat dari suatu pointer. p1
x1
FFF4
12
p2
x2
FFF2
20
Alamat : FFF4
Alamat : FFF0
Dari gambar dapat dilihat p1 dan p2 setelah diinisialisasi masing-masing dengan alamat x1 dan x2 dengan menggunakan operator &. Misalnya setelah deklarasi kita bermaksud untuk membuat x1 menjadi nilai x2 yaitu 20 dengan cara : p1 = p2;
Walaupun kita mendapatkan nilai 20 untuk *p1, namun yang kita lakukan sebenarnya adalah membuat p1 menunjuk ke lokasi yang sama dengan yang ditunjuk p2 yaitu ke x2 sehingga jika kita bermaksud mengubah nilai x1 dengan p1 : *p1 = 2;
maka kita tidak akan mengubah nilai x1, namun x2 ! Ilustrasi untuk pointer assignment (p1 = p2) dapat dilihat pada gambar berikut :
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 32
p1
x1
FFF0
12
p2
x2
FFF2
20
Alamat : FFF4
Alamat : FFF0
Inisialisasi Pointer Operator & dalam inisialisasi ini berarti mengambil alamat dari operand dalam hal ini alamat dari variabel n. Inisialisasi ini sangat penting karena pointer sebelum digunakan harus menunjuk ke lokasi memori yang valid kalau tidak maka program kita dapat melakukan kesalahan yang fatal yang biasa dikenal dengan access violation error. Misalnya : int *pn; *pn = 12; // fatal error !!
C juga mendeklarasikan konstanta untuk menyatakan sebuah pointer tidak valid atau tidak menunjuk ke manapun yaitu konstanta NULL yang perlu digunakan untuk inisialisasi pointer jika tidak segera digunakan. Agar program menjadi “tangguh”, kita harus sedapat mungkin memeriksa pointer agar tidak NULL sebelum digunakan : int *pn = NULL; if (pn != NULL) { /* aman menggunakan pn */ } else { /* pointer NULL */ }
Melewatkan parameter dengan pointer Pada bab sebelumnya kita menjelaskan tentang fungsi dalam C. Dalam bab ini kita akan menggunakan fungsi untuk menukar nilai dua buah variabel yang dilewatkan ke fungsi yang biasanya disebut swap. Berikut adalah contoh program untuk mengilustrasikan prosesnya :
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 33 LISTING 6.1. Swap1.C #include <stdio.h> /* prototipe fungsi swap */ void swap(int,int); int main(void) { int a = 10,b = 5; printf(“Before swap a : %d b : %d\n”,a,b); swap(a,b); printf(“After swap a : %d b : %d\n”,a,b); return 0; } void swap(int v1,int v2) { int tmp = v1; v1 = v2; v2 = tmp; }
Setelah dijalankan, program menghasilkan : Before swap a : 10 b : 5 After swap a : 10 b : 5
yang tidak sesuai dengan tujuan program kita. Hal itu disebabkan karena fungsi swap() melewatkan variabel ke dalam fungsi dengan nilai (by value) jadi pada saat kita melewatkan a dan b, fungsi akan mengcopy nilai-nilai itu sehingga pada saat kita berubah nilainya, nilai pada variabel diluarnya tetap. Agar kita dapat mengubah atau memodifikasi nilai di luar fungsi maka kita harus menggunakan pointer yang akan melewatkan alamat dari variabel di luar fungsi. Dengan mekanisme ini, kita dapat melewatkan apa saja ke dalam fungsi secara efisien karena ukuran pointer selalu sama untuk masing-masing sistem operasi. Kembali ke program swap, kita harus memodifikasi fungsi swap() dengan menggunakan pointer untuk melewatkan nilai ke dalam fungsi. Program setelah dimodifikasi menjadi : LISTING 6.2. Swap2.C #include <stdio.h> /* prototipe fungsi swap */ void swap(int*,int*); int main(void) { int a = 10,b = 5; printf(“Before swap a : %d b : %d\n”,a,b); swap(&a,&b); /* Perhatikan tanda & untuk mengambil alamat variabel */ printf(“After swap a : %d b : %d\n”,a,b);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 34
}
return 0;
void swap(int *v1,int *v2) { int tmp = *v1; *v1 = *v2; *v2 = tmp; }
Dengan program kali ini kita dapat menukar nilai a dan b yang menghasilkan : Before swap a : 10 b : 5 After swap a : 5 b : 10
Pointer ke data konstan Pada fungsi print_data() juga menggunakan kata kunci const untuk mengawali tipe data dalam parameternya. const di sini berfungsi untuk mencegah data yang dilewatkan dalam fungsi dimodifikasi atau diubah. Dengan const ini, jika kita secara tidak sengaja mengubah nilai parameter dalam fungsi maka compiler akan mengindikasikan sebagai kesalahan (compiler error) void print_data(const double *data) { /* *data = 100; compiler error !!!*/ printf(“Data : %lf\n”,data); }
Fasilitas ini sangat penting untuk mengisolasi suatu proses yang dilakukan oleh sebuah fungsi dengan pemanggil jika kita tidak menghendaki modifikasi data. Namun jika kita memang menghendaki fungsi dapat memodifikasi data luar seperti fungsi swap(), maka kita harus menghilangkan kata kunci const dalam paramaternya.
Pointer ke pointer C mengijinkan kita membuat pointer ke tipe apa saja termasuk bentuk yang aneh seperti : int **pp;
yang mendeklarasikan pp sebagai pointer ke pointer ke integer. Bentuk ini pada dasarnya adalah jika kita hendak memodifikasi isi dari sebuah pointer dengan melewatkannya ke dalam fungsi. Kita juga dapat mendeklarasikan sekaligus menginisialisasi. int x = 12; int *p = &x; int **pp = &x;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 35
Jika digambarkan akan nampak sebagai : x
12
Alamat : FFF4
p
FFF4
Alamat : FFF2
pp
FFF2
Alamat : FFF0
Kalau anda masih bertanya-tanya di mana anda akan menggunakan bentuk yang satu ini, maka kami yakinkan anda seiring dengan pengalaman anda membuat program dan menyelesaikan banyak permasalahan-permasalahan anda akan mengetahui sendiri kapan bentuk ini tidak nampak aneh lagi namun menjadi suatu kebutuhan bagi anda. Sebagai satu informasi bagi anda yang penasaran, bentuk ini sangat sering digunakan dalam pemrograman COM yang berguna untuk melakukan binding (koneksi antara antarmuka atau interface dengan implementasinya), dimana yang dilewatkan adalah alamat dari pointer ke suatu interface sehingga isi dari pointer itu sendiri yang akan diubah, perhatikan penggalan berikut : ISuatuInterface* pi; pOtherInterface->QueryInterface(SOME_ID,&pi);
Dengan asumsi pOtherInterface sudah valid dan QueryInterface() berhasil maka pi akan menunjuk ke lokasi implementasi interface dengan identitas SOME_ID. Pada bagian struktur data dinamis dengan linked list akan diilustrasikan bagaimana penggunaan tipe ** ini.
Pointer ke fungsi (function pointer) Selain tipe data yang telah disebutkan sebelumnya, kit juga dapat mendeklarasikan pointer ke sebuah fungsi dengan prototipe tertentu : int (*pf)(const int);
Bentuk ini mendeklarasikan pf sebagai pointer ke fungsi yang memiliki parameter konstanta dengan tipe integer dan memberikan nilai balik integer. Perhatikan tanda dereference * sebelum pf, jika ditulis tanpa tanda kurung maka akan menjadi : int *pf(const int);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 36 yang berarti fungsi biasa dengan parameter konstanta integer dan nilai balik pointer ke integer. Jadi tanda kurung itu adalah keharusan untuk membedakannya dengan deklarasi fungsi reguler. Sebelum menggunakan pointer ke fungsi ini, terlebih dahulu harus diinisialisasi dengan alamat fungsi yang sesuai. LISTING 6.3. FuncPtr.C #include<stdio.h> /* prototipe */ int myfunc(const int d); int main(void) { int (*pf)(const int) = myfunc; /* deklarasi sekaligus inisialisasi */ (*pf)(12); /* penggunaan pointer ke fungsi */ return 0; } int myfunc(const int d) { return d*2; }
Kalau bentuk pointer ke fungsi yang kompleks, kita dapat menggunakan typedef untuk memudahkan penulisan : typedef int (*PF)(const int);
Penggunaannya menjadi lebih mudah : PF pf = myfunc; (*pf)(12);
Hal yang menarik dari pointer ke fungsi ini adalah kita dapat membuat array dari pointer ke fungsi dengan bentuk : Dan selanjutnya digunakan dengan cara : int (*pf[5])(const int); pf[0] = myfunc; … … for (i = 0; i < 5;i++) (*pf[i])(i);
Dengan memahami pointer yang satu ini, kita dapat membuat program yang dinamis dan table-driven dengan mendeklarasikan beberapa pointer ke fungsi dalam sebuah tabel atau array dan selanjutnya dipanggil dengan bentuk seperti penggunaan pointer.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 37
Pointer ke fungsi ini sering digunakan untuk sistem dengan callback function yaitu sebuah fungsi akan dipanggil oleh fungsi yang lain tanpa perlu mengetahui implementasinya. Jika kita ingin mengubah perilaku sistemnya kita tinggal memodifikasi fungsi yang dipanggil saja. Contoh berikut mengilustrasikan hal itu : LISTING 6.4. Callback.C #include<stdio.h> typedef int (*FP)(const int); void display_numbers(int start,int stop,FP); int filter(const int num); int main(void) { display_numbers(0,20,filter); return 0; } void display_numbers(int start,int stop,FP fp) { int i; for (i = start;i <= stop;i++) { if (fp == NULL) printf("%i\n",i); else else if ((*fp)(i)) printf("%i\n",i); } } int filter(const int num) { return (num % 3 == 0); }
Program ini mendeklarasikan pointer ke fungsi : typedef int (*FP)(const int);
Fungsi display_numbers() akan menampilkan bilangan integer mulai dari nilai yang dilewatkan dalam parameter start sampai stop. Dan parameter ke tiga adalah sebuah callback function yang akan dipanggil untuk memberikan sebuah keputusan apakah sebuah bilangan dicetak atau tidak. Pada contoh ini bilangan nol dan kelipatan tiga saja yang dicetak sesuai dengan fungsi callback (filter()) : return (num % 3 == 0);
Fungsi display_numbers() dipanggil dalam main(): display_numbers(0,20,filter);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 38 yang akan mencetak bilangan nol dan semua bilangan kelipatan 3 mulai antara 0 sampai dengan 20. Dari program ini dapat dilihat bahwa pembandingan dilakukan dengan callback function, sehingga jika kita ingin menampilkan bilangan yang lain kita hanya perlu memodifikasi fungsi filter() saja. Pointer ke fungsi ini secara umum digunakan untuk mengisolasi antara tugastugas atau menyediakan sebuah coupling antara dua buah implementasi sistem yang memudahkan untuk memodifikasi masing-masing sistem tanpa perlu mengubah bentuk penggunaannya.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 39
7. ARRAY Program sering ditulis untuk memanipulasi kumpulan data dengan tipe yang sama misalnya dalam perhitungan statistik dan matrik. Dalam bahasa C kumpulan data itu disebut array.
Deklarasi array Array dideklarasikan dengan menggunakan [ ] int prices[5];
Dengan deklarasi itu, prices akan menunjuk ke kumpulan data dengan 5 item yang semuanya bertipe integer (int). Beberapa hal yang perlu diperhatikan tentang array : Nama array adalah pointer yang konstan (tidak dapat di-reassign) yang menyimpan alamat awal dari suatu kumpulan data. Item-item atau elemen-elemen dalam array harus mempunyai tipe data yang sama. Lokasi penyimpanan data di memori adalah kontinyu, jadi item pertama akan diikuti oleh item kedua dan seterusnya. Ukuran array adalah tetap dan tidak bisa diubah setelah deklarasi.
Inisialisasi array Deklarasi array dapat diikuti dengan inisialisasi misalnya : int prices[5] = {100,200,300,400,500}; double factors[] = {0.2,0.3,0.4}; unsigned int data[20] = {0}; long data[5] = {1,2};
mendeklarasikan array dari 5 tipe data integer dan diikuti dengan inisialisasi. factors adalah deklarasi dengan tidak menentukan jumlah elemen yaitu dengan tanda [ ]. Jumlah elemen dalam inisialisasi array itu yang menentukan ukuran array. data adalah bentuk ringkas dari deklarasi yang disertai dengan inisialisasi. Dengan bentuk ini semua elemen dalam array akan diisi dengan nol.Bentuk ini adalah cara singkat untuk menginisialisasi semua item menjadi nol dan hanya berlaku untuk inisialisasi dengan nol saja. data mendeklarasikan array dari 5 long dan dua elemen pertama diinisialisasi dengan nilai 1 dan 2 sedangkan yang lain dengan nol. prices
Mengakses elemen array Masing-masing elemen dalam array dapat diakses dengan menggunakan bilangan positif mulai dari 0. Contoh : int a[5] = {1,2,3,4,5};
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 40 printf(“Data ke 1 : %d\n”,a[0]);
Perhatikan kembali bahwa index array dalam C selalu mulai dari nol, jadi elemen pertama adalah elemen dengan index nol. Dan yang perlu diperhatikan adalah bahwa C tidak akan melakukan bound-checking atau pengujian terhadap index yang diterapkan apakah termasuk dalam jangkauan array atau tidak sehingga kita harus berhati-hati dalam mengakses elemen dalam array. Mengakses elemen array dengan index adalah salah satu cara yang bisa dilakukan. Seperti telah disebutkan bahwa nama array adalah pointer ke elemen pertama atau elemen dengan index nol, jadi kita juga mempunyai alternatif untuk mengakses elemen dalam array : int a[5] = {1,2,3,4,5}; int *p; p = a; printf(“%d\n”,*p ); ++p; printf(“%d\n”,*p );
Deklarasi itu dapat dijelaskan dengan gambar : p = a;
p
1
2
3
4
5
2
3
4
5
a
Selanjutnya ++p;
p
1 a
Jadi dengan pointer kita dapat mengakses elemen dalam array dengan bantuan operator ++ atau --. Namun nilai pertambahan dari operator ++ atau – adalah sesuai dengan tipe data yang ditunjuk oleh pointer. Dalam hal ini tipe data yang ditunjuk adalah int jadi besar perpindahan setiap pemanggilan operator ++ adalah sebesar ukuran integer. Operasi ini biasa disebut dengan pointer arithmetic. Yang perlu diperhatikan lagi adalah array tidak dapat di-assign dengan operator = : int a[5]; int b[5];
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 41 Deklarasi ini menyebabkan compiler error karena a dan b adalah pointer yang konstan.
Array sebagai paramater fungsi Karena array pada dasarnya adalah pointer, maka array juga dapat digunakan sebagai parameter fungsi dan dapat juga ditukar dengan bentuk pointer. LISTING 7.1. ArrArgs.C #include<stdio.h> /* prototipe */ void print_array(int[],int); int main(void) { int a[5] = {1,2,3,4,5}; print_array(a,sizeof(a)/sizeof(s[0])); return 0; } void print_array(int data[],int size) { int i; for (i = 0;i < size;i++) printf(“Elemen ke %d : %d\n”,i,data[i]); }
Program ini akan mencetak ke layar semua elemen. Pemanggilan fungsi print_array() disertai dengan sizeof(a)/sizeof(a[0])
ini adalah untuk menjamin fungsi tidak mengakses di luar jangkauan atau kapasitas array yaitu ukuran total yang dibutuhkan array dibagi dengan ukuran satu elemen. Ini adalah salah satu cara yang portable. Program ini juga dapat dimodifikasi dengan menggunakan pointer. Kita hanya perlu mengubah prototipe dan header dari fungsi print_array() dengan mengganti array dengan pointer : Pada prototipe : void print_array(int*,int);
Pada implementasinya : void print_array(int *data,int size) { … }
Selanjutnya program dapat dijalankan seperti semula.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 42
Array “Multidimensional” C tidak menyediakan array dimensional, namun kita dapat membuat array dari array yang nampak seperti array multidimensi. Contoh : int a[5][5]; int i,j; for (i = 0; i< 5; i++) for (j = 0;j < 5; j++) { a[i][j] = i * j; }
dideklarasikan sebagai array dari 5 array 5 integer dan pada baris selanjutnya diinisialisasi dengan nilai tertentu dalam sebuah iterasi. Dapat dilihat pengaksesan array dari array juga sangat konsisten dengan array biasanya yaitu dengan memandang setiap array memiliki index yang dimulai dari nol, jadi jika int a[5] maka a mempunyai elemen sebanyak 5 dan index untuk mengakses elemennya mulai dari 0 sampai dengan 4. a
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 43
8. STRING C tidak mempunyai tipe data string seperti bahasa Pascal atau Basic, namun C menggunakan array dengan tipe char sebagai gantinya. C menggunakan karakter khusus untuk menandai akhir dari string yaitu karakter nol (‘\0’).
Deklarasi Beberapa bentuk deklarasi dari array tipe char : char char char char
data1[6] = {‘H’,’e’,’l’,’l ‘,’o’,’\0’}; data2[6] = “There”; data3[] = “Learn C”; data4[7] = “No NULL”;
adalah deklarasi string yang mengharuskan kita menambahkan karakter ‘\0’ pada akhir array. Kalau kita tidak menyertakan karakter null, maka data1 bukan merupakan string tetapi array tipe char. data2 adalah deklarasi string dengan maksimum jumlah karakter adalah 5 sedangkan karakter ke 6 secara otomatis diisi dengan karakter null (‘\0’) oleh compiler. data3 adalah deklarasi string dengan tidak menentukan panjangnya. Dalam hal ini compiler juga akan menambahkan karakter null. data4 bukan string karena ukuran array adalah 7 dan semua terisi dengan karakter non null, sehingga akan menjadi array tipe char. data1
Mencetak String Fungsi-fungsi standar seperti printf() dapat digunakan untuk mencetak string ke layar dengan menggunakan format %s. char str[6] = “Hello”; printf(“%s”,str);
Kita juga dapat mencetak string dengan mengakses setiap karakter dan mencetak satu persatu ke layar dengan spesifikasi format %c : int i; char str[6] = “Hello”; while(str[i] != ‘\0’) { printf(“%c”,str[i++]); }
String Assignment String tidak dapat di-assignment atau dikopi dengan operator = karena nama string adalah seperti array yang merupakan pointer konstan. C menyediakan fungsi standar untuk memudahkan meng-kopi dari satu string ke string yang lain. Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 44
char * strcpy(char * dest,const char * src); Fungsi ini dapat meng-kopi string dari parameter yang dinamai src ke parameter yang dinamai dest. strcpy() melakukan pengkopian string tanpa memeriksa ukuran array dest, jadi kemungkinan akan overflow jika ukuran dest kurang mencukupi. char buffer[10]; strcpy(buffer,”Hello”);/* OK */ strcpy(buffer,”Hello there, how are you ?”);/* overflow – not OK */
char * strncpy(char * dest,const char * src,size_t count); Fungsi ini lebih aman dari strcpy() karena juga memperhitungkan jumlah maksimal karakter yang dikopi. Fungsi ini akan terus melakukan pengkopian karakter sampai ditemukan karakter null atau sebanyak maksimum karakter yang ditentukan. Jika strncpy() lebih dulu mencapai jumlah maksimum, maka karakter null tidak akan disertakan. Untuk itu kita harus menambahkannya secara manual. char buffer[10]; strncpy(buffer,”Hello”,9);/* OK */ strncpy(buffer,”Hello there, how are you ?”,9);/* maksimal 10 karakter*/ buffer[9] = ‘\0’; /* karakter ke 9 diganti dengan null – ‘\0’ */
Manipulasi string Kita dapat melakukan banyak hal dengan string misalnya kita dapat mengetahui panjang suatu string, mencari karakter tertentu, membandingkan dua buah string,serta mencari substring. Fungsi-fungsi ini dideklarasikan dalam header file string.h
size_t strlen(const char* str); Fungsi ini digunakan untuk menentukan panjang sebuah string tanpa termasuk karakter null. Contoh : strlen(“Hello”);/* menghasilkan 5 */
char * strrev(char * str); Fungsi ini berguna untuk membalik semua urutan karakter dalam string str kecuali karakter null. Contoh : char buffer[20] = “Hello”; strrev(buffer); /* buffer menjadi = olleH */
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 45
char *strcat(char * dest, const char * src); Fungsi ini digunakan untuk menambahkan string ke dalam buffer string yang lain. Contoh : char buffer[80 = “Hello “; strcat(buffer,” C!”); /* menghasilkan Hello C! */
char * strchr(const char* str,int c); Fungsi ini digunakan untuk mencari sebuah karakter pertama dalam string yang sama dengan karakter dalam parameter c dan memberikan nilai balik berupa pointer ke karakter yang ditemukan. Contoh : char buffer[80] = “C Programming Language”; printf(“%s”,strchr(buffer,’L’)); /* menampilkan Language */
Untuk mencari karakter terakhir, dapat menggunakan strrchr().
int strcmp(const char* str1,const char* str2); Dalam C kita tidak dapat membandingkan dua buah string dengan menggunakan operator == karena dengan cara itu yang kita bandingkan sebenarnya adalah lokasi memori atau alamat dari variabel itu. C standard memiliki fungsi untuk membandingkan dua buah string str1 dan str2 dengan memperhitungkan huruf kecil atau besar (case sensitive) sesuai dengan urutannya dalam abjad yang akan menghasilkan nilai balik: Negatif jika str1 < str2 menurut abjad. Nol jika str1 = str2. Positif jika str1 > str2 menurut abjad. Contoh : strcmp(“Crash”,”Course”); /* Hasilnya positif */
Untuk membandingkan dua buah string tanpa memandang case atau case insensitive, dapat menggunakan fungsi stricmp() dengan paramater yang sama.
char *strstr(const char * str,const char * sub); Fungsi ini berguna untuk mencari substring dalam sebuah string dan jika berhasil memberikan pointer ke awal substring dan null jika gagal. Pembandingan yang dilakukan adalah case sensitive. Contoh : char buffer[80] = “This is my first time to learn C”; char * psub; psub = strstr(buffer,”time”); if (psub != NULL)
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 46 {
printf(“Substring : %s\n”,p);
}
akan mencetak hasil : time to learn C
size_t strspn(const char * str,const char * cset); Fungsi ini berguna untuk menentukan lokasi atau index karakter pertama dalam str yang tidak terdapat dalam cset. Contoh : char cset = “1234567890”; char str[20] = “123456h56”; size_t pos; pos = strspn(str,cset); printf(“Not match at : %c”,pos);
akan mencetak nilai 6 yaitu posisi karakter h.
char *strtok(char * str,const char * delim); Fungsi ini berguna untuk mengekstrak substring-substring dalam string yang dipisahkan oleh karakter-karakter dalam parameter delim. Fungsi ini dapat digunakan sebagai tokenizer dalam pembuatan compiler. Penggunaan fungsi ini adalah dengan melewatkan pointer ke suatu buffer yang mengandung string str dan parameter delim yang sudah diinisialisasi dengan karakter-karakter pemisah antara substring. Pada pemanggilan berikutnya, lewatkan NULL ke parameter str, maka akan diperoleh substring-substring berikutnya sampai memberikan nilai balik NULL. Contoh : char delim = “ \t\n”; /* pemisah : spasi, tab atau karakter 13 */ char buffer[80] = “This is my first time to learn C”; char * token; token = strtok(buffer,delim); while(token != NULL) { printf(“%s\n”,token); token = strtok(NULL,delim); }
Akan menghasilkan : This is my first time to learn C
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 47 Untuk fungsi-fungsi manipulasi string yang lain dapat dilihat pada referensi standar C atau anda juga dapat menggunakan yang diserta oleh pembuat compiler (compiler vendor) yang biasanya jumlahnya sangat banyak serta dengan dokumentasi yang jelas.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 48
9. STRUKTUR Pada bab sebelumnya kita telah membahas bagaimana array dapat menyimpan kumpulan data dengan tipe yang sama. C juga memiliki bentuk khusus yang memungkinkan kita mengelompokkan beberapa data dengan berbagai tipe data ke dalam satu unit data yang disebut struktur (struct). Bentuk struct ini biasa juga disebut user-defined type karena terserah pada pemrogram untuk menentukan jenis data apa saja yang ingin disimpan dalam sebuah struct. C bahkan mengijinkan untuk membuat struktur dalam struktur.
Deklarasi struct tagStruct { tipe member; … }; Misalnya : struct People { int nAge; char name[20]; };
yang mendeklarasikan tipe data People dengan isi atau member berupa data int dan array char.
Penggunaan struktur Deklarasi struktur atau struct itu biasanya disebut template atau “blue print” yang berguna bagi compiler untuk membuat bentuk nyatanya yang disebut instance yang secara harfiah diartikan sebagai “contoh”. Berawal dari kata instance itu selanjutnya dalam literatur-literatur komputer banyak menggunakan bentuk kata kerja dari instance yang menjelaskan proses membuat instance dari template yaitu instantiate. Dalam bab ini kita akan menggunakan apa adanya karena kami belum menemukan kata yang sepadan adalam bahasa kita tanpa menimbulkan kebingungan. Sebelum dapat digunakan, struktur harus di-instantiate misalnya dengan mendeklarasikan variabel seperti biasanya dengan menambahkan kata struct di depan variabel yang bersangkutan misalnya : struct People worker; struct People student = {20,”Devi”};
Notasi dot (.) dapat digunakan untuk mengakses member dalam struktur : worker.nAge = 30;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 49 strcpy(worker.name,”David”);
Struktur dalam struktur Struktur juga dapat nested yaitu struktur yang lain terdapat dalam suatu struktur, misalnya contoh sebelumnya kita kembangkan dengan menambahkan alamat sebagai sebuah struktur dalam struktur People : struct Location { char phone[16]; char city[20]; }; struct People { int nAge; char name[20]; struct Location address; };
Untuk mengakses member-membernya dapat dilakukan dengan cara yang sama seperti sebelumnya dengan notasi dot misalnya : People worker; strcpy(worker.address.city,”Malang”);
Mengakses struktur dengan pointer Seperti tipe data lainnya, struktur juga bisa dimanipulasi dengan menggunakan pointer misalnya : People worker; People * pw = &worker; (*pw).nAge = 20;
Perhatikan bentuk (*pw).nAge, bentuk ini digunakan untuk mengakses member nAge dengan menggunakan pointer. C menyediakan cara yang lebih ringkas yaitu: pw->nAge = 20;
Bentuk ini selain ringkas juga sangat desktriptif karena berbentuk tanda panah yang dapat segera dipahami sebagai menunjuk ke suatu tempat.
Assignment antara struktur Kita telah membahas bagaimana isi array tidak dapat ditransfer atau diassign dengan operator =. Berbeda dengan array, struktur dapat menggunakan operator = untuk assignment.Jika struktur tersebut mengandung array maka isi array itu juga akan dikopi misalnya.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 50
People worker1,worker2; worker1 = worker2; /* isi worker 1 menjadi sama dengan worker2 */
Melewatkan parameter non-primitive data Seperti telah disebutkan bahwa pointer adalah tipe data yang menyimpan alamat variabel yang lain dan ukuran pointer adalah sama. Dengan mengetahui hal itu, kita dapat menggunakan pointer untuk menyimpan alamat data selain data primitive (int, float, double, dan sebagainya) atau melewatkan ke dalam sebuah fungsi. Misalnya : LISTING 9.1. Struct.C #include <stdio.h> typedef struct _mydata { int data1; double data2; }; /* prototipe */ void print_data(const _mydata*); int main(void) { _mydata data = {12,10.5}; print_data(&data); }
return 0;
void print_data(const _mydata *data) { printf(“Integer data : %d, Double data : %lf\n”,data->data1,data>data2); }
Variabel data yang bertipe _mydata dideklarasikan disertai inisialisasi. Kemudian dilewatkan ke fungsi print_data() dengan pointer yang selanjutnya akan mencetaknya ke layar.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 51
10. OPERASI FILE C mewarisi banyak model UNIX dalam menangani file, tentu saja karena UNIX dan C dapat dikatakan tumbuh bersama. Dalam UNIX semua operasi Input Output (I/O) selalu dilakukan pada file, dan file dipandang sebagai kumpulan bytes. Dalam C, sebelum bekerja dengan file harus diasosiasikan dengan stream. Stream adalah struktur data yang berfungsi sebagai buffer atau penampung sementara yang berada antara program dan file. Ini berguna untuk mengatasi masalah pengaksesan file yang berada di perangkat penyimpanan yang lebih lambat dari memori misalnya disk.
Stream Dalam C ada struktur yang bernama FILE yang berguna untuk menyimpan informasi tentang stream bagi file yang sedang diakses. Programmer tidak perlu mengetahui isi dari FILE ini untuk melakukan operasi file, kita cukup menganggapnya sebagai black box saja dan melewatkannya ke fungsi-fungsi yang menangani file IO. Setiap program C menyediakan stream yang telah didefinisikan yaitu stdaux, stderr, stdin, stdout dan stdprn. stdout berhubungan dengan penampilan ke layar, stdin berkenaan dengan masukan keyboard, stdaux berkenaan dengan perangkat misalnya Com1 port, stderr juga berkenaan dengan perangkat display untuk menampilkan pesan kesalahan. Dan stdprn adalah koneksi dengan pencetak atau printer.
File teks (text file) File text disimpan dengan berpedoman pada karakter ASCII yang menyimpan data berdasarkan karakter yang masing-masing berukuran satu byte dan diakhiri dengan karakter khusus yang disebut dengan end of file (EOF). File text dengan mudah dapat dimodifikasi dan dibaca. File dibuka dengan menggunakan fungsi FILE * fopen(const char * name,consth char * mode);
Contoh : LISTING 10.1. TextFile.C #include<stdio.h> int main(void) { FILE* in = fopen("c:\\autoexec.bat","r"); FILE* out= fopen("c:\\autoexec.old","w"); int ch; while((ch = fgetc(in)) != EOF) { fputc(ch,stdout); fputc(ch,out);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 52 }
}
fclose(out); fclose(in); return 0;
Program ini akan membuka file autoexec.bat dengan asumsi berada pada direktori c:\. Setelah program dibuka dan diasosiasikan dengan stream yang diwakili dengan variabel in dengan pointer ke tipe FILE. Disamping itu juga dibuka sebuah file untuk ditulisi untuk menduplikat file autoexec.bat menjadi file autoexec.old. Semua proses pembacaan dan penulisan dilakukan dalam sebuah iterasi dengan menggunakan while yang mengecek karakter yang dibaca dengan fungsi fgetc() tidak sama dengan karakter end of file (EOF) yang akan menyebabkan loop berhenti. Setiap karakter yang dibaca akan ditampilkan ke layar dan sekaligus ditulis ke file autoexec.old dengan fungsi fputc() dengan parameter kedua masing-masing stdout untuk ke layar dan out untuk ke file. Sebelum program keluar, semua file ditutup dengan fungsi fclose(). Fungsi fgetc() akan membaca setiap karakter dari stream dan pindah ke posisi karakter berikutnya dalam stream. memerlukan string sebagai parameter dengan nama mode yang ditentukan sesuai dengan tabel. fopen()
Mode “r” “w” “a” “r+” “w+” “a+”
Deskripsi Membuka file untuk dibaca saja dan file harus sudah ada. Membuka file baru, jika file sudah ada maka akan direset. Menambahkan data pada akhir file yang sudah ada. Membuka file untuk dibaca dan ditulisi dan file harus sudah ada. Membuka file baru untuk dibaca dan ditulisi, jika file sudah ada maka akan direset (dikosongkan). Membuka file yang sudah ada untuk dibaca dan ditulis.
Disamping mode diatas, ada juga mode opsional yaitu “t” dan “b” yang dapat ditambahkan pada mode dalam tabel yang berarti “text” dan “binary”. Kalau kita tidak menyertakan “b” dalam fopen(), maka akan dianggap sebagai “t” karena itu adalah nilai defaultnya.
Penanganan kesalahan (error handling) File yang dibuka dengan fungsi fopen() dapat menyebabkan kesalahan (error) yang dapat diperiksa dengan mengecek hasil keluarannya. LISTING 10.2. FOpen.C #include <stdio.h> int main(void) { FILE * in = fopen(“test.txt”,”r+);
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 53
if (in == NULL) { fprintf(stderr,”fopen failed !\n”); perror(“Error : “); return 1; } fclose(in); return 0; }
Fungsi perror() berfungsi untuk menampilkan pesan kesalahan operasi file dengan menambahkan string pada awal pesan pada parameternya. Yang perlu diperhatikan dalam penulisan nama file terutama yang mengandung direktori misalnya : C:\mydata\test.txt
jika kita melewatkannya dalam parameter fopen() : in = fopen(“C:\mydata\test.txt”,”r”);
maka kita akan mendapatkan bahwa in bernilai NULL yang berarti terjadi kesalahan pada fopen(), padahal kita sudah yakin bahwa file : C:\mydata\test.txt sudah ada sebelum pemanggilan. Kesalahan ini sering terjadi karena kita lupa bahwa C mempunyai escape sequence yang diawali dengan karakter “\”, jadi jika compiler menemukan karakter “\”, maka sebuah karakter yang mengikutinya akan dianggap sebagai satu unit seperti “\n”, “\t”, sehingga penulisan C:\mydata\test.txt akan membingungkan karena C memiliki karakter khusus untuk menampilkan karakter “\” yaitu dengan “\\”, sehingga penulisan yang benar adalah : in = fopen(“C:\\mydata\\test.txt”,”r”);
File biner (binary file) Berbeda dengan file text yang menyimpan data dalam bentuk karakter ASCII, file biner tidak melakukan translasi karakter, jadi misalnya bilangan 12.3 tidak akan disimpan dalam empat karakter (“1”,”2”,”.” dan “3”), tetapi dalam bytes yang mewakili bilangan itu sehingga menjadi efisien dan menghemat tempat. File biner juga memungkinkan kita melakukan pengaksesan secara acak dalam file dengan lebih mudah. Untuk bekeja dengan file biner, kita dapat menggunakan fungsi sebelumnya untuk membuka file dengan menambahkan karakter “b” pada parameter mode. LISTING 10.3. WBinFile.C #include<stdio.h> int main(void)
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 54 {
}
double pi = 3.14; FILE * out = fopen(“test.bin”,”wb”); if (out == NULL) { perror(“Error : “); return 1; } fwrite(&pi,sizeof(double),1,out); fclose(out); return 0;
Jika fopen() gagal, maka program sebaiknya keluar dan menampilkan pesan kesalahan yang terjadi dengan fungsi perror(). Jika fopen() berhasil fwrite() digunakan untuk menuliskan sebuah data dengan tipe double dengan fungsi fwrite() yang mempunya prototipe seperti : size_t fwrite(void * p,size_t size,size_t n,FILE * stream); p adalah pointer ke data yang ingin ditulis ke file. size adalah ukuran dari data itu. n adalah jumlah dari data yang ingin ditulis. stream adalah stream untuk file yang bersangkutan.
Untuk membaca data dari sebuah file biner, kita dapat melakukannya dengan fungsi fread() Contoh : LISTING 10.4. RBinFile.C #include<stdio.h> int main(void) { double dd = 0; FILE * in = fopen(“test.bin”,”rb”); if (out == NULL) { perror(“Error : “); return 1; } fread(&pi,sizeof(double),1,in); fclose(in); return 0; }
Parameter-parameter dari fungsi fread() sama dengan fwrite().
Pencarian dalam file biner (binary file) Kita dapat melakukan pencarian data tertentu dalam sebuah file biner dengan memindahkan file pointer ke lokasi tertentu dalam file dan kemudian
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 55 membacanya. Fungsi-fungsi yang dapat digunakan antara lain fseek(), ftell(), frewind(), fsetpos dan fgetpos(). Untuk mengilustrasikan penggunaan fungsi-fungsi ini kita akan membuat sebuah program sederhana untuk menyimpan nama-nama orang dengan alamat-masingmasing. Pada saat program dijalankan akan menampilkan tiga pilihan yaitu : 1. Memasukkan data 2. Mencari data berdasarkan identitas 3. Keluar program LISTING 10.5. SBinFile.C #include<stdio.h> typedef struct _data_orang { unsigned int id; char nama[20]; char alamat[20]; unsigned int umur; }; /* prototipe */ int tampilkan_pilihan(); void tampilkan_data(const _data_orang * data); int cari_data(FILE * stream,int id); void masukan_data(FILE * stream); int main(void) { int pilihan,id; FILE* stream = fopen("friend.dat","a+b"); if (stream == NULL) { perror("Error : "); return 1; } while ((pilihan = tampilkan_pilihan()) != 3) { switch(pilihan) { case 1 : masukan_data(stream); break; case 2 : printf("Masukkan ID : "); scanf("%i",&id); fflush(stdin); if (!cari_data(stream,id)) { printf("Data tidak ditemukan \n"); } break; } }
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 56 fclose(stream); return 0; } int tampilkan_pilihan() { int pilihan; printf("\nMenu\n"); printf("1. Memasukan Data\n"); printf("2. Mencari Data\n"); printf("3. Keluar\n"); printf("Pilih[1-3] : "); scanf("%i",&pilihan); printf("\n"); fflush(stdin); return pilihan; } void tampilkan_data(const _data_orang * data) { printf("\nData sudah ada... \n"); printf("ID\t: %d\n",data->id); printf("Nama\t: %s\n",data->nama); printf("Alamat\t: %s\n",data->alamat); printf("Umur\t: %i\n",data->umur); } void masukan_data(FILE * stream) { _data_orang data; printf("ID : "); scanf("%i",&data.id); fflush(stdin); if (!cari_data(stream,data.id)) { printf("Nama : "); gets(data.nama); fflush(stdin); printf("Alamat : "); gets(data.alamat); fflush(stdin); printf("Umur : "); scanf("%i",&data.umur); fflush(stdin); fwrite(&data,sizeof(_data_orang),1,stream); } } int cari_data(FILE * stream,int id) { int i,size,found = 0; _data_orang data; fseek(stream,0,SEEK_END); size = ftell(stream); rewind(stream); for (i = 0;i < size/sizeof(_data_orang);i++) { fread(&data,sizeof(_data_orang),1,stream); found = data.id == id;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 57
}
if (found) break; } if (found) tampilkan_data(&data); fseek(stream,0,SEEK_END); return found;
Program ini sangat sederhana yang terdiri dari empat fungsi pembantu int tampilkan_pilihan(); Fungsi ini berfungsi untuk menampilkan pilihan atau menu tentang proses yang akan dijalankan. void tampilkan_data(const _data_orang * data); Fungsi ini berfungsi untuk mencetak data struktur dengan tipe _data_orang ke layar. int cari_data(FILE * stream,int id); Fungsi ini berfungsi untuk mencari suatu data dengan id tertentu dan akan menhasilkan nilai balik bukan nol jika salah salah satu data ditemukan dan nol jika tidak. void masukan_data(FILE * stream); Fungsi ini akan meminta kita memasukkan data-data id, nama,alamat dan umur yang jika belum ada maka akan ditambahkan ke dalam file. Pada program utama (main()), sebuah stream dibuka dengan fopen() dengan mode “a+b” yang berarti mode untuk menambah file jika file itu sudah ada dan membuat file baru jika belum ada serta jenis file yang dibuat adalah jenis biner. Nampak dalam setiap selesai pemanggilan fungsi untuk menerima masukkan seperti scanf() atau gets() diikuti dengan fflush(). Hal ini perlu dilakukan untuk berjaga-jaga kalau kita salah memasukkan bentuk data tertentu misalnya kesalahan memasukkan bilangan. Karena semua yang diketikkan akan diletakkan dalam buffer yang akan dibaca oleh pemanggilan berikutnya. Tentuk saja hal ini tidak diinginkan, untuk itu perlu dipanggil fflush() untuk segera me-reset stream yang bersangkutan yang dalam hal ini adalah stdin. Cobalah untuk menjalankan program ini, dan coba kembangkan baik dalam penanganan kesalahan atau dalam tampilannya.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 58
11. MEMORI DINAMIS Pada bagian-bagian sebelumnya kita selalu mengandaikan bahwa jumlah variabel yang kita butuhkan dalam program selalu kita ketahui jumlahnya dengan pasti. Pada kenyataannya kita jarang sekali dapat menyelesaikan suatu permasalahan dengan asumsi itu. Misalnya kita tidak akan membatalkan program reservasi tiket kita hanya karena program kita dapat melayani jumlah tertentu. C menyediakan fasilitas untuk menentukan jumlah alokasi data atau memori yang dinamis yaitu yang dapat kita tentukan pada saat program sedang berjalan (run time). Dengan kemampuan ini, program kita akan menjadi fleksibel untuk mengantisipasi kebutuhan data dan juga program tidak harus mengalokasikan jumlah memori yang statis sebelum program dijalankan yang akan menjadi kurang efisien kalau pada saat berjalan hanya beberapa bagian data saja yang benar-benar digunakan.
Pointer dan Memori Dinamis Telah kita ketahui bahwa pointer menyimpan alamat dari suatu lokasi data yang lain. Dengan menggunakan pointer ini kita dapat menyimpan alamat awal dari blok memori yang kita buat dengan pemanggilan fungsi untuk pengalokasian memori dinamis standar yaitu malloc(), calloc(), realloc() dan free() yang dideklarasikan dalam header file malloc.h.
void * malloc(size_t n); Fungsi ini berfungsi untuk mengalokasikan blok memori sebanyak n bytes. Memori yang dialokasikan dengan malloc() tidak diinisialisasi, jadi akan berisi nilai-nilai acak. Contoh : double * pd = malloc(10*sizeof(double));
Jika malloc() berhasil (dengan memeriksa nilai keluarannya dengan NULL) maka pd akan menunjuk ke awal lokasi memori yang dapat menyimpan 10 tipe data double. Untuk menggunakan pd kita dapat menggunakan pointer arithmetic atau dengan bentuk seperti mengakses elemen array. Contoh : LISTING 11.1. Malloc.C #include<stdio.h> #include<malloc.h> int main(void) { double * p; unsigned int i,n;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 59
printf(“Jumlah array : “); scanf(“%u”,&n); /* Pengecekan NULL */ if ((p = malloc(n*sizeof(double))) == NULL) { fprintf(stderr,”Error alokasi memori dengan malloc!\n”); return 1; } /* akses lokasi memori seperti array */ for (i = 0;i < n;i++) { p[i] = i*i; } /* cetak isi memori */ for (i = 0;i < n;i++) { printf(“Data %u : %lf\n”,p[i]); } /* Memori harus dibebaskan */ free(p); return 0; }
void * calloc(size_t nelem, size_t elemsize); Pada dasarnya calloc() sama dengan malloc() hanya berbeda sedikit dalam bentuk pemanggilan dan dengan calloc() akan menginisialisasi blok memori dengan nol untuk tipe numerik dan karakter null jika tipe data string. Contoh pada malloc() dapat diganti dengan menggunakan calloc() hanya dengan mengganti perintah p = malloc(n* sizeof(double))
dengan p = calloc(n,sizeof(double))
akan mendapatkan hasil yang sama.
void * realloc(void * ptr, size_t n); Fungsi ini berfungsi untuk mengalokasikan kembali memori yang sudah dialokasikan sehingga ukurannya berubah. Misalnya sebuah array dinamis (memori dinamis) yang mengandung 10 double dan suatu saat kita ingin mengubahnya menjadi 20 dengan tetap mempertahankan 10 double yang sudah ada dalam memori.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 60 LISTING 11.2. Realloc.C #include<stdio.h> #include<malloc.h> int main(void) { double * p,*p_new; unsigned int i; p = calloc(10,sizeof(double)); if (p == NULL) { fprintf(stderr,”Error calloc !\n”); return 1; } /* re-alokasi */ p_new = realloc(p,20*sizeof(double)); if (p_new != NULL) p = p_new; else { fprintf(stderr,”Error re-alokasi !\n”); free(p);// p masih valid } free(p); return 0; }
Perhatikan baris : p_new = realloc(p,20*sizeof(double)); if (p_new != NULL) p = p_new; else { fprintf(stderr,”Error re-alokasi !\n”); free(p); }
Bentuk ini bisa juga diganti : p = realloc(p,20*sizeof(double));
Bentuk pertama lebih aman karena jika realloc() gagal mengalokasikan memori baru yang mencukupi maka akan memberikan nilai balik NULL yang akan di-assign ke p_new, namun p tetap tidak berubah, atau blok memori sebelumnya yang alamatnya disimpan dalam p tetap ada. Jika realloc() berhasil kita dengan aman dapat meng-assign p dengan p_new. Hal ini akan berbeda dengan bentuk kedua dimana jika gagal maka NULL akan disimpan langsung dalam p sehingga data sebelumnya akan hilang.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 61
void free(void * ptr); Fungsi ini berfungsi untuk mendealokasikan kembali memori yang sudah dialokasikan dengan malloc() atau calloc(). Penggunaannya dapat dilihat pada contoh-contoh malloc() dan calloc().
Lebih lanjut tentang realloc() Beberapa hal menarik dari realloc() adalah dapat menggantikan tugas-tugas yang dilakukan oleh fungsi malloc() dan free() p = malloc(n*sizeof(double));
dapat dilakukan juga dengan p = realloc(NULL,n*sizeof(double));
Dan bentuk free(p);
dapat diganti dengan realloc(p,0);
Fungsi realloc() jika dipanggil dengan NULL sebagai parameter pertamanya akan mengalokasikan memori baru sehingga dapat berfungsi seperti malloc(). Sedangkan jika parameter pertama dilewatkan variabel pointer ke suatu blok memori yang sudah dialokasikan sebelumnya dan parameter kedua dibuat nol, maka memori akan didealokasikan sehingga berperan seperti free().
Struktur data dinamis Pengalokasian memori dinamis dapat digunakan untuk membuat struktur data yang dinamis seperti linked list yang dapat menyimpan data dengan masingmasing elemen berupa struktur yang mempunyai member dengan tipe pointer yang merujuk ke struktur yang lain seperti gambar.
Data
Data
Data
Next
Next
Next
Dengan struktur data dinamis ini kita dapat mengalokasikan data secara bertahap tanpa mengalokasikan memori dalam jumlah besar dan tanpa memindahkan data. Contoh berikut menggambarkan singly linked list yaitu setiap elemen dalam list hanya menyimpan pointer ke elemen berikutnya saja. Jika anda memahami singly linked list, kami yakin anda dapat dengan mudah mengembangkannya menjadi doubly linked list.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 62
LISTING 11.3. SLList.C #include<stdio.h> #include<malloc.h> typedef struct _node { double data; _node* next; }node; /* prototipe */ node* new_item(double data); void insert_item(node** p,double data); void print_list(node* p); void free_list(node** head); int main(void) { node* head = NULL; double data; while (1) { printf("Masukkan data double : "); if ((scanf("%lf",&data) > 0)) { fflush(stdin); insert_item(&head,data); } else break; } printf("\nPrinting list...\n"); print_list(head); printf("\nFreeing items...\n"); free_list(&head); }
return 0;
node* new_item(double data) { node* tmp = (node*)malloc(sizeof(node)); tmp->data = data; tmp->next = NULL; return tmp; } void insert_item(node** p,double data) { node* tmp = NULL; if (p == NULL) *p = new_item(data); else { if (data <= (*p)->data) { tmp = *p;
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 63 *p = new_item(data); (*p)->next = tmp; } else insert_item(&(*p)->next,data);
} }
void print_list(node* p) { if (p == NULL) return; printf("Data : %lf\n",p->data); if (p->next != NULL) print_list(p->next); } void free_list(node** head) { static int i = 0; node* next = (*head)->next; // hanya satu item if (next == NULL && *head != NULL) { printf("Item %i\n",++i); free(*head); } while(next != NULL) { printf("Item %i\n",++i); next = (*head)->next; free(*head); *head = next; } }
Fungsi new_item() berfungsi untuk membuat sebuah tipe data node dengan fungsi malloc() dan sekaligus mengisi member data dengan nilai pada parameter dan next dengan NULL. Fungsi insert_item() memiliki parameter dengan pointer ke pointer tipe node (node**) yaitu p. Ini berguna untuk memodifikasi isi pointer dari dalam fungsi. Fungsi ini juga akan mengurutkan data yang dimasukkan dengan membandingkan dengan data yang dimiliki oleh parameter p. Jika lebih kecil atau sama maka item (tipe node) baru akan disisipkan sebelum data yang dirujuk oleh p. Jika lebih kecil maka akan dilakukan pemanggilan rekursif untuk menambahkan data baru pada bagian akhir list. Algoritma itu dapat dipahami dari baris program : if (p == NULL) *p = new_item(data);
Baris ini pula sebagai kriteria berhenti (termination condition) dari fungsi yang rekursif ini. Fungsi print_list() berfungsi untuk mencetak semua data dalam linked list juga dengan teknik rekursif. Pertama-tama fungsi ini akan mengecek pointer yang dilewatkan. Jika NULL maka fungsi akan keluar. Jika tidak maka data akan dicetak
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 64 dengan printf(). Selanjutnya member next akan diperiksa, jika tidak NULL pemanggilan rekursif akan dilakukan. Fungsi free_list() berguna untuk mendealokasikan semua memori yang digunakan oleh masing-masing item (node). Pointer untuk node yang pertama (head) dilewatkan dengan double indirection pointer (node**), agar kita dapat memodifikasi isi pointer diluar fungsi (head). Pointer next dari head akan disimpan sementara dalam variabel lokal next : node* next = (*head)->next;
Selanjutnya loop while akan memeriksa apakah next bernilai NULL, jika tidak maka pendealokasian memori akan dilakukan mulai dari ujung depan (head) dengan : while(next != NULL) { printf("Item %i\n",++i); next = (*head)->next; free(*head); *head = next; }
Setelah pendealokasian (dengan pemanggilan free()), pointer head akan diperbaharui dengan nilai yang yang telah disimpan sebelumnya. Sebagai tambahan untuk memeriksa data yang dialokasikan sama dengan yang didealokasikan, kita tambahkan pemanggilan fungsi printf() untuk mencetak informasi pendealokasian masing-masing item atau node. Perhatikan bentuk : next = (*head)->next;
tanda () diperlukan karena kalau tidak maka compiler akan menginformasikan kesalahan karena (*head) dan (*head)->next sama-sama menghasilkan tipe node* sedangkan tanpa () akan menjadi *head->next yang tidak menghasilkan tipe node*. Pada saat program dijalankan anda terus akan diminta memasukkan data tipe double sampai anda mengetikkan sesuatu yang tidak mewakili bilangan. Selanjutnya semua data dalam list yang sudah diurutkan akan dicetak dan pada akhirnya semua node akan dibersihkan atau didealokasikan.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 65
12. TANGGAL DAN WAKTU Standard C menyediakan fungsi-fungsi untuk memanipulasi tanggal dan waktu. Dalam perhitungan tanggal dan waktu, fungsi dengan nama time() digunakan untuk mengambil waktu dan tanggal sekarang dalam bentuk tipe data yang dideklarasikan sebagai time_t pada header time.h. Metode yang digunakan oleh fungsi time() ini berbeda-beda sesuai dengan implementasi oleh pihak yang memproduksinya (compiler vendor). Misalnya ada yang menggunakan perhitungan jumlah detik yang lewat sejak tengah malam GMT 1 Januari 1970, namun ada juga yang menghitung mulai tengah malam 31 Desember 1899. Walaupun implementasinya berbeda-beda, kita dapat menggunakannya dengan konsisten lewat pemanggilan fungsi time(). Fungsi-fungsi untuk penanganan tanggal dan waktu dituliskan dalam tabel : Fungsi asctime clock ctime difftime gmtime localtime mktime time
Deskripsi Konversi tanggal dan waktu dari struktur tm ke bentuk string. Memeberikan waktu prosesor yang berlalu dalam jumlah tick. Konversi tanggal dan waktu dari tipe time_t ke bentuk string Menghitung perbedaan antara dua tipe data time_t Konversi waktu dalam time_t ke dalam struktur tm yang sesuai dengan UTC Konversi waktu dan tanggal dalam time_t menjadi struktur tm. Konversi waktu dalam struktur tm menjadi time_t dan melakukan penyesuaian. Memberikan waktu dan tanggal sekarang dalam time_t
Contoh : LISTING 12.1. Time.C #include<stdio.h> #include int main(void) { time_t sekarang; time(&sekarang); printf(“Waktu sekarang : %s\n”,ctime(&sekarang)); return 0; }
Deklarasi struktur tm adalah sebagai berikut : struct tm { int tm_sec; // detik int tm_min; // menit int tm_hour; // jam int tm_mday; // hari dalam bulan 1-31 int tm_mon; // bulan 0 - 11 int tm_year; // tahun sejak 1900 int tm_wday; // hari sejak minggu 0-6 int tm_yday; // hari sejak januari 1-365
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 66 int tm_isdst;
};
Sekarang kita akan membuat program yang cukup panjang untuk menampilkan kalender dengan mengetikkan dari command line: cldr januari 2004
dan akan menampilkan kalender dalam format yang umum di indonesia: Januari 2004 S S R K J S M -------------------------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
Program ini menggunakan fungsi-fungsi yang ada dalam header file time.h yaitu mktime() dan struktur tm. LISTING 12.2. Cldr.C
#include<stdio.h> #include<stdlib.h> #include #include<string.h> /* prototipe */ int get_wday(struct tm* ptm); int main(int argc,char ** argv) { static char * days[] = {"S","S","R", "K","J","S","M"}; static char * months[] = {"Januari","Februari","Maret", "April","Mei","Juni", "Juli","Agustus","September", "Oktober","Nopember","Desember"}; int mon = 2,year = 2003,row = 0; int firsttime = 1,firstwday = 0; int cal[6][7]; tm t; int i,j,day = 0; if (argc < 3) { printf("Penggunaan : cldr bulan tahun\n"); return 1; }
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 67 for (i = 0;i < 12;i++) { if (strnicmp(argv[1],months[i],strlen(argv[1])) == 0) break; } if (i > 11) { printf("Tidak ada bulan dengan nama %s\n",argv[1]); return 1; } mon = i; year = atoi(argv[2])-1900; memset(cal,0,sizeof(cal)); for (i = 1;i < 32;i++) { memset(&t,0,sizeof(t)); t.tm_mon = mon; t.tm_year= year; t.tm_mday= i; if (get_wday(&t) != -1) { if (firsttime) { firsttime = 0; firstwday = t.tm_wday; /* agar minggu tampil terakhir */ day = (firstwday == 0)?6:firstwday-1; row = 0; } day = (t.tm_wday == 0)?6:t.tm_wday-1; cal[row][day] = i; if (++day > 6) { ++row; } } else break; } /* cetak kalender */ printf("\n\t%s %d\n\n",months[mon],year + 1900); for (i = 0;i < 7;i++) printf("%3s ",days[i]); printf("\n --------------------------"); for (i = 0;i < 6;i++) { printf("\n"); for (j = 0;j < 7;j++) { if (cal[i][j] == 0) printf(" "); else printf("%3d ",cal[i][j]); } } return 0; }
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 68 int get_wday(struct tm* ptm) { int mon,year,mday; mon = ptm->tm_mon; year = ptm->tm_year; mday = ptm->tm_mday; if (mktime(ptm)== -1) return -1; if ((year == ptm->tm_year) && (mon == ptm->tm_mon) && (mday == ptm->tm_mday) && (ptm->tm_wday <= 6)) return ptm->tm_wday; else return -1; }
Simpanlah program ini dengan nama cldr.c dan compile menjadi cldr.exe. Cobalah untuk memahami program ini dengan memperhatikan baris demi baris dan merujuk ke referensi yang lain misalnya dalam dokumentasi compiler yang digunakan tentang fungsi-fungsi untuk manipulasi waktu.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 69
13. UNION, TIPE ENUMERASI DAN PREPROCESSOR Union Selain tipe data struktur dengan kata kunci struct, C juga dapat membuat tipe data yang mana masing-masing membernya dapat menempati lokasi memori yang sama yang disebut dengan union. Contoh : typedef union bilangan { char c; short s; int i; double d; }; bilangan b; b.c = ‘a’; b.s = 1200; b.i = 50000; b.d = 20.006;
Ukuran dari sebuah union adalah sama dengan ukuran tipe data terbesar yang dikandungnya dalam hal ini adalah sebesar double. Ini tentunya sangat berbeda dengan tipe struct yang kalau mengandung data-data seperti contoh union ini akan merupakan jumlah dari ukuran masing-masing data membernya.
Enumerasi Pada saat tertentu kita ingin menginginkan konstanta yang mewakili suatu angka tertentu. Kita dapat menggunakan definisi dengan preprocessor : #define #define #define #define #define #define #define
minggu senen selasa rabu kamis jumat sabtu
0 1 2 3 4 5 6
… int h = minggu;
atau kita dapat menggunakan tipe enumerasi ; enum hari {minggu,senen,selasa,rabu,kamis,jumat,sabtu};
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 70
enum hari h = minggu;
Dengan enum compiler akan menjamin semua nilai akan berbeda. Jika kita tidak memberikan nilai tertentu pada masing-masing item maka compiler akan menganggap nilai mulai dari nol dan item berikutnya akan ditambah satu dan seterusnya. Jika kita memberikan nilai tertentu pada sebuah item maka nilai untuk item-item yang mengikutinya akan terus ditambah satu. Contoh : enum arah {utara = 1,timur,selatan,barat}; nilai timur = 2, selatan = 3 dan barat = 4.
Atau kita juga bisa memberi nilai yang berbeda untuk masing-masing item enum arah {utara = 0,timur = 90,selatan = 180,barat = 270};
Preprocessor (“front end processor”) Seperti pernah disinggung bahwa compiler akan memroses hasil dari preprocessor. Jadi preprocessor akan melakukan tugasnya terlebih dahulu sebelum dilewatkan ke compiler. Dengan mekanisme ini kita dapat melakukan beberapa hal diantaranya :
Menyertakan file Mendeklarasikan konstanta Mendefinisikan makro Debugging
Menyertakan file Kita sudah sering menggunakan fungsi-fungsi standar yang dideklarasikan dalam header file yang kita sertakan pada awal penulisan program misalnya: #include <stdio.h> #include <malloc.h>
Dengan deklarasi ini memerintahkan preprocessor untuk memroses isi file-file yang diawali dengan #include dan berada dalam < >. Preprocessor tahu dimana harus menemukan file-file ini dengan berpedoman pada apa yang disebut environment variables yang dalam MS-DOS didefinisikan dalam autoexec.bat misalnya compiler C tertentu menggunakan nama INCLUDE dan diikuti dengan direktori-direktori dimana preprocessor akan mencari header-header file ini.
Mendeklarasikan Konstanta Konstanta dengan preprocessor dideklarasikan seperti pada penjelasan tipe enumerasi. Deklarasi ini menyebabkan preprocessor akan melakukan substitusi setiap kali menemukan konstanta dalam listing program.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 71 Konstanta dengan preprocessor juga dapat dideklarasikan secara kondisional misalnya : #if !defined(TEST_VALUE) #define TEST_VALUE 0 #endif
Kondisional ditulis di antara #if dan #endif.
Mendefinisikan makro Makro juga melakukan substitusi dengan parameter. #define MAX(a,b) (a) > (b) ? (a) : (b)
MAX akan menentukan nilai yang paling besar antara a dan b dengan menggunakan operator kondisional seperti yang telah dijelaskan sebelumnya. Tanda () diperlukan untuk setiap parameter dalam operasionalnya. Jika tanpa () dan kita menggunakan MAX untuk menyelesaikan pernyataan berikut : mx = MAX(12 + 3,10);
Preprocessor akan menjabarkan sebagai : mx = 12 + 3 > 10 ? 12 + 3 : 10;
Yang tentu saja akan membingunkan compiler. Namun bentuk dengan tanda () dapat memperjelas bentuk menjadi : mx = (12 + 3) > (10) ? (12 + 3) : (10);
Debugging Preprocessor juga dapat digunakan untuk membantuk melacak alur program yang sangat berguna untuk menemukan letak kesalahan dalam program. Dengan bantuan konstanta yang dimengerti oleh preprocessor seperti __LINE__ untuk menentukan baris program dalam integer dan __FILE__ untuk menentukan nama file yang sedang diproses. Contoh : #if defined(_MY_DEBUG) #define TRACE_LINE printf(“Baris no : %i File : %s\n”,__LINE__,__FILE__); #else #define TRACE_LINE #endif
Makro ini selanjutnya digunakan seperti menggunakan fungsi : #define _MY_DEBUG TRACE_LINE
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 72
yang akan menampilkan nomor baris dan nama file. Kalau kita mendefinisikan _MY_DEBUG, maka TRACE_LINE tidak melakukan apa-apa. Dengan fasilitas ini kita dapat menyisipkan makro-makro kita dalam program untuk mencetak nilai-nilai variabel tertentu untuk melihat kerja program sehingga memudahkan untuk memperbaiki kesalahan.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 73
APPENDIX ANSI C Escape Sequences and Trigraph Dalam C kita dapat memasukkan karakter yang tidak tercetak (non-printable) dengan menggunakan escape sequence yang diawali dengan karakter ‘\’. Tabel berikut adalah escape sequences dalam C Sequence \a \b \f \n \r \t \v \\ \’ \” \?
Nama Alert Backspace Form Feed Newline Carriage return Horizontal Tab Vertical Tab Backslash Single Quote Double Quote Question Marks
Interpretasi Bunyi seperti bell Pindah satu karakter ke kiri Pindah kursor ke awal baris Pindah ke baris berikutnya Pindah ke awal baris Pindah ke posisi tab horizontal berikutnya Pindah ke posisi tab vertikal berikutnya \ ‘ “ ?
C juga mengenalkan konsep yang disebut trigraph yang mengijinkan programmer untuk mengetikkan kombinasi karakter-karakter tertentu pada keyboard untuk mewakili karakter tertentu yang tidak tersedia langsung di keyboarnya. Misalnya keyboard non-english tidak bisa mencetak secara langsung beberapa karakter dalam bahasa inggeris. Masing-masing trigraph diawali dengan ?? diikuti dengan karakter ketiga. Beberap trigraph dituliskan dalam tabel : Trigraph ??( ??/ ??) ??’ ??< ??! ??> ????=
Translasi [ \ ] ^ { | } ~ #
ANSI Library Header Files ANSI C library menentukan semua aspek bahasa C secara keseluruhan walaupun telah melalui standarisasi. Fungsi-fungsi dalam library Standard C ditampilkan dalam tabel untuk memudahkan mempelajari berdasarkan header file yang perlu diikutkan dalam program. Header file assert.h ctype.h errno.h float.h
Kegunaannya Mendeklarsikan makro untuk keperluan diagnostik. Mendeklarasikan fungsi-fungsi untuk konversi karakter. Mendeklarasikan makro untuk kondisi error dan juga variabel errno dimana fungsi-fungsi dalam library mendeposit kode error. Mendefinisikan jangkauan tipe data floating-point.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 74 limits.h locale.h math.h setjmp.h signal.h stdarg.h stddef.h stdio.h stdlib.h string.h time.h
Mendefinisikan jangkauan tipe data integer Mendeklarasikan struktur lconv dan fungsi-fungsi untuk keperluan customize program C dalam regional tertentu. Mendeklarasikan fungsi-fungsi yang berkaitan dengan matematika Mendeklarasikan fungsi setjmp() dan longjmp() yang berguna untuk mentransfer kontrol antara fungsi tanpa tergantung pemanggilan fungsi secara normal. File ini juga mendeklarasikan tipe jmp_buf. Mendeklarasikan fungsi-fungsi untuk penanganan eksepsi. Mendefinisikan makro untuk keperluan parameter fungsi dengan jumlah yang variabel. Mendefinisikan tipe-tipe data standar seperti size_t,wchar_t dan juga simbol NULL dan juga makro offsetof. Mendeklarasikan fungsi-fungsi untuk operasi input output seperti printf() dan scanf(). Juga mendefinisikan makro SEEK_SET,SEEK_CUR dan SEEK_END. Mendeklarasikan fungsi-fungsi utilitas seperti konversi string, alokasi memori, pembangkit bilangan acak dan beberapa fungsi untuk proses seperti abort, exit dan system. Mendeklarasikan fungsi-fungsi untuk manipulasi string. Mendeklarasikan fungsi-fungsi untuk memanipulasi tanggal dan waktu.
Fungsi-fungsi untuk konversi Berikut ini adalah beberapa fungsi yang berguna untuk konversi dari string ke numerik yang dideklarasikan dalam stdlib.h. Untuk konversi dari numerik ke string dapat menggunakan fungsi sprintf().
double atof(const char* str); Untuk konversi dari string ke tipe double. Fungsi ini akan melakukan konversi sampai ditemukan karakter yang tidak dapat ditanganinya sebagai numerik. Contoh double d; d = atof(“2100.45 rupiah”);
d akan menjadi 2100.45
int atoi(const char * str); int atol(const char * str); Fungsi-fungsi ini menkonversi string menjadi int dan long sampai ditemukan karakter yang tidak sesuai sebagai bilangan integer. Contoh : int n = atoi(“100 halaman”);// n menjadi 100 long l = atol(“12000000 orang”); // l menjadi 12000000
Fungsi-fungsi untuk konversi karakter dari huruf kecil ke huruf besar dan sebaliknya. Dideklarasikan dalam ctype.h.
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 75
int tolower(int c); c adalah karakter yang ingin dikonversi. Fungsi ini menghasilkan nilai balik berupa nilai karakter yang sudah dikonversi. Contoh : int c = tolower(‘A’);// c menjadi a
int toupper(int c); Melakukan konversi sebaliknya dari tolower(). Fungsi-fungsi untuk menguji apakah sebuah karakter termasuk dalam abjad atau bukan. Dideklarasikan dalam ctype.h.
int isalnum(int c); Fungsi ini menguji apakah c termasuk karakter alphanumneric yaitu salah satu di antara 0-9,a-z atau A-Z.
int isalpha(int c); Fungsi ini menguji apakah c termasuk karakter huruf yaitu karakter antara a-z dan A-Z. Untuk konversi dari numerik ke string dapat menggunakan fungsi sprintf() yang dideklarasikan dalam stdio.h.
int sprintf(char * str, const char * fmt,…); Fungsi ini menerima masukan variabel (dengan …) dengan format tertentu sesuai dengan parameter fmt yang sama dengan printf(). Hasil konversi yang berupa string akan disimpan dalam str. Contoh : char buffer[80]; sprintf(buffer,”Bilangan ini adalah %.2f”,12.3);
buffer akan berisi Bilangan ini adalah 12.30
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 76
KEPUSTAKAAN The C Programming Language 2nd Edition B.W. Kernighan & D.M. Ritchie
Thinking in C++2nd Edition Bruce Eckel
The C Standard Library P.J. Plauger
Microsoft C/C++ Developer’s Guide Nabajyoti Barkakati
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 77
WHAT’S NEXT… Windows Programming in C (SDK, Win32 API perspective) C++ Programming Windows Programming with Microsoft Foundation Class (MFC)
Copyright Chipmunk Personal Passion Lab © 2003
C Programming – Foundation Level 78
CATATAN
Copyright Chipmunk Personal Passion Lab © 2003