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.