Sudah berlangganan artikel blog ini via RSS Feed?

Pengikut

Diberdayakan oleh Blogger.

Selasa, 13 September 2011

modul pemograman lanjut

BAB 1: Pointer Dasar
Pokok bahasan:
 Referensi
 Deklarasi dan definisi pointer
 Referensi dan dereferensi
 Void pointer
 Null pointer
 Aritmetika pointer
 Pointer sebagai parameter fungsi
5
1.1 Pendahuluan
Sebuah pointer (kadang-kadang diterjemahkan sebagai “penunjuk”) adalah sebuah variabel yang
bertipe khusus, yaitu yang menyimpan alamat dari sebuah variabel lainnya. Pointer memiliki peran
yang sangat penting dalam C/C++. Secara khusus, pointer berperan vital dalam implementasi
struktur data seperti array, string, dan linked list. Selain itu, pointer juga dapat digunakan untuk
pengiriman parameter fungsi dan untuk menunjuk pada alamat fungsi. Untuk tujuan yang terakhir
ini pembahasannya di luar fokus bab ini.
Dalam memahami pointer, ada beberapa konsep dasar atau terkait yang perlu dipelajari.
Diantaranya adalah referensi, pendeklarasian pointer, inisialisasi dan pendefinisian pointer, akses
pointer, dereferensi, null ponter, void pointer, dan penggunaan pointer untuk pengiriman
parameter fungsi.
1.2 Referensi
Seperti yang telah diketahui, setiap variabel yang dideklarasikan akan dialokasikan tempat tertentu
pada memori. Keberadaan variabel ini memudahkan kita untuk menggunakan data yang tersimpan
pada memori, tanpa memedulikan lokasi fisik data tersebut. Untuk mengakses atau mengubah
data tersebut cukup merujuknya melalui nama variabelnya. Tetapi sebenarnya kita masih bisa
mengakses lokasi data tersebut melalui alamat variabelnya jika diperlukan. Alamat variabel ini
sering juga disebut dengan “referensi” dari variabel tersebut. Dalam bahasa C/C++, proses me-
“referensi” atau mengakses alamat sebuah variabel dapat menggunakan operator alamat atau
referensi yang direpresentasikan dengan simbol ampersand (&).
Contoh di bawah ini menunjukkan cara mengakses alamat dari variabel menggunakan operator &.
123456789 10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
int main(){
int a = 17;
double b = 13.5;
printf("Isi variabel: \n");
printf("\t a = %d",a);
printf("\t b = %.2lf",b);
printf("\n\nAlamat variabel: \n");
printf("\t a = %d ",&a);
printf("\t b = %d ",&b);
system(“pause”);
6
16
17
return 0;
}
Gambar 1.1
Sebagai latihan, ketiklah contoh di atas untuk menjadi sebuah program. Setelah menjalankan
program tersebut dan memperhatikan hasilnya, cobalah untuk mengubah format keluaran &a dan
&b pada baris ke-13 dan ke-14 dari %d menjadi %p lalu amati hasilnya. Ambillah kesimpulan dari
perubahan tersebut.
Saat variabel a dan b dideklarasikan dan diinisialisasikan dengan nilai masing-masing 17 dan 13.5,
di memori dialokasikan tempat yang sesuai, seperti yang diilustrasikan pada gambar 1.2.
Gambar 1.2
Nilai alamat dari a dan b yang tertulis di sini hanya sebagai contoh; nilai yang sebenarnya dapat
berbeda dalam setiap menjalankan program. Alamat a dan b dapat diakses dengan ekspresi
masing-masing &a dan &b.
1.3 Deklarasi Variabel Pointer
Sebelum diisikan dengan alamat dari variabel lainnya, sebuah pointer perlu dideklarasikan terlebih
dahulu. Sintaksis pendeklarasiannya adalah sebagai berikut.
tipedatavariabelyangditunjuk *namavariabelpointer;
atau
tipedatavariabelyangditunjuk * namavariabelpointer;
Perhatikan penggunaan simbol bintang/asterisk (*) di atas. Simbol ini membedakan deklarasi
sebuah variabel non-pointer dengan deklarasi variabel pointer. Tipe data variabel yang ditunjuk
pointer dapat berupa sembarang tipe. Aturan penamaan variabel pointer harus mengikuti aturan
yang sama dengan penamaan variabel biasa.
Contoh deklarasi pointers:
int* pi; // pointer to integer
float* pf; // pointer to float
7
Pointer yang telah dideklarasikan hanya dapat diisikan dengan alamat dari variabel yang bertipe
data sesuai dengan deklarasi pointernya. Sebagai contoh, sebuah pointer to integer hanya dapat
menyimpan alamat dari variabel yang bertipe data integer.
1.4 Pendefinisian Pointer dan Proses Referensi
Saat dideklarasikan, sebuah pointer menunjuk pada alamat yang ‘acak’ atau tidak terdefinisi.
Dalam keadaan demikian usaha untuk mengakses pointer ini dapat berakibat fatal karena pointer
ini mungkin berisi alamat dari memori yang sedang dikelola oleh sistem atau aplikasi lain. Oleh
karena itu, untuk menggunakan sebuah pointer kita harus memastikan bahwa dia berisi alamat
yang benar atau yang kita inginkan.
Inisialisasi atau pendefinisian sebuah pointer dapat dilakukan dengan salah satu dari dua cara.
Pertama, dengan proses referensi ke variabel yang sudah ada. Kedua, dengan alokasi memori
dinamik. Sub bab ini hanya akan membahas cara yang pertama. Cara yang kedua akan
didiskusikan di bab lainnya.
Sintaksis proses referensi sebuah pointer ke variabel lain yang sudah ada adalah:
namavariabelpointer = &namavariabellainnya;
Perhatikan pemakaian operator referensi (&) pada pernyataan di atas. Tentunya, kedua variabel di
atas sudah harus dideklarasikan sebelumnya.
Contoh di bawah ini menunjukkan inisialisasi pointer dengan cara referensi ke variabel lainnya.
Jalankanlah program ini dan perhatikan hasilnya.
123456789
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <stdlib.h>
int main(){
int x; // Nilai x acak
int *px; // Nilai px acak
printf("\nKondisi x dan px sebelum inisialisasi ");
printf("\nNilai x: %d", x);
printf("\nAlamat x: %d", &x);
printf("\nNilai px = %d", px);
printf("\nAlamat px = %d\n", &px);
px = &x;
x = 10;
printf("\nKondisi x dan px setelah inisialisasi ");
printf("\nNilai x: %d", x);
printf("\nAlamat x: %d", &x);
8
20
21
22
23
24
25
printf("\nNilai px = %d", px);
printf("\nAlamat px = %d", &px);
system("pause");
return 0;
}
Gambar 1.3
Beberapa proses yang terjadi saat program ini dijalankan dapat diilustrasikan pada gambar 1.4
berikut.
int x;
int *px;
px=&x;
x=10;
deklarasi
inisialisasi pointer
p dengan referensi
10
x
px
px x
inisialisasi x px x
x tidak terdefinisi
px tidak terdefinisi
Gambar 1.4
1.5 Akses Pointer dan Proses Dereferensi
Pengaksesan pointer dengan cara memanggil nama variabel pointer sama dengan mengakses
alamat variabel yang ditunjuknya. Untuk mengakses nilai yang dikandung oleh variabel yang
ditunjuknya, kita dapat menggunakan simbol bintang (*) yang diletakkan sebelum nama variabel
pointer. Proses ini disebut dereferensi.
Perhatikan contoh dereferensi pada kode di bawah ini.
123456789
10
11
#include <stdio.h>
#include <stdlib.h>
int main(){
int x; // Nilai x acak
int *px = &x; // Deklarasi dan inisialisasi px
x = 11;
printf("\nKondisi x dan px setelah inisialisasi");
printf("\nNilai x: %d", x);
printf("\nNilai px: %d", px);
9
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// dereferensi untuk mengakses nilai x via pointer px
printf("\nNilai *px = %d", *px);
// dereferensi untuk mengubah nilai x via pointer px
*px = 5;
printf("\nKondisi x dan px setelah x diubah");
printf("\nNilai x: %d", x);
printf("\nNilai px: %d", px);
printf("\nNilai *px = %d", *px);
system("pause");
return 0;
}
Gambar 1.5
Beberapa proses yang terjadi saat kode di atas ini dijalankan dapat diilustrasikan pada gambar
berikut:
int x;
int px=&x;
*px=5;
deklarasi x
deklarasi &
inisialisasi p
5
x
px x
px x
dereferensi px
x tidak terdefinisi
x=11;
inisialisasi x
px x 11
Gambar 1.6
Amati penggunaan dereferensi pada baris ke-14 dan ke-16 pada gambar 1.4, lalu ambil
kesimpulan tentang perbedaan kegunaannya. Amati juga perbedaan antara px dan *px.
Cobalah untuk menambahkan variabel baru y bertipe integer dan inisialisasikan dengan sebuah
nilai, misalnya 100. Referensikan alamat y ini ke pointer px setelah baris ke-19, kemudian cetak
nilai px dan *px. Amati dan simpulkan hasilnya.
Setelah itu coba ubah nilai y melalui px, misalnya menjadi 1000, dan cetak nilai y dan *px untuk
mengamati perubahan y.
10
1.6 Simbol *: Deklarasi vs Dereferensi
Perlu diingat benar bahwa simbol bintang (*) dalam pembahasan pointer memiliki dua semantik
(makna) dan penggunaan yang berbeda. Makna pertama adalah untuk menunjukkan bahwa
sebuah variabel merupakan sebuah pointer. Makna ini didapat dari pendeklarasian pointer
tersebut. Contoh * untuk deklarasi dapat dilihat di baris ke-6 gambar 1.2 dan baris ke-6 gambar
1.3, seperti di bawah ini.
int *px; // Deklarasi px: px adalah sebuah “pointer to integer”
int *px = &x; // Deklarasi dan inisialisasi px
Makna kedua adalah untuk mengambil isi dari alamat yang disimpan oleh pointer tersebut. Proses
ini disebut dengan “dereferensi” seperti yang telah dijelaskan sebelumnya. Contoh * untuk
deklarasi dapat dilihat di baris ke-14 dan baris ke-16 gambar 1.3, seperti di bawah ini.
// dereferensi untuk mengakses nilai x via pointer px
printf("\nNilai *px = %d", *px);
// dereferensi untuk mengubah nilai x via pointer px
*px = 5;
Dua makna yang berbeda dari simbol * ini sangat penting untuk diperhatikan dan diingat karena
sering disalahpahami.
1.7 Void Pointer
Void pointer adalah pointer dengan tipe khusus. Dalam C/C++ void melambangkan ketiadaan tipe
data, sehingga void pointer adalah pointer yang menunjuk pada nilai yang tidak bertipe data.
Dengan demikian void pointer dapat menunjuk pada data dari sembarang tipe, seperti integer,
float, double, char atau string. Tetapi void pointer ini memiliki keterbatasan. Karena pointer ini
bersifat ‘void’, data yang ditunjuknya tidak dapat secara langsung didereferensikan. Agar dapat
didereferensikan, pointer ini (atau alamat yang tersimpan di dalamnya) harus dikonversi paksa (dicast
) dahulu menjadi pointer yang dapat menunjuk pada tipe data kongkrit.
Untuk memahami konsep void pointer dan proses casting di atas, kerjakan dan analisis kode di
bawah ini.
123456789
#include <stdio.h>
#include <stdlib.h>
int main(){
void* pv; // Pointer terhadap void
int* pi; // Pointer terhadap integer
double* pd; // Pointer terhadap double
int ivalue = 100;
double dvalue = 50.55;
11
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// pv dapat menunjuk pada variabel bertipe data integer
pv = &ivalue;
printf("pv=%d, sizeof(pv)=%d\n",pv, sizeof(pv));
// pernyataan ini salah krn pv tidak dapat didereferensikan
printf("*pv=%d, sizeof(*pv)=%d\n",*pv, sizeof(*pv));
// pv dapat menunjuk pada variabel bertipe data double
pv = &dvalue;
printf("pv=%d, sizeof(pv)=%d\n",pv, sizeof(pv));
// pernyataan ini salah krn pv tidak dapat didereferensikan
printf("*pv=%.2lf, sizeof(*pv)=%d\n",*pv, sizeof(*pv));
// pd menerima hasil casting dari pv
pd = (double*)pv;
printf("pd=%d, sizeof(pd)=%d\n",pd, sizeof(pd));
// pernyataan ini benar, pd dapat didereferensikan
printf("*pd=%.2lf, sizeof(*pd)=%d\n",*pd, sizeof(*pd));
system("pause");
return 0;
}
Gambar 1.7
1.8 Null Pointer
Sebuah null pointer adalah sebuah pointer yang memiliki nilai khusus yang menununjukkan bahwa
pointer tersebut tidak menyimpan alamat memori manapun. Nilai ini dihasilkan dari penugasan
nilai NULL atau 0 ke sebuah pointer. Contoh:
int *p;
p = NULL; // atau p = 0;
Null pointer berbeda dengan void pointer. Null pointer adalah pointer yang tidak menunjuk pada
alamat memori manapun, sedangkan void pointer adalah pointer yang dapat menunjuk pada
sebuah alamat memori tanpa tipe data tertentu. Istilah null diasosiasikan dengan nilai yang
disimpan pada pointer, sedangkan void mengacu pada tipe data yang ditunjuk oleh pointer.
12
1.9 Aritmetika Pointer
Operasi aritmetika dapat juga diterapkan pada pointer, tetapi dengan lebih banyak keterbatasan
daripada operasi aritmetika pada tipe data integer, float, atau, double. Hanya penjumlahan dan
pengurangan yang berlaku pada operasi aritmetika pointer. Perilaku kedua operasi ini bergantung
pada ukuran tipe data yang ditunjuk oleh pointer yang bersangkutan.
Dalam bahasa C/C++ tipe-tipe data yang berbeda dapat memiliki ukuran yang berbeda pula
tergantung pada kompilator (compiler) dan jenis platform target programnya. Sebagai contoh,
dengan kompilator dan platform tertentu, char akan berukuran 1 byte, short 2 bytes, dan
long 4 bytes.
Misalkan kita mendefiniskan 3 buah pointer berikut:
char *mychar;
short *myshort;
long *mylong;
dan kita ketahui bahwa pointer-pointer tersebut masing-masing menunjuk pada alamat 1000,
2000 and 3000 pada memori. Lalu kita tuliskan:
mychar++; //ekivalen mychar +=1;
myshort++; //ekivalen myshort +=1;
mylong++; //ekivalen mylong +=1;
Setelah itu mychar akan bernilai 2002 (bukan 1001), myshort bernilai 2002 (bukan 2001), dan
mylong 3004 (bukan 3001), walaupun masing-masing hanya ditambah dengan 1. Alasannya
adalah penambahan satu tersebut menyebabkan masing-masing pointer menunjuk pada elemen
yang bertipe data sama pada lokasi memori berikutnya. Jadi, penambahan satu di sini bermakna
perpindahan 1 unit tipe data pada elemen berikutnya, seperti yang diilustrasikan pada gambar di
bawah ini.
Gambar 1.8
13
1.10 Pointer sebagai Parameter Formal Fungsi
Pointer dapat dimanfaatkan sebagai parameter formal dalam sebuah fungsi. Pointer ini akan
menyimpan alamat dari variabel yang dilewatkan sebagai parameter aktual pada pemanggilan
fungsi tersebut. Dengan demikian nilai variabel yang bersangkutan dapat diubah di dalam fungsi
melalui proses dereferensi. Mekanisme pengiriman alamat variabel sebagai parameter pada fungsi
disebut dengan passing by reference.
Sebagai contoh, kerjakan dan amati kode di bawah ini. Kode ini menyediakan 2 buah fungsi,
masing-masing untuk konversi nilai dari standar satuan metrik (cm) ke standar satuan Inggris
(inch) dan sebaliknya. Penggunaan pointer sebagai parameter fungsi dapat diamati pada definisi
fungsi inchToCm() di baris ke-7 sampai ke-9. Contoh passing by reference dapat dilihat pada
baris ke-21. Bandingkanlah dengan mekanisme passing by value pada baris ke-17, menggunakan
fungsi yang didefinisikan pada baris ke-4 sampai ke-6.
123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>
double cmToInch(double a){
return a*0.393700787;
} void inchToCm(double* a){
*a *= 2.54;
}
int main(){
// Panjang dalam cm
double panjang=15;
printf("panjang: %.2lf cm\n",panjang);
// Konversi dari cm ke inch, passing by value
panjang = cmToInch(panjang);
printf("panjang: %.2lf inch\n",panjang);
// Konversi kembali dari inch ke cm, passing by reference
inchToCm(&panjang);
printf("panjang: %.2lf cm\n",panjang);
system("PAUSE");
return 0;
}
Gambar 1.9
14
1.11 Tugas
 Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
 Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
 Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
15
2 BAB 2: Array
Pokok bahasan:
 Array satu dimensi
o Deklarasi
o Inisialisasi
o Akses
o Array dan pointer
o Array sebagai parameter fungsi
 Array dua dimensi
o Deklarasi
o Inisialisasi
o Akses
o Array sebagai parameter fungsi
16
2.1 Pendahuluan
Array (kadang-kadang diterjemahkan sebagai “larik”) adalah serangkaian elemen-elemen yang
berasal dari tipe data yang sama, disusun secara berurutan di dalam memori, dan masing-masing
dapat diakses dengan menambahkan indeks pada nama array tersebut.
Tipe data dari elemen array dapat berupa tipe data sederhana maupun tipe data kompleks. Setiap
elemen array mempunyai nomor indeks yang unik dan disimpan secara berurutan di dalam
memori. Array dapat berdimensi satu, dua, tiga, ataupun lebih, sesuai dengan kebutuhan
pemrogram.
2.2 Array Satu Dimensi
2.2.1 Deklarasi Array Satu Dimensi
Penamaan array harus mengikuti aturan-aturan penamaan variabel. Seperti halnya variabel
sederhana, array pun harus dideklarasikan dahulu sebelum digunakan. Deklarasi array berisi tipe
data array, nama array, dan jumlah elemen yang dimilikinya. Sintaksis deklarasi array adalah
sebagai berikut:
tipedataelemen namaarray[jumlahelemen];
Contoh deklarasi array bernama A dengan 5 elemen integer:
int A[5];
Dalam bahasa C/C++, elemen pertama suatu array diberi indeks nol, elemen kedua diberi indeks
satu, dan seterusnya. Array billy dapat digambarkan sebagai berikut:
A
A[0] A[1] A[2] A[3] A[4]
int int int int int
Gambar 2.1
Dalam deklarasi yang tidak langsung menyertakan inisialisasi array, jumlah elemen dalam array
haruslah didefinisikan. Sebagai contoh, pernyataan berikut tidaklah valid.
int A[]; // invalid, compile error
2.2.2 Inisialisasi Array Satu Dimensi
Setelah dideklarasikan, array dapat didefinisikan atau diisi dengan nilai-nilai. Inisialisasi array dapat
dilakukan dengan beberapa cara berikut.
17
1. Inisialisasi dalam satu pernyaatan dengan deklarasi
Contoh:
int Ai[4] = {2,4,5,7};
float Af[] = {2.2,4,6.5,8};
char Ac[] = {‘i’,’a’};
int B[4] = {1,3};
Sebagai catatan, jika jumlah elemen array dalam kurung tegak [] di sebelah kiri tanda
penugasan (=) dideklarasikan, maka jumlah elemen ini harus sama dengan atau lebih besar
daripada jumlah dari elemen yang dinisialisaskikan dalam kurung kurawal {} di sebelah kanan
tanda penugasan. Hal ini terlihat pada contoh inisialisasi array Ai dan B di atas.
Sementara itu, jika jumlah elemen array dalam kurung tegak [] di sebelah kiri tanda
penugasan (=) tidak dideklarasikan, maka jumlah elemen array-nya adalah jumlah dari
elemen yang dinisialisasikan dalam kurung kurawal {} di sebelah kanan tanda penugasan.
Contohnya adalah pada inisialisasi array Af dan Ac di atas.
Jika jumlah elemen array dalam kurung tegak [] di sebelah kiri tanda penugasan (=) lebih
besar daripada jumlah dari elemen yang dinisialisasikan dalam kurung kurawal {} di sebelah
kanan tanda penugasan, maka jumlah elemen yang valid adalah yang di sebelah kiri tanda
penugasan. Elemen yang tidak tertulis akan by default diber nilai nol (0). Contohnya adalah
pada inisialisasi array B di atas. Elemen-elemen dari B adalah 1, 3, 0, dan 0.
Ai 2 4 5 7
Ai[0] Ai[1] Ai[2] Ai[3]
Int int int int
Af 2.2 4 6.5 8
Af[0] Af[1] Af[2] Af[3]
Float float float float
Ac 'i' 'a'
Ac[0] Ac[1]
Char char
Ai 1 3 0 0
Ai[0] Ai[1] Ai[2] Ai[3]
int int int int
Gambar 2.2
2. Inisialisasi elemen-elemen array secara individu melalui indeksnya masing-masing
18
Sintaksis pengisian nilai ke dalam indeks tertentu dari sebuah array:
namaarray[indeksarray] = nilai;
Contoh:
double Ad[3]; // deklarasi array
Ad[0] = 3.3; // inisialisasi elemen dari Ad pada indeks ke-0
Ad[1] = 1.5; // inisialisasi elemen dari Ad pada indeks ke-1
Ad[2] = 2.43; // inisialisasi elemen dari Ad pada indeks ke-2
Ad 3.3 1.5 2.43
Ad[0] Ad[1] Ad[2]
double double double
Gambar 2.3
Jika nilai-nilai elemen array memiliki pola tertentu, inisialisasinya dapat memanfaatkan
mekanisme seleksi dan/atau perulangan. Contohnya, array X yang berisi bilangan bulat antara
1 dan 5, inklusif. Deklarasi dan inisialisasi tersebut adalah sebagai berikut:
int X[5];
for(int i=0; i<5; i++){
X[i]=i+1;
}
2.2.3 Akses array satu dimensi
Setelah sebuah array didefinisikan, elemen array dapat diakses dengan cara memanggil nama dan
nomor indeksnya, seperti ekspresi berikut ini:
namaarray[indeksarray]
Sebagai contoh, lihat pernyataan berikut:
int Ai[4] = {2,4,5,7}; // deklarasi Ai
printf(“Elemen pada indeks ke-2 dari Ai: %d\n”, Ai[2]);//akses A[2]
Contoh lainnya, sebuah array S yang tiap elemennya dicetak ke monitor dapat ditulis sebagai
berikut:
char S[]={‘s’,’a’,’l’,’a’,’m’};
for(int i=0; i<5; i++){
printf(“Elemen pada indeks ke-%d dari S: %c\n”,i,S[i]);
}
19
2.2.4 Array dan Pointer
Array memiliki hubungan erat dengan pointer. Dalam banyak kesempatan, array dikatakan
“ekivalen” dengan pointer. Ekivalen di sini tidak berarti sama persis. Keduanya berbeda, tetapi
dapat digunakan secara berkaitan. Perhatikan contoh berikut:
int A[4] = {2,4,5,7}; // deklarasi A
Seperti telah diketahui, elemen pada indeks ke-0 dan ke-1 dalam Ai dapat diakses dan dimodifikasi
dengan cara berikut:
A[0]=3; A[1]=10;
Dengan ekivalensi antara array dan pointer, kedua elemen di atas dapat diakses dan dimodifikasi
dengan cara berikut:
*A=3; *(A+1)=10;
Hal ini dapat terjadi karena variabel array A dapat dianggap sebagai sebuah variabel pointer A.
Sebagai sebuah pointer, A berisikan alamat elemen pertama (indeks ke-0) dari array A, yaitu
A[0].
Untuk lebih memahami hubungan pointer dan array, kerjakan dan analisis kode pada gambar 2.4
berikut.
123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <stdlib.h>
int main(){
// Deklarasi dan inisialisasi A
int A[4]={2,4,5,7};
// Akses dan modifikasi dengan 'cara array'
A[0]=10; A[1]=20;
// Akses dan modifikasi dengan 'cara pointer'
*(A+2)=30; *(A+3)=40;
// Tampilkan nilai A, alamat A, alamat A[0]
printf("A: %d, &A: %d, &A[0]: %d\n\n",A,&A,&A[0]);
// Cetak tiap elemen ke monitor dengan 'cara array'
for(int i=0; i<4; i++){
printf("Elemen pada indeks ke-%d dari A: %d\n",i,A[i]);
printf("Alamat elemen pada indeks ke-%d dari A: %d\n",
i,&A[i]);
}
// Deklarasi pointer variabel
20
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int *p;
// Inisialisasi p dengan A
p = A;
// Cetak tiap elemen ke monitor dengan 'cara array'
for(int i=0; i<4; i++){
printf("Elemen pada indeks ke-%d dari p: %d\n",i,p[i]);
}
// Pernyataan di bawah ini invalid, A adalah pointer konstan
// A = p;
system("PAUSE");
return 0;
}
Gambar 2.4
Perhatikan bagaimana dua cara yang berbeda untuk mengisikan nilai pada elemen array (baris ke-
9 dan ke-12) ternyata memberikan efek yang sama. Perhatikan juga baris ke-17 sampai ke-22.
Cobalah untuk membuat kode yang memiliki tujuan yang sama dengan yang berada pada baris ini,
tetapi dengan ‘cara pointer’.
Kemudian lihatlah baris ke-24 sampai selesai. Di sana sebuah pointer p dideklarasikan, diinisialisasi
dengan A, dan seluruh elemennya ditampilkan menggunakan ‘cara array’. Hal ini menunjukkan
bahwa p memiliki tipe data yang kompatibel dengan A. Ketika baris ke-27 dieksekusi, hubungan p
dan A dapat diilustrasikan sebagai berikut:
Gambar 2.5
Sekarang perhatikan baris ke-35. Coba hilangkan tanda // sehingga pernyataan A = p
dikompilasi. Perhatikan hasilnya. Walaupun A dapat dilihat sebagai pointer, tetapi dia tidak dapat
ditugasi (assigned) atau diisikan dengan nilai pointer lain. Sekali array dideklarasikan, pointernya
akan selalu menunjuk pada elemen yang sama, yaitu elemen pertama (indeks ke-0) dari array
tersebut, tidak dapat diubah ke alamat memori lain. Dengan demikian variabel array disebut juga
sebagai sebuah pointer konstan.
Amati juga keluaran program ini oleh baris ke-15. Dari pengamatan nilai A dan alamat A[0],
terlihat bahwa A dapat dilihat sebagai pointer yang menunjuk pada atau berisi alamat A[0]. Ada
21
hal lain yang menarik di sini. Alamat A ternyata juga memiliki nilai yang sama dengan nilai A dan
alamat A[0]. Hal ini mungkin nampak membingungkan. Masalah ini tidak akan dibahas lebih
dalam di sini. Kesimpulan sementara yang dapat ditarik adalah bahwa C/C++ memang
memperlakukan array seperti ini untuk mendukung konsep bahwa array bisa dilihat sebagai
sebuah pointer dan dia adalah pointer konstan.
2.2.5 Array sebagai Parameter Fungsi
Array dapat dikirimkan sebagai parameter sebuah fungsi. Untuk bisa menerima parameter array
ini, fungsi itu perlu didefinisikan dengan parameter formal pointer yang menunjuk pada tipe data
yang sesuai dengan tipe data elemen array tersebut. Dengan kata lain, array tersebut harus
dikirim by reference. Prototipe fungsi tersebut dituliskan dalam sintaksis berikut:
tipedatakembalian namafungsi(tipedata *parameterformal);
atau
tipedatakembalian namafungsi(tipedata parameterformal[]);
atau
tipedatakembalian namafungsi(tipedata parameterformal[jumlahelemen]);
Gambar berikut mencontohkan penggunaan array sebagai parameter fungsi.
123456789
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
void cetakElemen(int *A, int index){
printf("Elemen pada indeks ke-%d: %d\n",index,A[index]);
}
int main(){
int X[]={7,8,9,10};
cetakElemen(X,2);
system("pause");
return(0);
}
Gambar 2.6
2.3 Array Multidimensi
Selain berdimensi satu, array juga dapat bermultidimensi. Array multidimensi disebut juga ‘array of
arrays’. Contoh array multidimensi adalah array dua dimensi.
22
2.3.1 Deklarasi Array Dua Dimensi
Deklarasi array dua dimensi terdiri dari tipe data array, nama array, jumlah elemen pada dimensi
pertama, dan jumlah elemen pada dimensi kedua. Sintaksis deklarasi array adalah sebagai berikut:
tipedataelemen namaarray[jumlahelemendimensi1][jumlahelemendimensi2];
Array dua dimensi sering dimodelkan sebagai sebuah matriks dua dimensi yang memiliki baris dan
kolom. Dimensi pertama array tersebut direpresentasikan sebagai baris dan dimensi kedua sebagai
kolom. Contoh deklarasi sebuah array dua dimensi:
int A[2][3]; // array dengan 2 baris dan 3 kolom
Array A ini dapat dibayangkan seperti sebuah matriks pada gambar 2.7.
Kolom 0 Kolom 1 Kolom 2
Baris 0 A[0][0] A[0][1] A[0][2]
Baris 1 A[1][0] A[1][1] A[1][2]
Gambar 2.7
Walaupun array dua dimensi ini bisa dilihat sebagai matriks dua dimensi, tetapi dalam memori
elemen-elemen array ini tersusun secara linier dengan urutan seperti pada gambar 2.8.
nama
elemen nilai alamat
A[0][0] 2293520
A[0][1] 2293524
A[0][2] 2293528
A[1][0] 2293532
A[1][1] 2293536
A[1][2] 2293540
Gambar 2.8
2.3.2 Inisialisasi Array Dua Dimensi
Sebagaimana array satu dimensi, inisialisasi array dua dimensi dapat dilakukan dengan beberapa
cara berikut.
1. Inisialisasi dalam satu pernyaatan dengan deklarasi
Contoh:
int A[3][4] = {{2,4,5,5},{7,9,11,5},{0,2,2,1}};
int B[2][3] = {3,5,7,9,0,4};
int C[2][3] = {1,10,5,6};
23
int D[3][2] = {{1},{10,5},{6}};
Aturan pengisian nilai elemen dalam array dua dimensi mengikuti aturan “row major order”
(RMO). Untuk mengetahui bagaimana RMO bekerja untuk setiap array di atas, perhatikan
ilustrasi untuk definisi A, B, C, dan D di bawah ini, lalu ambil kesimpulannya.
int A[3][4] = {{2,4,5,5},{7,9,11,5},{0,2,2,1}};
A Kolom 0 Kolom 1 Kolom 2 Kolom 3
Baris 0 2 4 5 5
Baris 1 7 9 11 5
Baris 2 0 2 2 1
int B[2][3] = {3,5,7,9,0,4};
B Kolom 0 Kolom 1 Kolom 2
Baris 0 3 5 7
Baris 1 9 0 4
Jadi int B[2][3] = {3,5,7,9,0,4}; ekivalen dengan
int B[2][3] = {{3,5,7},{9,0,4}};
int C[2][3] = {1,10,5,6};
C Kolom 0 Kolom 1 Kolom 2
Baris 0 1 10 5
Baris 1 6 0 0
Jadi int C[2][3] = {1,10,5,6}; ekivalen dengan
int C[2][3] = {1,10,5,6};
int D[3][2] = {{1},{10,5},{6}};
D Kolom 0 Kolom 1
Baris 0 1 0
Baris 1 10 5
Baris 2 6 0
Jadi, int D[3][2] = {{1},{10,5},{6}}; ekivalen dengan
int D[3][2] = {{1},{10,5},{6}};
2. Inisialisasi elemen-elemen array secara individu melalui indeksnya masing-masing
24
Sintaksis pengisian nilai ke dalam indeks tertentu dari sebuah array:
nama_array[indeks_pada_dimensi1][indeks_pada_dimensi2]=nilai;
Contoh:
double A[2][3]; // deklarasi array
A[0][0] = 3.3; // inisialisasi A[0][0]
A[1][1] = 1.5; // inisialisasi A[1][1]
A[2][0]= 2.43; // inisialisasi A[2][0]
// dst.
Jika nilai-nilai elemen array memiliki pola tertentu, inisialisasinya dapat memanfaatkan
mekanisme seleksi dan/atau perulangan. Contohnya, deklarasi dan inisialisasi array 2x2 B yang
berelemen integer dengan nilai masing-masing 0,0,1, dan 1, sebagai berikut:
int B[2][2];
for(int i=0; i<2; i++){
for(int j=0; j<2, j++){
B[i][j]=i;
}
}
2.3.3 Akses Array Dua Dimensi
Setelah sebuah array dua dimensi didefinisikan, elemen array dapat diakses dengan cara
memanggil nama dan nomor indeks sesuai dimensinya, seperti ekspresi berikut ini:
namaarray[indekspadadimensi1][indekspadadimensi2]
Sebagai contoh, lihat pernyataan berikut:
int A[2][3] = {2,4,5,7}; // deklarasi A
printf(“A[2][3]: %d\n”, A[2][3]); // akses A[2][3]
Contoh lainnya, sebuah array B yang tiap elemennya dicetak ke monitor dapat ditulis sebagai
berikut:
char B[2][2]={1,1,5,2,4};
for(int i=0; i<2; i++){
for(int j=0; j<2;i++){
printf(“B[%d][%d]:%d\n”,i,j,B[i][j]);
}
2.3.4 Array Dua Dimensi sebagai Parameter Fungsi
Seperti pada array satu dimensi, pengiriman parameter array dua dimensi pada fungsi juga
dilakukan by reference. Prototipe fungsi tersebut dapat dituliskan dalam sintaksis berikut:
tipedatakembalian namafungsi(tipedata **parameterformal);
atau
25
tipedatakembalian namafungsi(tipedata parameterformal[][jumlahelemen]);
atau
tipedatakembalian namafungsi(tipedata parameterformal[jumlahelemen]
[jumlahelemen]);
Gambar 2.9 berikut mencontohkan penggunaan array sebagai parameter fungsi.
123456789
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
void cetak(int A[2][3]){
for(int i=0; i<2; i++){
for(int j=0; j<3; j++){
printf("A[%d][%d]=%d\n",i,j,A[i][j]);
}
}
}
int main(){
int Y[2][3]={1,2,3,4};
cetak(Y);
system("pause");
return(0);
}
Gambar 2.9
2.4 Tugas
Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
26
3 BAB 3: Pointer Lanjutan - Alokasi Memori Dinamik
Pokok bahasan:
 Alokasi memori dengan malloc dan new
 Dealokasi memori dengan free dan delete
 Realokasi memori dengan realloc
27
3.1 Pendahuluan
Pada bab sebelumnya telah dijelaskan tentang konsep dasar pointer dan bagamaina
mendeklarasikan dan mendefinisikannya dengan cara referensi. Contoh-contoh yang diberikan
setelah itu untuk inisialisasi atau pendefinisian pointer hanya menggunakan cara referensi, yaitu
membuat atau mengubah nilai pointer itu sehingga menunjuk ke variabel yang sudah ada
sebelumnya. Sesungguhnya ini hanya salah satu cara, masih ada yang lainnya. Kita dapat
membuat pointer tersebut menunjuk ke lokasi data yang baru yang belum dimiliki oleh variabel
manapun. C/C++ menyediakan fasilitas untuk mengaplikasikan cara kedua di atas.
3.2 Pengalokasian Memori Secara Dinamik
Proses membuat pointer menunjuk ke lokasi data yang baru yang belum dimiliki oleh variabel
manapun dinamakan alokasi memori dinamik dan pointernya sendiri sering disebut dengan pointer
dinamik. Kondisi ini disebut dinamik karena dua hal. Pertama, jumlah rangkaian memori yang
dialokasikan dapat diubah oleh pemrogram atau berdasarkan masukan pengguna, selama
memorinya tersedia. Dengan demikian kita dapat membuat semacam array ‘dinamik’ yang jumlah
elemennya dapat diubah-ubah, mengatasi keterbatasan array konstan yang jumlah elemennya
selalu tetap. Kedua, pengalokasian memori ini dilakukan saat eksekusi program atau run-time. Hal
ini memungkinkan kita untuk meminta pengguna memasukkan jumlah elemen dari array ‘dinamik’
tersebut.
Konsep yang akan dibahas berikutnya adalah fasilitas C/C++ yang dapat digunakan untuk
implementasi alokasi memori dinamik
3.2.1 Fungsi malloc
Untuk mengalokasikan memori secara dinamik kita dapat menggunakan fungsi malloc yang
terdapat pada pustaka standar C. Prototipe fungsi ini memiliki sintaksis berikut:
void * malloc(size_t size);
Parameter:
Parameter fungsi ini (size) adalah ukuran blok memori dalam bytes yang dipesan ke
malloc.
Kembalian:
Jika pemesanan memori sukses, fungsi ini mengembalikan sebuah pointer yang menunjuk
pada awal blok tersebut. Isi dari blok-blok tersebut tidak diinisialisasikan (tidak terdefinisi).
28
Tipe data kembalian fungsi ini adalah void*, yang dapat di-cast (dikonversi paksa) ke tipe
data yang bisa didereferensikan.
Jika alokasi memori gagal, sebuah null pointer akan dikembalikan.
Perhatikan contoh penggunaan malloc pada gambar 3.1 di bawah ini.
123456789
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>
int main(){
int *A, *B;
A=(int*)malloc(sizeof(int));
if(A!=NULL){
*A = 100;
printf("*A=%d\n",*A);
} else{
printf("Alokasi memori gagal.");
}
B=(int*)malloc(5*sizeof(int));
if(B!=NULL){
for(int i=0; i<5; i++){
*(B+i) = i;
printf("*(B+%d)=%d\t",i,*(B+i));
printf("B[%d]=%d\n",i,B[i]);
}
} else{
printf("Alokasi memori gagal.");
} free(A);
A = NULL;
free(B);
B = NULL;
system("pause");
return 0;
}
Gambar 3.1
Pada contoh di atas dua buah pointer dideklarasikan kemudian dialokasikan memori yang ditunjuk
oleh mereka. Perhatikan baris ke-7 dan ke-16, lalu amati perbedaan dari keduanya. Ambil
kesimpulan dari perbedaan tersebut dan bandingkanlah dengan gambar 3.2 di bawah ini.
29
Gambar 3.2
Perhatikan juga pernyataan kondisional pada baris ke-7 sampai ke-15, dan pada baris ke-16
sampai ke-22. Pikirkanlah kenapa pernyataan kondisional ini diperlukan.
Cobalah amati baris ke-20 dan ke-21 berikut keluarannya pada monitor. Ambillah kesimpulan dari
kedua pernyataan pada baris-baris tersebut.
3.2.2 Operator new
Operator new adalah operator dalam C++ (bukan C) yang memiliki kegunaan yang sama dengan
malloc. Operator ini memiliki sintaksis penggunaan yang lebih singkat daripada milik malloc,
seperti berikut:
namapointer = new tipedata;
atau
namapointer = new tipedata[jumlahelemen];
Cobalah untuk mengubah kode pada gambar 3.1 untuk alokasi memori dinamik dari malloc
menjadi new.
3.3 Dealokasi atau Pembebasan Memori
Memori yang dialokasikan dengan malloc atau new dapat bertahan sampai program usai. Selama
itu, walaupun sudah tidak digunakan lagi, memori tersebut tidak dibebaskan secara otomatis oleh
program atau sistem operasi. Pemrogram harus membebaskan memori itu secara eksplisit. C/C++
menyediakan sarana ini dengan fungsi free (C) dan operasi delete (C++) yang akan dijelaskan
sebentar lagi.
Sebagai catatan, kebanyakan program menggunakan memori untuk keperluan singkat. Suatu saat
dia dibutuhkan, setelah itu tidak lagi. Karena kapasitas memori terbatas, sebaiknya memori yang
sudah tidak dipakai dibebaskan agar dapat digunakan untuk operasi yang lainnya.
30
3.3.1 Fungsi free
Protitpe fungsi free memiliki bentuk sebagai berikut:
void free(void * ptr);
Parameter:
Parameter fungsi ini (ptr) adalah pointer yang menunjuk pada blok memori yang akan
dibebaskan dan sebelumnya dialokasikan dengan malloc atau fungsi lainnya, . Jika ptr
bernilai NULL, maka fungsi ini tidak melakukan apa-apa.
Kembalian:
Fungsi ini tidak memberikan nilai kembalian.
Catatan:
Walaupun fungsi ini membebaskan blok memori yang ditunjuk oleh ptr, nilai ptr tetap sama
dengan sebelumnya (alamat memori yang sudah dibebaskan), bukan NULL. Blok memori
bebas sudah dapat digunakan oleh operasi lain. Mungkin ini agak membingungkan, tetapi
seperti inilah implementasi fungsi free pada bahasa C. Untuk mencegah kesalahan dalam
penggunan ptr berikutnya (agar ptr tidak dikira bernilai NULL), setelah operasi free
tuliskan:
ptr = NULL;
atau
ptr = 0;
Contoh penggunaan fungsi ini dapat dilihat pada baris ke-27 sampai ke-30 pada gambar 3.1
sebelumnya.
3.3.2 Operator delete
Operator ini memiliki fungsi yang sama dengan free pada C. Sintaksis penggunaan operator ini
adalah:
/* untuk pointer yang menunjuk pada satu blok memori yang berisi 1 unit
tipe data tertentu */
delete ptr;
atau
/* untuk pointer yang menunjuk pada satu blok memori yang berisi lebih
dari 1 unit tipe data tertentu*/
delete [] ptr;
31
Cobalah untuk mengubah kode pada gambar 3.1 untuk pembebasan memori dinamik, dari free
menjadi delete.
3.4 Realokasi Memori
Sebuah pointer yang sudah dialokasikan dengan malloc atau fungsi lainnya dapat direalokasikan
kembali untuk mengubah ukuran dari memori yang ditunjuknya. Fungsi yang dapat digunakan
adalah realloc dan bentuk dari prototipenya adalah sebagai berikut:
void * realloc(void * ptr, size_t size);
Parameter:
ptr: Pointer yang akan direalokasikan dan sebelumnya menunjuk pada blok memori yang
dialokasikan dengan malloc atau fungsi lainnya. Jika ptr bernilai NULL, maka fungsi ini
akan mengalokasikan blok memori baru dan pointer yang menunjuk pada blok ini
dikembalikan oleh fungsi ini.
size: Ukuran baru memori yang akan dialokasikan dalam bytes. Jika size bernilai 0,
maka blok memori yang sebelumnya dialokasikan untup ptr akan dibebaskan dan sebuah
NULL pointer akan dikembalikan oleh fungsi ini.
Kembalian:
Fungsi ini mengembalikan sebuah pointer yang menunjuk pada blok memori yang telah
direalokasikan. Blok memori ini mungkin berlokasi sama dengan yang sebelumnya atau
berada pada lokasi baru.
Tipe pointer ini adalah void*, yang dapat di-cast (dikonversi paksa) ke tipe data pointer
yang diinginkan agar dapat didereferensi.
Isi dari blok memori yang lama akan dipertahankan sampai sejumlah ukuran blok memori
yang baru. Jika ukuran blok memori yang baru lebih besar dari yang lama, isi dari bagian
memori yang baru ini tidak terdefinisi.
Jika Jika fungsi ini gagal merealokasikan blok memori yang diminta, sebuah NULL pointer
akan dikembalikan dan ptr tetap menunjuk pada blok memori yang lama.
Sebagai contoh aplikasi fungsi realloc, cobalah untuk menambahkan kode di antara baris ke-26
dan ke-27 pada gambar 3.1 yang merealokasikan pointer A dan B masing-masing ke 5 unit
memori baru sesuai tipe data masing-masing. Selanjutnya isikan blok memori baru dari A dengan
5 bilangan ganjil mulai dari bilangan 1 dan blok memori baru dari B dengan 5 bilangan genap
mulai dari bilangan 2. Tampilkan seluruh isi blok memori dari A dan B ke layar monitor.
32
3.5 Tugas
 Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
 Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
 Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
33
4 BAB 4: String
Pokok bahasan:
 Array of characters
 Deklarasi string
 Inisialisasi dan pendefinisian string
 Penanganan string
34
4.1 Pendahuluan
Sebuah string pada dasarnya adalah serangkaian karakter yang disusun berurutan. Sementara itu
karakter sendiri adalah simbol yang diambil dari satu set alphabet tertentu. Dalam bahasa C, string
ini dapat diimplementasikan dalam array yang berlemen karakter alias array of characters dengan
serangkaian karakter yang diakhiri dengan karakter null. Selanjutnya untuk mendeklarasikan dan
mendefinisikan string, ada beberapa cara yang dapat dilakukan, seperti yang akan dibahas dalam
sub bab berikutnya.
Dalam bahasa C++, string sudah diimplementasikan sebagai sebuah tipe data tersendiri yang
didefinisikan dalam pustaka standar C++. String dengan model ini berada di luar bahasan bab ini.
4.2 Deklarasi String
4.2.1 Deklarasi via Array of Characters
Sebagai array of characters, string dapat dideklarasikan dengan sintaksis sebagai berikut:
tipedatachar namastring[jumlahelemen];
Sebagai contoh, untuk mendeklarasikan sebuah string bernama str yang akan memiliki
maksimum 15 buah karakter (termasuk karakter null), pernyataannya adalah:
char str[5];
Saat pernyataan ini dijalankan, str dialokasikan 5 unit memori bertipe char seperti diilustrasikan
pada gamber 4.1 berikut. Cara menginisialisasi string ini akan dibahas pada sub bab berikutnya.
str
str[0] str[1] str[2] str[3] str[4]
char char Char char char
Gambar 4.1
4.2.2 Deklarasi via Pointer
Seperti telah diketahui, array adalah pointer konstan. Variabel bertipe array menyimpan alamat
dari elemennya yang pertama (indeks ke-0) sejak dideklarasikan sampai seterusnya. Selain itu,
array juga memiliki ‘ekivalensi’ dengan pointer umumnya (sub bab 2.2.4). Karena kedekatan ini,
sebuah pointer to character dapat dideklarasikan untuk menunjuk pada sebuah string dengan cara
referensi ke array string yang ada maupun dengan alokasi memori dinamik.
35
Referensi
Proses ini sebenarnya tidak sepenuhnya merupakan deklarasi sebuah string. Hal ini karena string
yang ditunjuk oleh pointer yang bersangkutan sebenarnya sudah dideklarasikan sebelumnya via
array of characters. Di bawah ini adalah contoh deklarasi sebuah pointer yang kemudian diset
untuk menunjuk pada sebuah string yang belum terdefinisi.
char str[5];
char * p;
p = str;
str[0]
str[2]
str[1]
str[3]
str[4]
char str[5];
char *p; p
str[0]
str[2]
str[1]
str[3]
str[4]
p = str; p
Gambar 4.2
Inisialisasi string ini akan dibahas pada sub bab selanjutnya.
Alokasi memori dinamik
Untuk mengalokasi memori secara dinamik, kita dapat menggunakan fungsi malloc atau fungsi
lain yang relevan (lihat bab 3). Memori yang dialokasikan akan digunakan untuk menampung
karakter pada string yang bersangkutan. Berikut contoh deklarasi pointer to char and
pengalokasian memorinya untuk membuat sebuah string.
char * p;
p = (char*)malloc(5*sizeof(char));
Proses ini dapat diilustrasikan sebagai berikut:
36
char *p; p
p[0]
p[2]
p[1]
p[3]
p[4]
p=(char*)malloc(5*sizeof(char)); p
// jika alokasi memori berhasil
Gambar 4.3
Inisialisasi string ini akan dibahas pada sub bab selanjutnya.
4.3 Inisialisasi dan Pendefinisian String
Setelah dideklarasikan, string dapat diinisialisasikan atau didefinisikan dengan beberapa cara
berikut.
4.3.1 Inisialisasi via Array
1. Inisialisasi dalam satu pernyaatan dengan deklarasi
Contoh:
char s1[] = {‘h’,’i’,’\0’};
char s2[8] = {‘h’,’e’,’l’,’l’,’o’,’\0’};
char s3[] = “salam”;
Inisialisasi s1 dan s2 adalah inisialisasi dengan cara yang ‘primitif’, yaitu dengan menuliskan
setiap karakter satu per satu dalam {}. Aturan array untuk penulisan jumlah elemen array
(lihat bab 2) tetap berlaku. Yang harus diingat juga adalah bahwa sebuah string (yang valid)
harus diakhiri dengan karakter null atau karakter nol (‘\0’).
37
Gambar 4.4
Perhatikan hasil inisialisasi s2 pada gambar 4.4. Di sini s2 diinisialisi dengan 6 karakter tertulis
(termasuk karakter null), tetapi sebenarnya s2 tetap memiliki 8 karakter seperti deklarasinya.
Sisa karakter yang tidak didefinisikan menempati s2[6] dan s2[7] digambarkan dengan
kotak yang diarsir, biasanya diisikan dengan nilai default karakter null.
Sementara itu, s3 diinisialisasi dengan konstanta atau literal string “salam”. Inisialisasi ini
ekivalen dengan pernyataan berikut:
char s3[] = {‘s’,’a’,’l’,’a’,’m’,’\0’};
Jika diilustrasikan, inisialisasi ini akan menghasilkan kondisi berikut:
Gambar 4.5
2. Inisialisasi elemen-elemen array secara individu melalui indeksnya masing-masing
Cara ini juga masih dianggap cara yang ‘primitif’. Sintaksis pengisian nilai ke dalam indeks
tertentu dari sebuah array string:
namastring[indeksarray] = nilai;
Contoh:
char str[3]; // deklarasi string via array
str[0] = ‘h’; // inisialisasi elemen dari str pada indeks ke-0
str[1] = ‘i’; // inisialisasi elemen dari str pada indeks ke-1
str[2] = ‘\0’; // inisialisasi elemen dari str pada indeks ke-2
38
3. Inisialisasi dengan menyalin dari sebuah konstanta string atau isi string lainnya dengan fungsi
strcpy
Cara ini lebih sering dipakai karena lebih praktis. Contoh penyalinan string:
char str1[15];
char str[] = “Selamat pagi”;
strcpy(str1,”Hello World”);
// Coba cek isi str1
printf(“str1: %s\n”, str1);
strcpy(str1,str2);
// Coba cek isi str1
printf(“str1: %s\n”, str1);
Untuk membuat program yang aman, panjang string yang akan disalin ke array target
haruslah sama dengan atau lebih kecil daripada ukuran array target penyalinan dikurangi satu.
Hal ini untuk menghindari inisialisasi atau pendefinisian nilai yang melewati batas array.
Perlu diingat, ukuran array selalu konstan sejak dideklarasikan. strcpy tidak dapat
menambah ukuran array target penyalinan untuk menampung string yang lebih panjang
daripada batas array ini.
4.3.2 Inisialisasi via Pointer
Inisialisasi string via pointer digunakan untuk array string yang ditunjuk oleh pointer dengan
referensi atau yang dideklarasikan melalui pointer dinamik.
Referensi
Inisialisasi dengan cara ini melanjutkan deklarasi string via pointer yang sudah dibahas
sebelumnya (sub bab 4.2.2). Jika terdapat pernyataan berikut:
char str[5];
char * p;
p = str;
maka kita dapat menggunakan pointer p untuk mengisikan string str baik secara per karakter
melalui indeksnya atau per string dengan fungsi strcpy. Contoh:
// pengisian per karakter untuk membuat string “you”
p[0]=’y’; p[1]=’o’; p[2]=’u’; p[3]=’\0’;
// Coba cek isi p dan str
printf("p: %s, str: %s\n", p,str);
for(int i=0; i<5; i++){
printf("p[%d]:%c, \t", i,p[i]);
printf("str[%d]:%c\n", i,str[i]);
}
39
// mengganti isi string str dengan “kamu” via strcpy
strcpy(p,”kamu”);
// Coba cek lagi isi p dan str
printf("p: %s, str: %s\n", p,str);
for(int i=0; i<5; i++){
printf("p[%d]:%c, \t", i,p[i]);
printf("str[%d]:%c\n", i,str[i]);
}
str[0]
str[2]
str[1]
str[3]
str[4]
char str[5];
char *p; p
str[0]
str[2]
str[1]
str[3]
str[4]
p = str; p
str[0]
str[2]
str[1]
str[3]
‘y’
‘o’
‘u’
‘\0’
str[4]
p[0] = ‘y’; p
p[1] = ‘o’;
p[2] = ‘u’;
p[3] = ‘\0’;
str[0]
str[2]
str[1]
str[3]
‘k’
‘a’
‘m’
‘u’
str[4] ‘\0’
strcpy(p,”kamu”); p
Gambar 4.6
Alokasi memori dinamik
Setelah sebuah pointer dialokasikan memori secara dinamik dengan cara berikut:
char * p;
40
p = (char*)malloc(5*sizeof(char));
maka, seperti juga pada cara referensi, kita bisa mengisikan mengisikan string str baik secara per
karakter melalui indeksnya atau per string dengan fungsi strcpy. Contoh:
// pengisian per karakter untuk membuat string “you”
p[0]=’y’; p[1]=’o’; p[2]=’u’; p[3]=’\0’;
// Coba cek isi p
printf(“p: %s\n”, p);
for(int i=0; i<5; i++){
printf("p[%d]:%c, \t", i,p[i]);
printf("str[%d]:%c\n", i,str[i]);
} // mengganti isi string str dengan “
saya” via strcpy
strcpy(p,”saya”);
// Coba cek lagi isi p
printf(“p: %s\n”, p);
for(int i=0; i<5; i++){
printf("p[%d]:%c, \t", i,p[i]);
printf("str[%d]:%c\n", i,str[i]);
}
char *p; p
p[0]
p[2]
p[1]
p[3]
p[4]
p=(char*)malloc(5*sizeof(char)); p
// jika alokasi memori berhasil
p[0]
p[2]
p[1]
p[3]
‘y’
‘o’
‘u’
‘\0’
p[4]
p[0] = ‘y’; p
p[1] = ‘o’;
p[2] = ‘u’;
p[3] = ‘\0’;
p[0]
p[2]
p[1]
p[3]
‘s’
‘a’
‘y’
‘a’
p[4] ‘\0’
strcpy(p,”saya”); p
Gambar 4.7
41
4.4 Penanganan String
Ada banyak fungsi dalam pustaka standar C yang dapat dipakai untuk menangani dan
memanipulasi string. Di antaranya adalah strlen, strcmp, strcpy, strncpy, strcat.
4.4.1 Fungsi strlen
Deklarasi:
size_t strlen(const char *str);
Fungsi ini menghitung panjang string str, mengembalikan jumlah karakter pada string, tapi tidak
termasuk karakter null pemberhenti string. size_t adalah unsigned int.
Contoh:
int len;
char *string;
len = strlen (string);
4.4.2 Fungsi strcmp
Deklarasi:
int strcmp(const char *str1, const char *str2);
Fungsi ini membandingkan dua buah string, yang ditunjuk oleh str1dan yang ditunjuk oleh str2.
Jika str1 and str2 memiliki nilai string yang sama (equal, bukan identical), fungsi ini
mengembalikan 0.
Jika str1 < str2 (sesuai urutan alfabetiknya pada tabel ASCII), fungsi ini mengembalikan nilai
kurang dari 0.
Jika str1 > str2 (sesuai urutan alfabetiknya pada tabel ASCII), fungsi ini mengembalikan nilai lebih
dari 0.
Contoh:
int value;
char *s1,*s2;
value = strcmp(s1,s2);
4.4.3 Fungsi strcpy
Deklarasi:
42
char *strcpy(char *str1, const char *str2);
Fungsi ini menyalin string yang ditunjuk oleh str2 ke str1. Penyalinan ini sampai dan mencakup
karakter null pemberhenti pada str2. Jika str1 dan str2 overlap , perilakunya tidak terdefinisi.
Fungsi ini mengembalikan argument str1.
Contoh:
char *to,*from;
to = strcpy (to,from);
4.4.4 Fungsi strncpy
Deklarasi:
char *strncpy(char *str1, const char *str2, size_t n);
Fungsi ini menyalin sampai sejumlah n karakter dari string yang ditunjuk oleh str2 ke str1.
Penyalinan berhenti saat n karakter tersalin atau karakter null pemberhenti pada str2 dicapai. Jika
karakter null dicapai, karakter null akan terus disalin ke str1 sampai sejumlah n karakter tersalin.
Fungsi ini mengembalikan argumen str1.
Contoh:
char *to,*from;
int n;
to = strncpy (to,from,n);
4.4.5 Fungsi strcat
Deklarasi:
char *strcat(char *str1, const char *str2);
Fungsi ini menyambungkan (concatenate) string yang ditunjuk oleh str2 ke akhir dari string yang
ditunjuk oleh str1. Karakter null pemberhenti dari str1 ditumpuki (overwritten). Penyalinan
berhenti ketika karakter pemberhenti dari str2 telah tersalin. Jika terjadi overlapping, hasilnya
tidak terdefinisi.
Fungsi ini mengembalikan argumen str1.
Contoh:
char *s1 = "string one";
char *s2 = "string two";
int main (){
43
char buffer[255];
strcat(buffer,s1);
strcat(buffer,s2);
}
4.4.6 Fungsi strncat
Deklarasi:
char *strncat(char *str1, const char *str2, size_t n);
Fungsi ini menyambungkan (concatenate) string yang ditunjuk oleh str2 ke akhir dari string yang
ditunjuk oleh str1 sampai sepanjang n karakter. Karakter null pemberhenti dari str1 ditumpuki
(overwritten). Penyalinan berhenti ketika sejmlah n karakter telah tersalin atau karakter
pemberhenti dari str2 telah tersalin. Sebuah karakter null pemberhenti selalu ditambahkan ke
str1. Jika terjadi overlapping, hasilnya tidak terdefinisi.
Fungsi ini mengembalikan argumen str1.
Contoh:
char *onto,*new,*this;
new = strncat(onto,this,n);
4.4.7 Fungsi atof
Deklarasi:
double atof(const char *str);
Fungsi ini mengonversi string yang ditunjuk oleh str ke tipe double (floating-point number).
Karakter whitespace yang ada di awal string diabaikan (space, tab, carriage return, new line,
vertical tab, atau formfeed). Konversi berhenti saat karakter tak dikenal dicapai.
Jika sukses, fungsi ini akan mengembalikan angka hasil konversi. Jika konversi tidak dapat
dilakukan, fungsi ini akan mengembalikan 0. Jika nilai yang dikonversi di luar jangkauan tipe
double, HUGE_VAL akan dikembalikan dengan tanda yang sesuai dan ERANGE disimpan ke
variable errno. Jika nilai yang dikonversi terlalu kecil untuk dikembalikan sesuai dengan tipe
double, maka nol akan dikembalikan dan ERANGE disimpan dalam variabel errno.
Contoh:
double x;
char *stringptr;
x = atof(stringptr);
44
4.4.8 Fungsi atoi
Deklarasi:
int atoi(const char *str);
Fungsi ini mengonversi string yang ditunjuk oleh str ke tipe double (floating-point number).
Karakter whitespace yang ada di awal string diabaikan (space, tab, carriage return, new line,
vertical tab, atau formfeed). Konversi berhenti saat karakter tak dikenal dicapai.
Jika sukses, fungsi ini akan mengembalikan angka hasil konversi. Jika konversi tidak dapat
dilakukan, fungsi ini akan mengembalikan 0. Jika nilai yang dikonversi di luar jangkauan tipe
double, HUGE_VAL akan dikembalikan dengan tanda yang sesuai dan ERANGE disimpan ke
variable errno. Jika nilai yang dikonversi terlalu kecil untuk dikembalikan sesuai dengan tipe
double, maka nol akan dikembalikan dan ERANGE disimpan dalam variabel errno.
Fungsi ini mengonversi string yang ditunjuk oleh str ke integer (type int). Any initial whitespace
characters are skipped (space, tab, carriage return, new line, vertical tab, or formfeed). The
number may consist of an optional sign and a string of digits. Conversion stops when the first
unrecognized character is reached.
On success the converted number is returned. If the number cannot be converted, then 0 is
returned.
Contoh:
int i;
char *stringptr;
i = atoi(stringptr);
4.4.9 Fungsi atol
Declaration:
long int atol(const char *str);
The string pointed to by the argument str is converted to a long integer (type long int). Any
initial whitespace characters are skipped (space, tab, carriage return, new line, vertical tab, or
formfeed). The number may consist of an optional sign and a string of digits. Conversion stops
when the first unrecognized character is reached.
On success the converted number is returned. If the number cannot be converted, then 0 is
returned.
long i;
char *stringptr;
45
i = atol(stringptr);
4.5 Tugas
 Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
 Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
 Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
46
5 BAB 5: Struct
Pokok bahasan:
 Struktur (struct)
 Deklarasi tipe struct dan variabel bertipe struct
 Inisialisasi dan akses anggota struct
 Keyword typedef
 Union (union)
 Deklarasi tipe struct dan variabel bertipe struct
 Inisialisasi dan akses anggota struct
47
5.1 Pendahuluan
Seiring dengan semakin kompleksnya sebuah program, data yang berada di dalamnya pun juga
menjadi bertambah kompleks. Variabel dari tipe data primitif dan array sudah tidak lagi dapat
memenuhi kebutuhan program ini. Yang dibutuhkan adalah sebuah struktur data, yang dapat
mengombinasikan berbagai tipe data dalam sebuah struktur yang bermakna. Dari sinilah
diperkenalkan sebuah tipe data baru yaitu tipe struct, atau dalam bahasa lain record.
Tipe struct ini biasanya dibahas bersama dengan tipe lain yaitu union. Sebenarnya kedua tipe
ini memiliki tujuan yang berbeda. Bab ini akan membahas keduanya.
5.2 Struktur atau struct
struct adalah sebuah paket yang terdiri dari satu atau lebih variabel yang dikelompokkan di
bawah sebuah nama. struct berbeda dengan array dalam hal tipe data anggotanya; sebuah
struct dapat memiliki anggota-anggota dari tipe data yang berbeda, sementara array hanya
berisi elemen-elemen yang bertipe data sama.
5.3 Deklarasi tipe struct dan variabel bertipe struct
Bentuk umum deklarasi tipe struct adalah sebagai berikut:
struct tipestruktur{
tipeanggota1 namaanggota1;
tipeanggota2 namaanggota1;
...
};
Kemudian jika kita hendak membuat sebuah variabel bertipe struct di atas, bentuk penulisannya
adalah:
struct tipestruktur namavariabel;
Contoh deklarasi sebuah tipe struct dengan nama tertentu dan deklarasi variabel dari tipe struct
tersebut adalah sebagai berikut:
// deklarasi tipe struct Employee
struct Karyawan{
char id[15];
char nama[20];
char alamat[50];
double gaji;
};
// deklarasi variabel emp1 dan emp2 bertipe struct Employee
48
struct Karyawan k1;
struct Karyawan k2;
Perlu ditekankan bahwa struct adalah sebuah kategori tipe data yang para anggotanya dapat
memiliki tipe data berbeda-beda sesuai kebutuhan kita. Oleh karena itu, sebelum kita dapat
menggunakan sebuah struct sebagai tipe data sebuah variabel, tipe struct ini perlu kita
deklarasikan dahulu.
Pada contoh di atas struct Karyawan digunakan untuk memodelkan tipe data seorang
karyawan, yaitu memiliki id, nama, alamat, dan gaji. Selanjutnya struct Karyawan ini dapat
digunakan untuk membuat data seorang karyawan tertentu. Pada contoh di atas, k1 dan k2,
masing-masing mewakili data seorang karyawan. Id, nama, alamat, dan gaji masing-masing
karyawan ini dapat diisikan atau diakses kemudian. Proses inisialisasi dan akses data ini akan
dibahas pada sub bab berikutnya.
Bandingkanlah metode di atas dengan jika kita memodelkan data karyawan di atas menggunakan
array. Betapa terbatasnya data karyawan yang dapat kita modelkan dengan array karena array
hanya dapat berisi anggota atau elemen yang berasal dari tipe data yang sama.
Penulisan deklarasi di atas dapat juga disingkat menjadi:
struct Karyawan{
char id[15];
char nama[20];
char alamat[50];
double gaji;
} k1, k2;
Dalam C++ deklarasi sebuah variabel yang bertipe data struct boleh menghilangkan keyword
struct, sehingga untuk contoh di atas:
struct Karyawan k1;
cukup dituliskan menjadi:
Karyawan k1;
5.4 Keyword typedef
typedef digunakan untuk mengasosiasikan suatu tipe dengan simbol tertentu untuk menghindari
penulisan tipe data yang berulang. Perhatikan contoh berikut:
typedef int bilbulat;
struct Karyawan{
char id[15];
char nama[20];
char alamat[50];
49
double gaji;
};
typedef Karyawan Pegawai;
typedef struct {
char nim[15];
char nama[20];
int angkatan;
} Mahasiswa;
// sekarang bilbulat adalah suatu tipe data
// x dideklarasikan sebagai bilbulat (i.e. integer)
bilbulat x;
x = 10;
// sekarang Pegawai adalah suatu tipe data
// p1 dideklarasikan sebagai Pegawai (i.e. struct Karyawan)
Pegawai p1;
// sekarang Mahasiswa adalah suatu tipe data
// m1 dideklarasikan sebagai Pegawai Mahasiswa
Mahasiswa m1;
Dengan typedef di atas kita mendenisikan tiga tipe data: bilbulat, Pegawai, dan Mahasiswa.
Setelah itu kita menggunakannya seperti tipe data biasa untuk mendeklarasikan variabel.
5.5 Inisialisasi dan Akses Anggota struct
Anggota struct dapat diinisialisasi atau diakses dengan memanggil nama variabel struct
tersebut diikuti dengan simbol tertentu (i.e. operator titik (.) atau operator panah (->), tergantung
bagaimana variabel struct dideklarasikan) dan nama anggota yang bersangkutan. Jika variabel
struct tidak dedeklarasikan melalui pointer, maka anggotanya dapat diakses dengan sintaksis
ekspresi berikut:
namavariabelstruct.anggotastruct
Perhatikan contoh deklarasi struct Karyawan dan k1 sebelumnya. Untuk menginisialisasi
anggota k1, penulisannya adalah:
struct Karyawan k1;
strcpy(k1.id, “20110521”);
strcpy(k1.nama, “Lin Dan”);
strcpy(k1.alamat, “Jl RRC Jakpus”);
k1.gaji = 5250000;
50
5.6 Ruang Lingkup struct
struct mengikuti aturan ruang lingkup sebagaimana tipe data lainnya. Sebuat tipe struct
dapat menjadi global atau lokal tergantung pada di mana dia dideklarasikan. Demikian juga
variabel bertipe struct tersebut; jika dia dideklarasikan secara lokal, dia hanya dapat diakses di
dalam blok (yang dilingkupi oleh tanda {}) tempat dia dideklarasikan.
void buatVariabelStruct(){
/* Pernyatan di bawah ini ilegal, karena A adalah struct lokal
terhadap fungsi main*/
struct A a;
} int main(){
struct A{
int x;
float y;
};
struct A a;
}
5.7 Pointer to struct
Selain mendeklarasikan variabel bertipe struct, kita juga dapat membuat sebuah pointer yang
menunjuk pada obyek atau data struct, yang disebut dengan pointer to struct. Sebagai contoh,
dengan menggunakan contoh struct Karyawan di atas, kita bisa mendeklarasikan sebuah
pointer pk1 sebagai berikut:
struct Karyawan *pk1;
Kemudian, sebelum kita dapat menginisialisasi para anggota pk1, kita harus mengalokasikan dulu
kepada pk1 memori dengan jumlah yang memadai. Jika kita hanya menginginkan pk1 untuk
menunjuk pada satu (unit) struct Karyawan, maka alokasi memori untuk pk1 dapat dituliskan
sebagai berikut:
pk1 = (struct Karyawan*)malloc(sizeof(struct Karyawan));
Perhatikan bahwa untuk pk1 hanya dialokasikan 1 x sizeof(struct Karyawan) bytes.
Selanjutnya jika alokasi ini berhasil, para anggota pk1 dapat diinisialisasikan sebagai berikut:
strcpy(pk1->id, “007”);
strcpy(pk1->nama, “James Bond”);
strcpy(pk1->alamat, “London, UK”);
pk1->gaji = 1000;
51
Perhatikan penggunaan simbol panah (->) di atas. Simbol ini digunakan untuk mengakses anggota
struct yang ditunjuk oleh pointer. Tanda ini bisa juga digantikan dengan kombinasi tanda bintang
(*) dan titik (.) seperti pada contoh di bawah ini.
strcpy((*pk1).id, “007”);
strcpy((*pk1).nama, “James Bond”);
strcpy((*pk1).alamat, “London, UK”);
(*pk1).gaji = 1000;
5.8 Union
Seperti struct, union dapat digunakan untuk mendeklarasikan sekelompok data yang memiliki
tipe berlainan. Bedanya, pada union semua data anggota tersebut menduduki lokasi memori
yang sama. Karena sebenarnya pada satu saat sebuah alamat hanya dapat menyimpan satu
macam tipe data, maka pada satu saat union hanya dapat berisi salah satu dari anggotanya. Jadi,
union ini berperilaku seperti sebuah kontainer berukuran tertentu yang dapat menyimpan
berbagai macam tipe data.
Kegunaan utama dari union adalah untuk menghindari fragmentasi memori dengan membuat
sebuah ukuran data standar pada memori. Dengan demikian kita dapat memastikan bahwa setiap
bagian memori yang telah dibebaskan dari alokasi dinamik dapat dialokasikan lagi untuk variabel
yang memiliki tipe union sama. Ini adalah strategi umum pemrograman sistem yang memiliki
banyak variabel yang berkaitan dan dialokasikan secara dinamik.
Deklarasi, inisialisasi, akses, ruang lingkup, dan penggunaan pointer serta array pada union
memiliki sintaksis yang sama dengan pada struct.
Untuk mengilustrasikan persamaan dan perbedaan antara struct dan union, jalankanlah kode
di bawah ini.
123456789
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// deklarasi tipe struct SAkun
struct SAkun{
int id;
char nama[15];
};
// deklarasi tipe union UAkun
union UAkun{
int id;
char nama[15];
};
52
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int main(){
// deklarasi variabel bertipe struct SAkun
struct SAkun akun1;
// inisialissi data anggota akun1
akun1.id = 11;
strcpy(akun1.nama,”Bachdim”);
// cetak data anggota akun1
printf("akun1.id: %d\n", akun1.id);
printf("akun1.nama: %s\n\n", akun1.nama);
// cetak alamat akun1 dan alamat anggota akun1
printf("&akun1: %d\n", &akun1);
printf("&akun1.id: %d\n", &akun1.id);
printf("&akun1.nama:%d\n\n", &akun1.nama);
// cetak ukuran akun1 dan ukuran data anggota akun1
printf("sizeof(akun1): %d\n",sizeof(akun1));
printf("sizeof(akun1.id): %d\n",sizeof(akun1.id));
printf("sizeof(akun1.nama): %d\n\n\n",sizeof(akun1.nama));
// deklarasi variabel bertipe union UAkun
union UAkun akun2;
// inisialissi data anggota akun2
akun2.id = 22;
strcpy(akun2.nama,”Gonzales”);
// cetak data anggota akun2
printf("akun2.id: %d\n", akun2.id);
printf("akun2.nama: %s\n\n", akun2.nama);
// cetak alamat akun2 dan alamat anggota akun2
printf("&akun2: %d\n", &akun2);
printf("&akun2.id: %d\n", &akun2.id);
printf("&akun2.nama:%d\n\n", &akun2.nama);
// cetak ukuran akun2 dan ukuran data anggota akun2
printf("sizeof(akun2.id): %d\n",sizeof(akun2.id));
printf("sizeof(akun2.nama): %d\n",sizeof(akun2.nama));
printf("sizeof(akun2): %d\n\n",sizeof(akun2));
system("PAUSE");
return 0;
}
Gambar 5.1
53
Secara khusus, perhatikanlah beberapa hal berikut. Amati baris ke-27sampai ke-30 dan hasil
eksekusinya. Hal ini menunjukkan bahwa lokasi anggota struct berbeda-beda dan alamat dari
struct tersebut sama dengan alamat dari anggota struct yang dideklarasikan pertama.
Bandingkanlah hasil ini dengan hasil eksekusi baris ke-47 sampai ke-50.
Kemudian, amati baris ke-32 sampai ke-35 dan hasil eksekusinya. Hal ini menunjukkan bahwa
ukuran dari struct sama dengan atau lebih besar sedikit daripada jumlah ukuran data anggotanya.
Bandingkan hasil ini dengan hasil eksekusi baris ke-52 sampai ke-55.
Perhatikan juga baris ke-19 sampai ke-25 dan hasil eksekusinya. Bandingkan dengan baris ke-39
sampai ke-45. Ambillah kesimpulan dari perbedaan hasil ini.
5.9 Tugas
 Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
 Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
 Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
54
6 BAB 6: Operasi File
Pokok bahasan:
 Pengertian file
 Saluran I/O standar: stdin dan stdout
 Penanganan file: tingkat tinggi vs tingkat rendah
 Posisi program pada file
 Membuka file
 Menutup file
 Membaca file
 Menulis file
 Contoh kasus
55
6.1 Pendahuluan
Bab ini akan membahas konsep file dan penggunaannya dalam bahasa C/C++. Pertama,
pengertian file akan diuraikan secara singkat. Penanganan file dibagi menjadi penanganan tingkat
tinggi dan tingkat rendah, dan ini akan dijelaskan selanjutnya. Beberapa fungsi pada pustaka
standar C untuk mengoperasikan files juga aka dibahas setelah itu. Seperti pada bab-bab
sebelumnya, bab ini akan diakhiri dengan tugas tentang yang operasi file, yang dapat
dikombinasikan dengan tugas dalam bab lainnya.
6.2 File
C/C++ memperlakukan informasi yang masuk ke atau keluar dari program sebagai ‘aliran’ data
(steam of data/bytes/bits). Dikatakan aliran karena pada proses ini data disusun secara berurutan
seperti sebuah aliran, untuk dipindahkan dari satu lokasi ke lokasi lainnya. Aliran bytes inilah yang
disebut juga sebagai file.
Dengan bantuan sistem operasi, sebuah program melihat files melalui sejumlah saluran atau
‘portal’ (masuk dan keluar). Untuk dapat membaca atau menulis pada sebuah file, program
tersebut harus membuka dulu salah satu saluran/portal yang sesuai. Dengan demikian
saluran/portal ini menyembunyikan hal-hal teknis yang terlalu detil yang bergantung pada sistem
operasi dari pemrogram. Untuk membaca data dari sebuah file, sebuah program cukup
membacanya dari portal file-nya. Dia tidak perlu berurusan dengan bagaimana data tersebut
sampai kepadanya. Begitu juga sebuah program yang menulis informasi pada sebuah file cukup
menyampaikannya pada salah satu portal ini. Sisa pekerjaannya akan dilakukan oleh sistem
operasi. Kesimpulannya, untuk menggunakan sebuah file, sebuah program harus melakukan
langkah-langkah berikut:
1. Membuka file untuk membaca atau menulis (i.e. memesan sebuah portal untuk mencari file
tersebut pada disk atau lokasi lainnya).
2. Membaca atau menulis pada file itu menggunakan fungsi-fungsi untuk menangani file yang
disediakan oleh pustaka standar.
3. Menutup file untuk membebaskan portal yang telah dipakai agar dapat digunakan oleh
program atau file lain.
Sebuah program membuka file dengan memanggil sebuah fungsi pada pustaka standar yang
mengembalikan sebuah pointer yang menunjuk pada file. Program tersebut dapat menggunakan
pointer ini untuk mengolah file tersebut dan untuk membedakannya dari file-file lainnya. Tipe
pointer to file ini dituliskan dalam bentuk FILE *, di mana FILE adalah sebuah struct khusus
yang didefinisikan pada <stdio.h>. FILE ini bukanlah file yang dimaksud sebenarnya, melainkan
56
sebuah struct yang dapat membantu kita untuk mengakses dan memanipulasi file yang
sebenarnya. Pointer to FILE inilah yang dapat diibaratkan sebagai sebuah saluran/portal.
6.3 Saluran I/O Standar: stdin dan stdout
Selama ini kita sudah sering menggunakan masukan standar dan keluaran standar pada sebuah
program. Masukan standar sering diasosiasikan dengan ‘keyboard’ dan keluaran standar dengan
monitor. Untuk membaca data yang dimasukkan melalui keyboard, sebuah program cukup
memanfaatkan saluran/portal masukan standar, yaitu stdin. Fungsi scanf yang sering kita
pakai itu sebenarnya membaca input dari user yang telah masuk ke dalam buffer (pada memori)
yang bisa dibayangkan sebagai bagian dari stdin. Sebaliknya, untuk menulis ke layar monitor,
sebuah program menggunakan saluran/portal keluaran standar stdout. Fungsi printf yang
juga sering kita gunakan itu hanya mengalirkan data yang kita hantarkan sebagai parameter
fungsi tersebut ke stdout.
stdin dan stdout bertipe pointer to FILE (FILE *). Berbeda dengan saluran/portal lainnya
yang harus dibuka dulu sebelum digunakan dan ditutup setelah dipakai, stdin dan stdout selalu
terbuka secara otomatis ketika program yang bersangkutan dijanlankan.
6.4 Penanganan File: Tingkat Tinggi vs Tingkat Rendah
C menyediakan dua tingkat penanganan file: penanganan file tingkat tinggi dan tingkat rendah.
File tingkat tinggi diperlakukan sebagai file teks. Data yang masuk ke file ini adalah data teks
sebagaimana yang nampak pada layar monitor, karakter per karakter. File yang ditulis dengan
fungsi penanganan file tingkat tinggi akan menghasilkan file teks yang dapat diedit dengan
program pengedit teks.
File tingkat tinggi juga dibaca sebagai file teks, sebagaimana input dari keyboard yang dibaca oleh
program. Dengan demikian, fungsi penanganan file tingkat tinggi bekerja dengan konsep yang
sama dengan fungsi I/O standar.
Penanganan file tingkat rendah, sebaliknya, mengelola data dalam format yang lebih rendah (lebih
dekat dengan mesin atau piranti keras) tanpa mengonversinya terlebih ke dalam format teks.
Karena itu fungsi-fungsi untuk menangani file level rendah ini kurang ‘programmer-friendly’, tetapi
dapat bekerja lebih cepat dan efisien.
Dalam modul ini kita akan memfokuskan bahasan pada penanganan file level tinggi. Kebanyakan
fungsi penanganan file tingkat tinggi mudah dikenali dari namanya yang dimulai dengan huruf ‘f’,
seperti:
fopen()
fclose()
57
fprintf()
fscanf()
fgets()
fputs()
6.5 Posisi Program pada File
Saat data dibaca dari sebuah file, sistem operasi mencatat posisi terkini program pada file
tersebut. Program tersebut cukup memanggil fungsi standar tertentu untuk ‘membaca bagian file
berikutnya’ dan sistem operasi akan menjalankan perintah ini dengan membaca bagian file
berikutnya dan memajukan posisi program pada file. Begitu seterusnya sampai posisi pada file
mencapai akhir dari file. Setiap karakter yang dibaca akan menyebabkan posisi program pada file
maju satu langkah.
Walaupun sistem operasi secara otomatis akan menangani banyak hal tentang posisi pada file,
sebuah program juga dapat mengontrol perubahan posisi pada file tersebut melalui beberapa
fungsi, seperti ungetc() misalnya, jika dibutuhkan. Tetapi pada kebanyakan kasus, hal ini tidak
diperlukan dan lebih baik dihindari. Pergerakan posisi yang kompleks pada file dapat
menyebabkan pergereakan kompleks dari mekanisme disk drive, yang pada akhirnya bisa
mengakibatkan kerusakan pada disk dan munculnya kesalahan.
6.6 Membuka File
Seperti telah dijelaskan pada sub bab 6.2 di atas, langkah pertama untuk menangani file adalah
membuka file tersebut. Pada C fungsi untuk membuka file adalah fopen, dengan deklarasi
berikut:
FILE *fopen(const char *filename, const char *mode);
Fungsi ini membuka file ditunjuk oleh filename. Paremeter mode dapat bernilai salah satu dari
string berikut:
r Mode baca file teks (r=read)
w Mode tulis file teks (w=write, memotong ukuran/panjang file menjadi 0, atau
membuat file baru)
a Mode sambung file teks untuk menulis (a = append, membuka atau membuat
file dan mengeset pointer file pada akhir file, end-of-file)
rb Mode baca file biner (rb=read binary)
58
wb Mode tulis file biner (wb=write binary, memotong ukuran/panjang file menjadi
0, atau membuat file baru)
ab Mode sambung file biner untuk menulis (ab=append binary, membuka atau
membuat file dan mengeset pointer file pada akhir file, end-of-file)
r+ atau +r Mode baca dan tulis file teks
w+ atau +w Mode baca dan tulis file teks (memotong ukuran/panjang file menjadi 0, atau
membuat file baru)
a+ atau +a Mode baca dan tulis file teks (membuka atau membuat file dan mengeset
pointer file pada akhir file, end-of-file)
r+b atau rb+
atau +rb
Mode baca dan tulis file biner
w+b atau wb+
atau +wb
Mode baca dan tulis file biner (memotong ukuran/panjang file menjadi 0, atau
membuat file baru)
a+b atau ab+
atau +ab
Mode baca dan tulis file biner (membuka atau membuat file dan mengeset
pointer file pada akhir file, end-of-file)
Jika file yang dimaksud tidak ada dan dibuka dengan mode baca (r), maka operasi buka file akan
gagal.
Jika file dibuka dengan mode sambung (append, a), maka seluruh operasi tulis akan dimulai dari
akhir dari file tersebut tanpa memedulikan posisi file saat ini.
Jika file dibuka dengan mode update (+), maka keluaran (tulis) tidak dapat langsung diikuti
dengan masukan (baca) tanpa diintervensi oleh fseek, fsetpos, rewind, atau fflush.
Jika operasi membuka file sukses, sebuah pointer to *FILE akan dikembalikan . Jika operasi ini
gagal, maka null pointer akan dikembalikan.
6.7 Menutup File
Untuk menutup file kita dapat menggunakan fungsi fclose dari pustaka standar C, dengan
deklarasi berikut:
int fclose(FILE *stream);
59
Fungsi ini menutup file yang ditunjuk oleh stream sekaligus mem-flush buffer yang ada. Proses
flush ini akan menyebabkan data yang tersisa pada buffer, jika ada, akan tertulis pada file.
Jika sukses menutup file, fungsi ini mengembalikan nilai 0. Sedangkan jika gagal, fungsi ini akan
mengembalikan EOF.
6.8 Menulis File
Ada beberapa fungsi dari pustaka standar C yang dapat digunakan untuk menulis file, diantaranya
adalah:
 fprintf
 fputc
 fputs
6.8.1 Fungsi fprintf
Deklarasi:
int fprintf(FILE *stream, const char *format, ...);
Fungsi ini menuliskan keluaran yang terformat dalam bentuk string pada parameter format ke
dalam stream.
Jika sukses, fungsi ini akam mengembalikan jumlah karakter yang tertulis pada file. Jika ada
kesalahan, -1 dikembalikan.
fprintf() ini memiliki kesamaan dengan printf().Parameter yang digunakan hanya berbeda
pada satu hal, yaitu pada fprint terdapat tambahan satu parameter: sebuah pointer to file.
Sebenarnya fprintf() berhubungan dengan printf() dengan cara yang sederhana. Dua
pernyataan berikut adalah identik.
printf ("Hello world %d", 1);
fprintf (stdout,"Hello world %d", 1);
6.8.2 Fungsi fputc
Deklarasi:
int fputc(int character, FILE *stream);
Fungsi ini menulis satu karakter (unsigned char) yang dispesifikasikan oleh parameter
character ke file yang ditunjuk oleh stream dan menggerakkan maju indikator posisi file pada
stream tersebut.
60
Jika sukses, fungsi ini mengembalikan karakter yang ditulis. Jika ada kesalahan, indikator
kesalahan untuk stream diset dan EOF dikembalikan.
6.8.3 Fungsi fputs
Deklarasi:
int fputs(const char *str, FILE *stream);
Fungsi ini menulis sebuah string pada stream sampai pada (tetapi tidak termasuk) karakter null.
Jika sukses, fungsi ini mengembalikan nilai non negatif. Jika ada kesalahan, EOF dikembalikan.
6.9 Membaca File
Untuk membaca file beberapa fungsi di bawah ini dapat digunakan:
 fscanf
 fgetc
 fgets
6.9.1 Fungsi fscanf
Deklarasi:
int fscanf(FILE *stream, const char *format, ...);
Fungsi ini membaca input field dari sebuah stream sesuai dengan format format yang berisi
conversion specifier. Conversion specifier ini menentukan bagaimana input akan disimpan dalam
variabel yang sesuai. Setiap variabel yang menjadi parameter setelah format haruslah bertipe
pointer.
Pembacaan input field berhenti saat karakter yang ditemukan gagal untuk dikonversi dengan
conversion specifier atau tidak ada lagi input field yang dibaca.
Jika sukses, fungsi ini akam mengembalikan jumlah input field yang berhasil dikonversikan dan
disimpan dari stream. Jika ada kesalahan, EOF dikembalikan.
fscanf() ini analogis dengan scanf() sebagaimana frpintf() dengan printf().
6.9.2 Fungsi fgetc
Deklarasi:
61
int fgetc(FILE *stream);
Fungsi ini membaca dan mendapatkan karakter berikutnya (unsigned char) dari stream dan
memajukan indikator posisi dalam stream .
Jika sukses, fungsi ini mengembalikan karakter yand didapat. Jika end-of-file dicapai, EOF
dikembalikan dan indikator end-of-file diset. Jika kesalahan terjadi, maka indikator kesalahan
untuk stream tersebut diset dan EOF dikembalikan.
6.9.3 Fungsi fgets
Deklarasi:
char *fgets(char *str, int n, FILE *stream);
Fungsi ini membaca satu baris dari stream dan menyimpannya ke dalam string str. Fungsi ini
berhenti saat (n-1) karakter dibaca, karakter pada baris baru dibaca, atau end-of-file dicapai.
Karakter pada baris baru disalin ke string str. Sebuah karakter null ditambahkan pada akhir string
tersebut.
Jika sukses, fungsi ini mengembalikan string. Jika ada kesalahan, sebuah null pointer
dikembalikan. Jika end-of-file muncul sebelum ada karakter yang dibaca, string tidak berubah.
6.9.4 Fungsi feof
Deklarasi:
int feof(FILE *stream);
Fungsi ini mengecek indikator end-of-file pada stream. Jika end-of-file dicapai, fungsi ini akan
mengembalikan nilai bukan 0. Jika end-of-file belum dicapai, fungsi ini mengembalikan 0.
6.10 Contoh Aplikasi
Perhatikan contoh di bawah ini:
123456789
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *fp;
int i = 12;
float x = 2.356;
char ch = 's';
62
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
char str[20] = "Selamat Datang!\n";
// Membuka file untuk menulis
fp = fopen("latihan.txt", "w");
if (fp != NULL){
printf("Sukses membuka file\n");
// Menulis file dengan fprintf
fprintf (fp, "%d %f %c %s", i, x, ch, str);
//Menutup file
if(fclose(fp)==0){
printf("Sukses menutup file\n");
} else{
printf("Tidak sukses menutup file\n");
}
} else{
printf("Tidak sukses membuka file\n");
}
int j,n;
float y;
char c;
char s[20];
// Membuka file untuk membaca
fp = fopen("latihan.txt", "r");
if (fp != NULL){
printf("Sukses membuka file\n");
// Membaca file dengan fscanf
n = fscanf (fp, "%d %f %c %s", &j, &y, &c, s);
printf("Jumlah masukan yang sukses dibaca: %d\n", n);
printf ("j = %d, y = %f, c = %c, s = %s\n", j, y, c, s);
//Menutup file
if(fclose(fp)==0){
printf("Sukses menutup file\n");
} else{
printf("Tidak sukses menutup file\n");
}
} else{
printf("Tidak sukses membuka file\n");
}
63
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Membuka file untuk membaca
fp = fopen("latihan.txt", "r");
if (fp != NULL){
printf("Sukses membuka file\n");
// Membaca file dengan getc
while (!feof(fp)) {
c = getc(fp);
printf("%c",c);
}
//Menutup file
if(fclose(fp)==0){
printf("Sukses menutup file\n");
} else{
printf("Tidak sukses menutup file\n");
}
} else{
printf("Tidak sukses membuka file\n");
}
system("pause");
return 0;
}
Gambar 6.1
Analisis dan kerjakan kode di atas. Amati penggunaan fungsi-fungsi untuk menangani file.
Lakukanlah eksperiemen mandiri untuk lebih memahami operasi file. Cobalah menggunakan
fungsi-fungsi operasi file lain (yang tidak terdapat pada kode di atas) untuk membaca dan menulis
file.
6.11 Tugas
 Tugas yang relevan dengan topik bab ini diberikan oleh dosen/asisten praktikum.
 Tugas bab ini dapat dikombinasikan dengan tugas bab lain atas arahan dan ijin dosen/asisten
praktikum.
 Tugas bab ini dikumpulkan kepada dosen/asisten sesuai format yang diminta.
64
7 Daftar Pustaka
Arnold, K., Gosling, J., and Holmes, J. The Java Programming Language, 4th Edition. Addison
Wesley Professional, 2005.
Burgess, M. C Programming Tutorial (K&R version 4), 1999. Diakses 18 Oktober 2011, dari situs
Mark Burgess, Faculty of Engineering, Oslo University College:
http://www.iu.hio.no/~mark/CTutorial/CTutorial.html
C Language Tutorial. Diakses 18 Oktober 2011, dari Computational Physics, Department of
Physics, Drexel University: http://www.physics.drexel.edu/courses/Comp_Phys/General/C_basics/
Dodrill, G. 1997. C Language Tutorial. Diakses 18 Oktober 2011, dari Institute of Robotics, Faculty
of Electrical Engineering and Computer Science, University of Maribor: http://www.ro.feri.unimb.
si/predmeti/mik_si/C_prir/CLIST.HTM
Herianto, T. Tuntunan Praktis Pemrograman C++. PT Elex Media Komputindo Kelompok Gramedia,
Jakarta, 1995.
Laboratorium Komputer. Modul Praktikum Dasar Pemrograman Komputer. Program Studi Teknik
Informatika, wearnes,, Malang, 2011.
Pranata, A. Pemrograman Borland C++ 4.x. Jilid 1. Penerbit Andi, Yogyakarta, 1996.
Soulie, J. C++ Language Tutorial. Diakses 18 Oktober 2011 dari cplusplus.com:
http://www.cplusplus.com/doc/tutorial/

0 komentar:

:)) ;)) ;;) :D ;) :p :(( :) :( :X =(( :-o :-/ :-* :| 8-} :)] ~x( :-t b-( :-L x( =))

Posting Komentar