Pointer/Penunding di Dalam C++

Tajuk pointer merupakan tajuk yang paling digeruni oleh 
pelajar-pelajar yang baru mempelajari C++. Sebenarnya kalau kita 
memahami konsep asas di sebalik pointer ini, pointer merupakan satu 
perkara yang amat mudah difahami. Tetapi kerapkali konsep asas ini 
tidak diajar dengan sempurna atau diketepikan sama sekali oleh 
pensyarah-pensyarah; sebaliknya, disebabkan kesuntukan masa dan 
sebagainya, mereka terus melangkau ke penggunaan pointer. Akibatnya, 
pelajar-pelajar tahu menggunakan pointer-pointer setakat di dalam
skop di ajar, tetapi tidak tahu meluaskan penggunaan pointer-pointer 
di luar skop yang diajar ini.

Kita sudah tahu bahawa terdapat beberapa jenis asas kepada 
variable-variable: integer, float, char dan sebagainya. 
Variable-variable ini dicipta supaya dapat menyimpan satu nilai. 
Sepertimana jenis-jenis lain, pointer hanyalah satu lagi jenis 
variable; secara lebih spesifik, suatu pointer menyimpan satu nombor 
(Sepertimana integer dan float), tetapi nombor yang disimpan di dalam 
pointer mempunyai satu makna yang khas kepada komputer. Nilai sesuatu 
pointer hanya dapat difahami oleh komputer. Jika kita sebagai manusia 
melihat apakah nilai yang tersimpan dalam satu-satu variable pointer, 
kita tidak akan dapat memahami apakah yang diwakili oleh nilai ini. 
Kita cuma akan nampak satu nombor yang kelihatan rawak. Tetapi 
realitinya nombor ini membawa makna yang jitu dan penting kepada 
komputer kita.

Jadi apakah sebenarnya makna pointer ini? Kalau anda baca buku teks 
atau mendengar kepada pensyarah anda, anda akan diajar bahawa sesuatu 
pointer 'menunding/menunjuk kepada alamat sesuatu variable'. Setengah 
orang boleh faham ayat ini, tetapi separuh lagi tidak memahaminya. 
Jika anda tidak memahami definisi ini sepenuhnya, ia disebabkan anda 
belum memahami apakah yang dimaksudkan dengan 'alamat', dan 
'menunding'.

Maksud perkataan 'menunding' ini tidak lebih dari 'mengandungi'. 
Seperti yang sudah kita lihat di atas, pointer (seperti 
variable-variable lain) 'mengandungi' sesuatu. Tetapi kerana pointer 
ini menyimpan satu nilai yang membawa makna yang spesifik kepada 
komputer, maka perkataan 'mengandundi' ini digantikan dengan
perkataan 'menunding'. Dalam ertikata lain, pointer sebenarnya 
'mengandungi' alamat kepada sesuatu variable.

Apakah yang dipanggil 'alamat' ini? Untuk memahami apakah alamat,
kita harus memahami dulu akan konsep memory di dalam komputer. Seperti
mana yang kita ketahui, komputer kita mempunyai memory. Kita ketahui
bahawa memory digunakan untuk menyimpan maklumat agar dapat digunakan 
oleh CPU untuk melakukan tugas pemprosesan. Oh ya, bila saya 
perkatakan tentang memory, memory yang saya maksudkan ialah RAM -- 
random access memory. Saya tidak maksudkan memory-memory lain seperti 
ROM, EPROM, cakera keras anda dan sebagainya. Meskipun secara
tepatnya 
memory yang dicapai oleh program kita sebenarnya melibatkan kedua-dua 
RAM dan cakera keras (yang digunakan sebagai memory maya bilamana RAM 
tidak lagi mencukupi), namun untuk meringkaskan perbincangan marilah 
kita anggap bahawa hanya RAM digunakan untuk menyimpan maklumat.

Memory ialah satu ruang di dalam komputer di mana maklumat disimpan. 
Setiap proses (program yang dilarikan) akan diberi satu ruang memory 
yang khas oleh sistem operasi. Dalam WindowsNT misalnya, setiap
proses diberi ruang sebanyak 4 gigabyte untuk menyimpan datanya. Byte 
merupakan ukuran bagi memory -- sepertimana gram merupakan ukuran
bagi berat sesuatu makanan. Satu megabyte (MB) lebih-kurang sama 
nilainya dengan satu juta byte. Lazimnya komputer hari ini mempunyai 
antara 64 MB hingga 256 MB memory. Lebih banyak memory yang dipunyai 
oleh sesuatu komputer, maka lebih banyaklah maklumat yang dapat 
disimpan.

Jadi kita sudah tahu bahawa setiap proses mempunyai ruangan memorynya 
yang tersendiri. Memory sebanyak 4 GB ini sebenarnya dibahagikan lagi 
ke unit-unit kecil. Unit-unit kecil ini sebesar 1 byte. Jadi memory 
4GB sebenarnya merupakan satu rentetan panjang unit-unit 1 byte. Bila 
diberi sejumlah ruang yang begitu besar, harus terdapat satu
mekanisme untuk program kita mencapai setiap byte. Mekanisme ini 
dipanggil pengalamatan (addressing). Ringkasnya, setiap byte di dalam 
memory dikenali dengan satu nombor tertentu, dan nombor ini dikenali 
sebagai alamat. Byte pertama di dalam memory mempunyai alamat 0, 
diikuti dengan byte 1, 2, 3 ... dan seterusnya sehinggalah kesemua 4 
GB.

Setiap kali kita mencipta satu variable (sama ada secara 
statik/deklarasi, atau secara dinamik (malloc/new)), satu ruang
memory akan ditempah untuk menyimpan variable tersebut. Secara 
teknikalnya, 'tempahan' ini dipanggil 'allocation'. Apa yang berlaku 
dibelakang tabir, program kita akan membuat permohonan kepada 
operating system untuk memory sebesar sekian-sekian (besarnya memory 
yang diminta bergantung kepada saiz variable yang kita cipta itu). 
Operatingsystem akan mencari satu ruang di dalam memory 4GB ini. Jika 
ada kelapangan, maka ia akan memangkah ruangan memory ini sebagai 
"sudah dipenuhi", lalu mengembalikan alamat memory yang didapati ini 
kepada program kita. Anda boleh samakan proses ini seolah-olah anda 
membeli tiket wayang di pawagam. Setiap kali seorang pelanggan datang 
membeli tiket (mencipta variable), penjual tiket (operating system) 
akan mencari satu/lebih tempat kosong (memory) dan memberi tiket 
kepada pelanggan. Tiket yang diberi itu ditulis dengan nombor kerusi 
(alamat). Bilangan kerusi yang diberi adalah bergantung kepada 
bilangan kerusi (byte) yang diminta.

Ada satu perbezaan kecil di sini. Bila anda membeli tiket wayang,
anda akan menerima satu tiket bagi setiap kerusi yang dibeli. 
Sebaliknya, bila kita 'menempah memory' dari operating system, kita 
hanya akan diberi satu alamat, iaitu alamat bagi byte PERTAMA yang 
memory yang diberi kepada kita. Ketika kita meminta memory ini, kita 
sudah menyatakan (secara langsung atau tidak) akan bilangan memory 
yang kita perlukan. Dan bila operating system memberi kita 
memory-memory ini, ia sentiasa memberikan kita byte-byte yang 
_berjujukan_ (jika kita meminta lebih dari satu byte). Jadi selagi 
kita tahu apakah alamat byte pertama dan saiz memory yang kita minta, 
maka kita tidak memerlukan apa-apa maklumat lain untuk mencapai
memory ini.

Misalnya jika anda buat kod begini:

new CMyClass;

Anda sebenarnya meminta dari operating system supaya memberikan anda 
ruang sebanyak x byte, di mana x byte ialah saiz memory yang
ditempati oleh satu objek ber-class CMyClass. Saiz ini bergantung 
antara lainnya kepada bilangan member variable yang dikandungi dalam 
CMyClass.

Tetapi penyataan di atas tidak mencukupi. Kenapa? Bila operating 
system memulangkan alamat memory ini, ia perlu meletakkan alamat ini 
ke dalam sesuatu. Di sinilah pointer memainkan peranannya. Untuk 
mengaut alamat memory yang diberi oleh operating system, kita
perlukan satu pointer begini:

CMyClass *pMyObj;	// mencipta satu pointer kepada CMyClass
pMyObj = new CMyClass;	// meminta memory dari operating system 
sekaligus mengaut alamat memory yang diberi

Ketika ini, pMyObj dikatakan sebagai 'menunding kepada satu objek 
CMyClass'. Untuk mencapai objek ini, kita gunakan tanda -> begini:

pMyObj->m_nUmur = 10;
cout << pMyObj->m_nUmur;	
/* menganggap bahawa terdapat satu member variable di dalam CMyClass 
begini: int m_nUmur; */

Apa terjadi jika anda buat begini:

CMyClass *pMyObj;
cout << pMyObj->m_nUmur; 
// terus guna, terlupa untuk minta memory dari operating system

Jika anda buat begini, proses anda akan 'crash'. Kenapa? Kerana 
ringkasnya anda cuba buat sesuatu tanpa izin. Anda cuba menggunakan 
memory yang ditunding oleh pMyObj TANPA memberikannya satu alamat 
memory yang diminta dengan sah. Anda mungkin tertanya-tanya, jika
saya tidak melakukan apa-apa allocation, apakah sebenarnya alamat
yang dikandungi di dalam pMyObj? Jawapannya, tiada siapa yang tahu. 
pMyObj menunding ke satu alamat yang rawak.

Bagaimana jika anda buat begini?

CMyClass *pMyObj1;
CMyClass *pMyObj2;

pMyObj1 = new CMyClass;
pMyObj2 = pMyObj1;

pMyObj2 akan mengandungi alamat yang sama dengan pMyObj1. Dalam kata 
lain, pMyObj2 menunding ke objek yang sama dengan pMyObj1. Jadi jika 
anda buat ini selepas itu:

pMyObj1->m_nUmur = 10;
pMyObj2->m_nUmur = 30;

Nilai m_nUmur akan menjadi 30 kerana pMyObj1 dan pMyObj2 merujuk 
kepada objek yang sama di dalam memory.

Kita sudah lihat tentang meminta memory dari operating system. 
Semestinya, apa-apa yang kita pinjam, kita harus pulangkan, bukan? 
Sama juga dengan memory. Selepas kita sudah habis menggunakan memory 
ini, kita harus pulangkannya kembali. Memulangkan kembali memory ini 
hanyalah menggunakan arahan delete atau free.

delete pMyObj1;

Setelah delete dipanggil, pMyObj1 dan pMyObj2 akan tetap menunding ke 
alamat yang sama seperti dahulu, tetapi memory yang terletak di
alamat ini tidak lagi boleh digunakan kerana operating system sudah 
memadamkan tanda 'sudah dipenuhi' dari memory tersebut. Jika anda
cuba juga untuk buat begini:

pMyObj1->m_nUmur = 10;

Maka proses anda akan crash.

Kita sudah lihat konsep-konsep yang menjadi latarbelakang 
pointer-pointer. Kita sudah membincangkan apakah peranan operating 
system dalam penggunaan pointer ini, dan membincangkan 
fundamental-fundamental berkenaan memory. Dengan ini saya harap anda 
dapat meningkatkan pemahaman anda tentang penggunaan pointer.

Apakah pentingnya mempelajari pointer? Pointer merupakan building 
block asas kepada struktur-struktur programming yang lebih kompleks; 
kebanyakan struktur data bergantung kepada pemahaman pointer untuk 
diimplementasi, misalnya linked-list, array dan graph. Pehamaman 
pointer juga diperlukan untuk menerokai konsep-konsep pemprograman 
yang lebih advanced seperti interface (bukan user-interface, tetapi 
interface di dalam konteks pemprograman berlandaskan komponen -- COM, 
DCOM, CORBA dll.). Dalam ertikata lain, tanpa pemahaman tentang 
pointer akan dapat menolong anda memasuki tajuk-tajuk programming
yang digunakan seharian dalam arena profesional. Tanpa pemahaman 
tentang pointer, pemprograman seseorang akan terhad kepada 
pemprograman yang amat asas sahaja.

Ditulis oleh Hazman Halid
Web: http://www.hazman.com

Anda dibenarkan dan digalakkan untuk menyebarkan artikel ini kepada 
rakan-rakan anda, asalkan anda tidak mengubah kandungan asalnya atau 
memendekkannya.

    Source: geocities.com/tukangtaip