Saturday, April 15, 2017

Memahami pointer pada bahasa C

Pointer pada bahasa pemrograman C merupakan object yang menunjuk alamat dari sesuatu yang ditunjuk. Berbeda dengan variabel biasa, jika variabel biasa memuat nilai dari variabel tersebut (misal int a=5), maka pointer memuat nilai yang ditunjuk dari variabel berupa pointer tersebut.

Pointer merupakan kekuatan utama dari bahasa pemrograman C/C++ yang jarang dimiliki bahasa pemrograman lainnya. Dengan pointer kita bisa mengalokasikan memory secara dinamik dan meningkatkan performansi program khususnya untuk operasi yang berulang seperti akses nilai dari tabel, data string, dll. Pointer juga menghemat beban komputasi, yakni dengan me-reference/dereference (menginisiasi dan menghancurkan) suatu pointer daripada mengcopy/paste nilai suatu variabel.

Pointer dituliskan dengan menambahkan tanda bintang sebelum nama variabel dan setelah tipe variabel, misal: int * a; int* a; atau int *a. Referensi (address of, alamat dari) ditunjukkan dengan tanda ampersand (&), misal: &a. Penulisan pointer yang lebih disukai adalah int* a (bintang menyatu dengan tipe pointer).

Contoh 1: Pointer yang salah
Contoh pointer yang salah namun sangat berguna untuk memahami pointer adalah sebagai berikut.

#include <stdio.h>
 
int main() {
    int a, b;
    int* p;
    *p = 5;
 
    printf("a= %d, b=%d, p=%d\n", a, b, *p);
}

Perhatikan contoh di atas. Tujuan kita adalah untuk membuat dua variabel: pointer dan non-pointer, dimana pointer menunjukkkan nilai dari variabel pointer tersebut (p). Pada baris ke-5 proses tersebut dilakukan dengan script *p = 5. Hal ini merupakan kesalahan karena pointer tidak mempunyai alokasi memori untuk menyimpan nilai tersebut, hasilnya yang terjadi adalah segmentation fault, kerusakan segmentasi karena mencoba mengakses memory yang tidak ada. Error (kesalahan) tersebut muncul ketika progam di-run, saat di compile akan baik-baik saja karena memang tidak ada kesalahan sintaks.

Contoh 2: Pointer yang benar
Bagaimana solusi dari kesalahan pada contoh satu di atas? Ada dua macam solusi menurut saya: 1) Pointer menunjuk variabel yang sudah punya memori, atau cara 2) Mengalokasikan memory sementara untuk pointer (dinamik memory). Cara 1 akan dibahas disini, sedang cara 2 akan dibahas pada contoh 3.

Sesuai dengan konsepnya, pointer merupakan penunjuk, harus menunjuk objek lain, bukan malah diisi nilai seperti pada contoh 1. Jadi sebelum mengisi dengan *p = 5, saya definisikan int* p = &a. Artinya, yang ditunjuk p adalah alamat a. Selanjutnya dapat disisi *p = 5, yang ditunjuk p diisi dengan nilai 5. Disini tidak ada error karena yang ditunjuk p sudah ada. Program lengkapnya adalah sebagai berikut,
#include <stdio.h>

int main() {
    int a, b;
    int* p=&a;
    *p = 5;
    b = a;
    printf("a= %d, b=%d, p=%d\n", a, b, *p);
    printf("Alamat a=%p, Alamat b=%p, Alamat c=%p\n", &a, &b, &*p);
}

Jika program di atas dijalankan, tidak ada masalah. Nilai a, b dan p akan ditampilkan dengan nilai yang sama. Yang ditunjuk p (yakni a) diisi dengan 5, kemudian b adalah copy dari a, dan p merupakan pointer yang menunjuk isi alamat a, jadi ketiga-tiganya menunjukkan nilai yang sama. Agar lebih jelas, saya cetak juga alamat dari a, b dan p, dimana a dan p sama, namun berbeda dengan b. Disini kita hemat memory satu variabel, yakni p,karena hanya menunjuk alamat dari variabel lainnya.

Contoh 3: Pointer dengan Malloc
Selain dengan menunjuk alamat dari vaiabel lain, kita juga bisa mengalokasikan memory dinamik untuk pointer tersebut. Contoh sederhananya adalah dengan malloc, misal `int* p=malloc(sizeof(int))`. Disini kita perlu menambahkan library baru, stdlib.h, karena malloc dimiliki oleh library tersebut. Contoh tersebut mengalokasikan memory untuk variabel p sebesar memory untuk int (sizeof(int)). Program lengkapnya adalah seperti berikut,

#include <stdio.h>
#include <stdlib.h>
 
int main() {
    int a, b;
    int* ptr;
    ptr=malloc(sizeof(int));
    *ptr = 5;
    a=*ptr;
    b=a;
    printf("a= %d, b=%d, p=%d\n", a, b, *ptr);
    printf("Alamat a=%p, Alamat b=%p, Alamat c=%p\n", &a, &b, &*ptr);
    free(ptr);
 }

Program di atas akan menghasilkan output atau luaran yang sama persis dengan contoh 2 sebelumnya namun dengan teknik yang berbeda. Pada program ini, dialokasikan memory dinamik untuk pointer (ptr) sehingga pointer bisa diisi suatu nilai, tidak menunjuk alamat variabel lain. Variabel lain, yakni a, justru mengcopy isi dari yang ditunjuk pointer, yakni 5, sedangkan variabel b, sama seperti sebelumnya, mengcopy variabel a, yakni 5 juga. Jadi tiga-tiganya isinya sama, namun dengan alamat yang berbeda antar ketiganya karena sekarang pointer sudah memiliki memory (dynamic) sendiri.

Satu hal penting pada teknik kedua ini adalah menghapus memory untuk pointer, yakni dengan script: free(ptr). Jadi memory yang sudah kita alokasikan untuk pointer melalui malloc kita hapus di akhir progam akar beban komputasi normal kembali. Jika tidak ada script ini,program tidak akan ada masalah secara sintaksis, namun akan terjadi hang jika memory yang digunakan bertambah banyak dan komputer kehabisan memory.

Pointer juga bisa berupa fungsi (pointer function), akan kita bahas lain kali.
Related Posts Plugin for WordPress, Blogger...