Saturday, October 7, 2017

Kuliah 2 C++: Pointer


BAB 2.
Pointer






2.1 Pengantar
Pointer adalah sebuah variabel yang memuat (yang nilainya berupa) alamat memori dari variabel lain. Unit dasar dari memori adalah sebuah bit. Bit-bit dikelompokkan ke dalam grup-grup delapan bit. Grup-grup bit ini disebut dengan byte. Memori utama (RAM) dari komputer memuat byte-byte yang dinomori secara sekuensial. Setiap byte dinomori dan nomor ini adalah alamatnya. Ketika Anda mendeklarasikan sebuah variabel, Anda menyebutkan tipe dan nama variabel, dan kompiler berikut dengan sistem operasi mengalokasikan suatu blok memori dan lokasi untuk menyimpan nilai dari variabel tersebut. Jumlah byte yang dialokasikan kepada suatu variabel untuk penyimpanan nilainya bergantung pada tipe data dari variabel tersebut. Sebagai contoh, umumnya 4 byte dialokasikan untuk menyimpan sebuah nilai integer. Alamat dari sebuah variabel adalah alamat (nomor byte) dari byte pertama dari blok memori yang dialokasikan kepada variabel itu. Jadi, variabel mendapatkan sebuah alamat dimana nilainya disimpan. Anda dapat mengekstraksi alamat memori dari sebuah variabel dengan menggunakan operator alamat (&), yang juga dikenal dengan operator referensi. Sebagai contoh, jika n adalah sebuah variabel, maka alamatnya diberikan oleh &n. Anda dapat mendeklarasikan variabel lain untuk menyimpan &n, yang merupakan alamat dari variabel n. Variabel (yang menyimpan &n) itu disebut dengan pointer yang menunjuk ke n.


2.2 Deklarasi Pointer
Deklarasi atas sebuah variabel pointer dilakukan dengan menyebutkan tipe data dari variabel yang ditunjuknya, diikuti dengan operator indireksi, yang juga dikenal dengan operator dereferensi (*) dan nama dari variabel pointer. Operator (*) memberitahu kompiler bahwa variabel yang sedang dideklarasikan adalah sebuah pointer. Nama dari variabel pointer sama seperti variabel biasa. Sejumlah ilustrasi dari deklarasi pointer untuk variabel-variabel int diberikan berikut.


int m, n,;           //m dan n adalah variabel-variabel integer
int *ptr ;           //ptr merupakan pointer yang menunjuk ke sembarang nilai integer
int* ptr = &n;       //ptr sekarang menunjuk ke n.
int *ptr = &m;       //ptr sekarang menunjuk ke m
int* ptr = 0;               //sekarang ptr diinisialisasi dengan 0.


Perhatikan pula bahwa Anda bisa mendeklarasikan pointer dengan int* ptr atau dengan int *ptr, dimana simbol asterisk (*) dilekatkan pada int pada kasus pertama atau pada ptr pada kasus kedua. Adalah praktek pemrograman yang baik untuk menginisialisasi pointer ketika ia dideklarasikan. Pointer dapat diinisialisasi dengan suatu alamat atau dengan 0 atau NULL, yang merupakan sebuah konstanta simbolis yang didefinisikan di dalam bahasa C dan diwarisi oleh C++. NULL juga didefinisikan di dalam file header <iostream> dan file-file header lain di dalam C++. Pointer NULL tidak menunjuk ke data apapun.

Sebuah pointer yang menunjuk ke suatu variabel yang memiliki nilai desimal titik-mengambang seperti PI = 3.14159; dan yang menunjuk ke sebuah variabel karakter dideklarasikan seperti berikut. Dimisalkan bahwa pf adalah nama dari pointer yang menunjuk ke sebuah variabel float, pd adalah nama pointer yang menunjuk ke sebuah variabel double, dan pc adalah nama pointer yang menunjuk ke sebuah variabel karakter.


GAMBAR 2.1 Pointer-pointer yang menunjuk ke pelbagai tipe data


Pointer-pointer yang menunjuk ke dua atau lebih variabel yang bertipe sama dapat dideklarasikan pada baris yang sama seperti ditunjukkan pada kode berikut.

int n, y, *ptrn, *py; //n dan y adalah variabel-variabel integer
//ptrn dan py adalah pointer-pointer
ptrn = &n;           //inisialisasi dari pointer ptrn dengan &n
py = &y;             //inisialisasi dari pointer py dengan &y

Pada deklarasi di atas, ptrn adalah pointer yang menunjuk ke n dan py adalah pointer yang menunjuk ke y. Anda juga bisa menggunakan typedef berikut untuk mendeklarasikan sejumlah pointer bertipe sama.

typedef double* ptd;
double x, y, z;
ptd px = &x, py = &y, pz = &z;


OPERATOR INDIREKSI ATAU DEREFERENSI
Nilai dari sebuah variabel bisa didapatkan dari pointernya menggunakan operator indireksi yang juga dikenal dengan operator dereferensi (*). Aplikasi dari operator dereferensi diberikan berikut.

int n = 60, *ptrn;
ptrn = &n;
*ptrn = 60;   //menggunakan operator dereferensi


Program 2.1 berikut mengilustrasikan pendeklarasian atas pointer-pointer dan aplikasi dari operator alamat (&). Pointer juga adalah suatu variabel yang kepadanya dialokasikan sebuah blok memori untuk menyimpan nilainya (yang merupakan alamat dari variabel lain). Operator alamat (&) dapat pula digunakan untuk mendapatkan alamat dari pointer.

Program 2.1 Mengilustrasikan pendeklarasian pointer dan penggunaan operator alamat &

#include <iostream>
using namespace std;

int main()
{
   int n = 60 ;
   double B = 8.56;

   int* ptrn = &n;         //ptrn adalah pointer yang menunjuk ke variabel int n.
   double *pB = &B;        //pB adalah pointer yang menunjuk ke variabel double B

   cout<<"n = "<<n<<", B = "<<B<<endl;
   cout<<"Alamat dari n adalah = "<<&n<<", ptrn = "<<ptrn<<endl;

   cout<< "*ptrn = "<<*ptrn<<", *pB = " <<*pB <<endl;
   cout<<"Alamat dari B = "<<&B <<", pB = "<<pB<<endl;

   cout<<"Alamat dari ptrn = "<<&ptrn<<endl;

   return 0;
}
KELUARAN
n = 60, B = 8.56
Alamat dari n adalah = 0018FF44, ptrn = 0018FF44
*ptrn = 60, *pB = 8.56
Alamat dari B = 0018FF3C, pB = 0018FF3C
Alamat dari ptrn = 0018FF38


Dari keluaran program, jelaslah bahwa n dan *ptrn memiliki nilai yang sama, yaitu 60. Sama halnya, B dan *pB keduanya sama bernilai 8.56. Jadi, ini menunjukkan bahwa penggunaan operator dereferensi (*) pada variabel pointer ptrn dan pB menghasilkan nilai yang disimpan di dalam alamat yang ditunjuknya. Program juga menghasilkan alamat di mana ptrn disimpan. Di sini, Anda melekatkan ptr atau p pada nama variabel untuk mengindikasikan bahwa variabel itu adalah pointer. Tetapi, Anda sebenarnya bisa memberikan nama legal apapun. Program berikut mengilustrasikan beberape deklarasi pointer lain dan penggunaan dari typedef.


Program 2.2 Mengilustrasikan typedef pada pendeklarasian pointer

#include <iostream>
using namespace std;
int main()

{
   char ch = 'S';
   char* pc = &ch;

   cout<<"*pc = "<<*pc<<endl;

   double x = 4.5, z;
   typedef double* pd;
   pd px = &x;       //di sini, pd adalah singkatan untuk double*

   cout<<"px = "<<px<<endl;       //menampilkan nilai dari px
   cout<<"&x = "<< &x<<endl;      //menampilkan alamat dari &x

   pd pz = &z;
   pz = px;          //px (alamat dari x) ditugaskan kepada pz

   cout<<"*pz = "<<*pz<<endl;
   cout<<"*px = "<<*px<<endl;

   return 0;
}
KELUARAN
*pc = S
px = 0012FF70
&x = 0012FF70
*pz = 4.5
*px = 4.5


Keluaran menunjukkan bahwa alamat dari x sama dengan nilai dari px dan dengan mengekuasikan pz = px, Anda juga membuat pz untuk menunjuk ke nilai dari x seperti diilustrasikan pada Gambar 2.2.


GAMBAR 2.2 Dua pointer menunjuk ke variabel yang sama


Pointer-pointer yang menunjuk ke semua tipe data menempati ukuran memori yang sama karena nilai dari suatu pointer adalah alamat memori, yaitu sebuah integer tak-bertanda. Namun, variabel-variabel yang ditunjuk oleh pointer-pointer, tentu saja, menempatkan ukuran blok memori yang berbeda yang tergantung dari tipe datanya. Ini diilustrasikan pada program 2.3.

Program 2.3 Mengilustrasikan ukuran dari pointer yang menunjuk ke semua tipe data adalah sama

#include <iostream>
using namespace std;

int main()
{
   int n = 60, *pn;
   double PI = 3.14159, *pPI;

   pPI = &PI;
   pn = &n;

   char ch = 'M', *sam; //sam adalah nama pointer
   sam = &ch;              //pointer diinisialisasi dengan &ch.

   cout<<"Ukuran dari pointer yang menunjuk ke int n = " <<sizeof(pn)<<endl;

   cout<<"Ukuran dari pointer yang menunjuk ke double PI = "<<sizeof(pPI)<<endl;

   cout<<"Ukuran dari pointer yang menunjuk ke char ch = "<<sizeof(sam)<<endl;

   cout<<"Variabel-variabel yang digunakan: "<<*pn <<", "<<*pPI<<" dan "<<*sam<< endl;

   return 0;
}
KELUARAN
Ukuran dari pointer yang menunjuk ke int n = 4
Ukuran dari pointer yang menunjuk ke double PI = 4
Ukuran dari pointer yang menunjuk ke char ch = 4
Variabel-variabel yang digunakan: 60, 3.14159 dan M


Keluaran menunjukkan bahwa ukuran dari memori yang dialokasikan untuk sebuah pointer adalah 4 byte tanpa memandang fakta bahwa variabel yang ditunjuk adalah integer, double, atau karakter. Program 2.4 berikut mengilustrasikan bahwa aksi dari operator dereferensi dan aksi dari operator alamat (&) adalah berlawanan satu sama lain.

Program 2.4 Mengilustrasikan operator dereferensi(*) dan operator alamat (&)

#include <iostream>
using namespace std;

main()
{
   int n = 60;
   int* ptrn, *ptrm ;      //deklarasi dari dua piointer ke int

   ptrn = &n;
   ptrm = ptrn;                   //menugaskan pointer

   cout<<"n = "<<n<<"\t&n = "<<&n<<"\t *&n = "<<*&n<<endl;
   cout<<"ptrn = "<<ptrn<<" "<<"ptrm = "<<ptrm<<endl;

   cout<<"Nilai yang ditunjuk oleh ptrn = "<<*ptrn<<"\n" ;
   // *ptrn adalah nilai yang ditunjuk oleh pointer ptrn

   cout<<"Nilai yang ditunjuk oleh ptrm = " <<*ptrm<<endl;
   cout<<"Alamat dari ptrn = "<<&ptrn<<endl;

   double PI = 3.141592;
   double *pPI;                   //deklarasi dari pointer untuk PI

   pPI = &PI;

   cout<<"PI="<<PI<<",\t &PI = "<<&PI<<"\n";
   cout<<"*&PI = "<<*&PI<< " ,\t *pPI = "<<*pPI<<"\n";

   return 0;
}
KELUARAN
n = 60  &n = 0018FF44    *&n = 60
ptrn = 0018FF44 ptrm = 0018FF44
Nilai yang ditunjuk oleh ptrn = 60
Nilai yang ditunjuk oleh ptrm = 60
Alamat dari ptrn = 0018FF40
PI=3.14159,      &PI = 0018FF34
*&PI = 3.14159 ,         *pPI = 3.14159


Dari keluaran perogram, dapat dilihat bahwa n adalah sebuah integer dengan nilai 60. Alamat dari n adalah 0018FF44. Nilai dari ptrn, yang merupakan pointer yang menunjuk ke n, juga adalah 0018FF44. Nilai dari ptrn ditugaskan kepada ptrm untuk menciptakan pointer lain yang menunjuk ke n. Alamat dari ptrn dapat pula ditentukan dengan menggunakan operator &. Jadi, alamat dari ptrn adalah 0018FF40, yang jauhnya 4 byte dari 0018FF44. Nilai dari variabel n dapat ditentukan menggunakan operator dereferensi (*). Blok-blok memori yang dialokasikan untuk penyimpanan nilai n dan pointernya diilustrasikan pada Gambar 2.3a.


GAMBAR 2.3a Sebuah integer dan pointernya di dalam memori



GAMBAR 2.3b Dua pointer yang menunjuk nilai yang sama


Bagian kedua pada keluaran program terkait dengan suatu nilai double PI = 3.14159. Pointer untuk PI diberi nama dengan pPi. Alamat dari PI adalah 0018FF34. Nilai dari PI dapat ditentukan dengan memanggil PI atau dengan *&PI atau dengan *pPI. Penggunaan operator dereferensi (*) diilustrasikan pada Gambar 2.3b.



2.3 Memproses Data Menggunakan Pointer
Pointer dapat dipakai menggantikan variabel yang ditunjuknya. Anda telah melihat pada program sebelumnya bahwa n dan *ptrn memiliki nilai yang sama. Sekarang, jika ada perubahan pada nilai dari *ptrn, maka n juga berubah.

Program berikut menghitung keliling dan luas dari sebuah lingkaran dengan diameter D. Di sini, Anda akan menggunakan pointer-pointer yang menunjuk D dan PI, menggantikan penggunaan D dan PI. Nilai dari PI diberikan pada program sedangkan nilai diameter dimasukkan oleh user.


Program 2.5 Mengilustrasikan aplikasi dari pointer dalam komputasi

#include <iostream>
using namespace std;

int main()
{
   int D, *ptrD = &D ;     //deklarasi D dan pointer yang menunjuk ke D
   double PI= 3.14159;
   double* ptrPI = &PI; //pointer ke PI

   cout<<"Tuliskan diameter lingkaran: ";
   cin>>*ptrD;
   cout<<"Diameter = "<<*ptrD <<endl;

   double keliling = *ptrD * *ptrPI;            // = PI*D
   double luas = *ptrPI* *ptrD **ptrD/4; // = PI*D *D /4

   cout<<"Keliling = " <<keliling<<endl;
   cout<<"Luas lingkaran = " <<luas<<endl;

   return 0;
}
KELUARAN
n = 60  &n = 0018FF44    *&n = 60
ptrn = 0018FF44 ptrm = 0018FF44
Nilai yang ditunjuk oleh ptrn = 60
Nilai yang ditunjuk oleh ptrm = 60
Alamat dari ptrn = 0018FF40
PI=3.14159,      &PI = 0018FF34
*&PI = 3.14159 ,         *pPI = 3.14159



2.4 Pointer (yang menunjuk) ke Pointer
Sama seperti ketika Anda memiliki pointer yang menunjuk ke suatu variabel, Anda juga bisa mendefinisikan pointer yang menunjuk ke pointer untuk menjejak alamat pointer yang menunjuk ke variabel. Pada program berikut, n adalah sebuah variabel integer dengan nilai 57, ptrn adalan nama dari pointer yang menunjuk ke n dan pptrn adalah nama dari pointer yang menunjuk ke ptrn. Pointer ptrn yang menunjuk ke n dan pointer pptrn yang menunjuk ke pointer ptrn dideklarasikan dan diinisialisasi berikut.

int* ptrn = &n ;           //ptrn adalah pointer yang menunjuk ke n
int** pptrn = & ptrn ;     //pptrn adalah pointer yang menunjuk ke ptrn


Perhatikan bahwa keduanya, pointer maupun pointer ke pointer, bertipe int karena n adalah integer. Perhatikan pula bahwa untuk mendapatkan nilai dari variabel, Anda menggunakan satu operattor dereferensi (*) untuk pointer sedangkan untuk mendapatkan nilai dari variabel dari pointer (yang menunjuk) ke pointer, Anda perlu menggunakan dua operator dereferensi (**). Tetapi tidak ada perubahan pada penerapan atas operator alamat &. Perhatikan bahwa Anda tidak bisa menggunakan &&n karena & memerlukan suatu nilai kiri (l-value) sedangkan &n adalah suatu nilai kanan (r-value). Objek yang ditempatkan di sisi kiri dari operator penugasan (=) adalah nilai kiri dan objek yang ditempatkan di sisi kanan dari operator penugasan (=) adalah nilai kanan.


Program 2.6 Mengilustrasikan aplikasi dari pointer (menunjuk) ke pointer

#include <iostream>
using namespace std;

int main()
{
   int n = 57 ;
   int* ptrn = &n;   //pointer ke n

   cout<<"n = "<<n<<", Alamat dari n = " <<&n<<endl;
   cout<<"ptrn = "<< ptrn<<endl;
   cout<<"Alamat dari ptrn = "<<&ptrn<<endl;

   int** pptrn = &ptrn; //pointer ke pointer ke n
   cout<<"pptrn = "<<pptrn<<endl;

   int*** ppptrn = &pptrn; //pointer ke pointer ke pointer ke n
   cout<<"Alamat dari pptrn = "<<&pptrn<<endl;

   cout<<"ppptrn = "<<ppptrn<<"\n";
   cout<<"*ptrn = "<<*ptrn<<endl;

   cout<<"*pptrn = "<<*pptrn<<endl;
   cout<<"**pptrn = "<<**pptrn<<endl;

   cout<<"***ppptrn = "<<***ppptrn<<endl;

   return 0;
}
KELUARAN
n = 57, Alamat dari n = 0012FF7C
ptrn = 0012FF7C
Alamat dari ptrn = 0012FF78
pptrn = 0012FF78
Alamat dari pptrn = 0012FF74
ppptrn = 0012FF74
*ptrn = 57
*pptrn = 0012FF7C
**pptrn = 57
***ppptrn = 57

Keluaran dari program tersebut diilustrasikan pada Gambar 2.4.


GAMBAR 2.4 Nilai-nilai yang dituliskan di dalam blok-blok memori adalah nilai-nilai yang disimpan di dalam blok-blok memori. Alamat dari tiap blok dituliskan di bawah blok.


Pada deklarasi atas pointer ke float dan ke double, kedua tipe tidak bisa dicampur seperti diilustrasikan berikut.

float m ;                  //variabel bertipe float
float* ptrm = & m;         //pointer ke float, jangan gunakan double.
float** kptrm = & ptrm;    //pointer ke pointer, bertipe float
double n ;                 //variabel double
double* ptrn = &n;         //pointer ke double, jangan gunakan float.
double** kptrn = &ptrn     //pointer ke pointer ke double


POINTER KONSTAN
Pemodifikasi const dapat pula digunakan pada pointer. Namun, deklarasi seharusnya dilakukan dengan hati-hati, seperti berikut.

const int* ptr ;           //di sini, ptr adalah sebuah ptr tak-konstan yang
  menunjuk ke suatu int konstan

int* const ptr ;           //di sini, ptr adalah sebuah pointer konstan yang
  menunjuk ke suatu int tak-konstan

const int* const ptr ;     //di sini, ptr adalah sebuah pointer konstan yang menunjuk
  ke suatu int konstan


2.5 Pointer dan Array
Ketika Anda mendeklarasikan suatu array, pengenalnya (nama array) adalah sebuah pointer const yang menunjuk ke elemen pertama dari array. Pointer ke array tersebut juga membawa alamat dari elemen pertama array. Jadi, pointer ke sebuah array memiliki nilai sama dengan nama array. Perbedaannya adalah bahwa nama array adalah sebuah pointer const, yang tidak bisa diinkremen atau diubah sedangkan pointer yang menunjuk ke array yang membawa alamat dari elemen pertama array dapat diinkremen. Jika pointer yang menunjuk ke array diinkremen sebesar 1, maka pointer itu akan menunjuk ke elemen berikutnya dari array. Jadi, nilai dari pointer akan bertambah sebesar jumlah byte yang dialokasikan kepada satu elemen array. Deklarasi atas sebuah pointer yang menunjuk ke suatu array diilustrasikan berikut.

int A[] = {12, 25, 36, 50};       //A adalah nama array
int *ptrA ;
ptrA = A ;                 //Perhatikan bahwa tidak ada operator & digunakan

Definisi tersebut dapat pula dituliskan berikut.

int *ptrA = A;

dan juga dituliskan sebagai,

int* ptrA = &A[0];

Hal itu karena alamat dari A[0] sama dengan nilai dari A. Elemen-elemen array A[0], A[1], A[2], dan A[3] yang memiliki nilai-nilai berturut-turut 12, 25, 36, dan 50 dapat diperoleh dari pointer-pointer seperti diilustrasikan berikut.

A[0] = *ptrA;
A[1] = *(ptrA+1);
A[2] = *(ptrA+2);
A[3] = *(ptrA+3);

Diskusi tersebut menunjukkan bahwa indeks array dan offset pointer adalah sama. Jika Anda memanggil array A tanpa indeks, maka yang dihasilkan adalah alamat dari elemen pertama array. A + 1 menghasilkan alamat dari elemen kedua array, A + 2 menghasilkan alamat dari elemen ketiga array, dan seterusnya. Oleh karena itu, Anda juga dapat memperoleh nilai-nilai yang disimpan pada alamat-alamat tersebut menggunakan operator dereferensi (*). Jadi, untuk array yang dideklarasikan tersebut, Anda bisa mendapatkan nilai dari tiap elemen array sebagai berikut.

*A = 12
*(A+1) = 25
*(A+2) = 36
*(A+3) = 50


Perhatikan bahwa ekspresi *A++ tidak legal karena A adalah suatu pointer konstan yang menunjuk ke array dan sebuah konstanta tidak bisa diinkremen. Perhatikan pula bahwa indeks array sama dengan offset pointer untuk menjelajahi elemen-elemen array.

Program 2.7 Mengilustrasikan deklarasi atas pointer ke array

#include <iostream>
using namespace std;

int main()
{
   int A[] = {80, 40, 20, 10};    //A adalah sebuah array integer
   int *ptrA = A;    //ptrA adalah pointer ke array A. Perhatikan bahwa A tidak digunakan

   cout<<"*ptrA = "<<*ptrA<<" , \tptrA = "<<ptrA<<endl;
   cout<<"*(ptrA+1) = "<<*(ptrA+1)<<" ,\tptrA+1 = "<<ptrA+1<<endl;

   cout<<"*(ptrA+2) = "<<*(ptrA+2)<<" , \tptrA + 2 = "<<ptrA+2<<endl;
   cout<<"*(ptrA+3) = "<<*(ptrA+3)<<" , \tptrA+3= "<<ptrA+3<<"\n\n";

   cout<<"A = " <<A<<endl;
   cout<<ptrA[0]<<"\t"<<ptrA[1]<<"\t"<<ptrA[2]<<"\t"<<ptrA[3]<<endl;

   cout<<*(A+0)<<"\t"<<*(A+1)<<"\t"<<*(A+2)<<"\t"<<*(A+3)<<endl;
   //ini akan menampilkan nilai dari tiap elemen array

   return 0;
}
KELUARAN
*ptrA = 80 ,            ptrA = 0018FF38
*(ptrA+1) = 40 ,        ptrA+1 = 0018FF3C
*(ptrA+2) = 20 ,        ptrA + 2 = 0018FF40
*(ptrA+3) = 10 ,        ptrA+3= 0018FF44

A = 0018FF38
80      40      20      10
80      40      20      10

Dari keluaran program, Anda dapat melihat bahwa nilai dari A sama dengan nilai dari pointer ptrA yang menunjuk ke array. Keduanya menghasilkan alamat dari elemen pertama array, yaitu A = ptrA = 0018FF38.


Sekarang ptrA + 1 memiliki nilai 0018FF3C yang jaraknya 4 byte dari alamat dari elemen pertama array dan bahwa pada alamat itu nilai yang disimpan adalah *(ptrA + 1) = 40; atau *(A + 1) = 40, yang merupakan elemen kedua array. Oleh karena itu, ketika sebuah pointer yang menunjuk ke array diinkremen sebesar 1, pointer itu akan menunjuk ke elemen berikutnya di dalam array. Nilainya, pada dasarnya, diinkremen sebesar jumlah byte yang dialokasikan kepada satu elemen array. Sama halnya, ptrA + 2 adalah pointer yang menunjuk ke elemen ketiga, ptrA + 3 adalah pointer yang menunjuk ke elemen keempat array. Program berikut mengilustrasikan penjelajahan array menggunakan pointer.

Program 2.8 Mengilustrasikan penjelajahan array menggunakan pointer

#include <iostream>
using namespace std;

int main()
{
   int kim[] = {50, 86, 90, 12};
   int* pkim = kim; //mendefinisikan pointer ke array kim

   for (int i=0 ;i<4; i++) //loop for untuk menampilkan isi array
      cout<<"kim["<<i<<"] = "<<*(pkim +i)<<", ";
   //*(pkim +i) adalah nilai dari elemen kim[i] dari array

   return 0;
}
KELUARAN
kim[0] = 50, kim[1] = 86, kim[2] = 90, kim[3] = 12,


Pada kasus array, penginkremenan pointer sebesar satu, pada dasarnya, menambah nilai dari pointer sebesar ukuran byte dari satu elemen array. Jadi, jika pkim menunjuk ke elemen pertama dari array, maka pkim + 1 akan menunjuk ke elemen kedua array. Pada program berikut, elemen-elemen array akan dikenai operasi-operasi aritmatika dengan bantuan array.

Program 2.9 Mengilustrasikan pemanipulasian elemen-elemen array dengan pointer-pointer

#include <iostream>
using namespace std;
int main()
{
   int kim[] = {6,8,5,4} ; //array dengan empat elemen
   int* pkim = kim;               //deklarasi pointer

   for (int i=0; i<4; i++)
      cout<<"kim2["<<i<<"] = "<<*(pkim +i)**(pkim +i)<<", ";
   //menciptakan array kim2 dari elemen-elemen array kim

   cout<<"\n";
   for(int j= 0; j<4; j++) //menciptakan array kim3
      cout<<"kim3["<<j<<"]= "<<*(pkim+j)**(pkim +j) - *(pkim+j)<<", ";

   cout<<"\n";
   return 0;
}
KELUARAN
kim2[0] = 36, kim2[1] = 64, kim2[2] = 25, kim2[3] = 16,
kim3[0]= 30, kim3[1]= 56, kim3[2]= 20, kim3[3]= 12,



2.6 Array yang Memuat Pointer-Pointer (menunjuk) ke Array-Array
Pada program berikut, sebuah array yang memuat pointer-pointer int *pAB[2] dideklarasikan untuk dua array. Elemen pertama adalah pointer pAB[0] yang menunjuk ke array A dengan empat elemen 80, 70, 60, dan 50, dan elemen kedua adalah pointer pAB[1] yang menunjuk ke array B dengan elemen-elemen 10, 20, 30, dan 40. Program berikut mengilustrasikan bagaimana menampilkan elemen-elemen dari array A dan array B.

Program 2.10 Mengilustrasikan sebuah array yang memuat pointer-pointer ke array-array

#include <iostream>
using namespace std;

int main()
{
   int A[] = {80, 70, 60, 50} ; //array A
   int B[] = {10, 20, 30, 40};    //array B
   int* pAB[] = {A, B} ;

   //Array yang memuat pointer-pointer yang diinisialisasi dengan
   //nama array A dan B
   cout<<"Alamat dari A = "<<A<<endl;
   cout<<"Alamat dari B = "<<B<<"\n\n";

   cout<<"Alamat dari elemen pertama dari pAB[0] = "<<pAB<<endl;
   cout<<"Alamat dari elemen kedua dari pAB[1] = "<<pAB +1<<endl;

   cout<<"*pAB = "<<*pAB <<",\t**pAB = "<<** pAB <<"\n\n";
   // Here *pAB = A and **pAB = A[0], see the output below.

   cout<<"A[0] = *(*pAB) = "<<* (* pAB)<<endl;
   cout<<"A[1] = *(*pAB+1) ="<<*(*pAB+1)<<endl;

   cout<<"A[2] = *(*pAB+2) = "<<*(*pAB +2)<<endl;
   cout<<"A[3] = *(*pAB+3) = "<<*(*pAB +3)<<endl<<endl;
  
   cout<<"*(pAB+1)= " <<*(pAB+1) <<"\t **(pAB+1) = " <<**(pAB+1)<< endl;
   //di sini, *(pAB+1) = B dan **(pAB +1) = B[0], lihat keluaran

   cout<<"B[0]= *(*(pAB+1)) = "<<*(*(pAB+1)+0)<<endl;
   cout<<"B[1] = *(*(pAB+1)+1) = "<<*(*(pAB+1)+1)<<endl;

   cout<<"B[2]= *(*(pAB+1)+2) = "<<*(*(pAB+1)+2)<<endl;
   cout<<"B[3] = *(*(pAB+1)+2) ="<<*(*(pAB+1)+3 )<<endl;

   return 0;
}
KELUARAN
Alamat dari A = 0018FF38
Alamat dari B = 0018FF28

Alamat dari elemen pertama dari pAB[0] = 0018FF20
Alamat dari elemen kedua dari pAB[1] = 0018FF24
*pAB = 0018FF38,        **pAB = 80

A[0] = *(*pAB) = 80
A[1] = *(*pAB+1) =70
A[2] = *(*pAB+2) = 60
A[3] = *(*pAB+3) = 50

*(pAB+1)= 0018FF28       **(pAB+1) = 10
B[0]= *(*(pAB+1)) = 10
B[1] = *(*(pAB+1)+1) = 20
B[2]= *(*(pAB+1)+2) = 30
B[3] = *(*(pAB+1)+2) =40


Pada kode tersebut, Anda memberitahu bahwa inisialisasi dari array pointer dilakukan dengan menggunakan nama-nama array karena merupakan pointer-pointer konstan ke array-array. Pada program berikut, Anda memiliki tiga array dan mendeklarasikan sebuah array yang memuat pointer-pointer yang menunjuk ke ketiga array tersebut. Inisialisasi dari array pointer itu dilakukan menggunakan nama-nama array.

Program 2.11 Mengilustrasikan contoh lain dari sebuah array yang memuat pointer-pointer ke array-array

#include <iostream>
using namespace std;

int main()
{
   int Satu[] = {6, 8, 5, 4} ;                  //array dengan 4 elemen
   int Dua[] = {2, 3, 7};                       //array dengan 3 elemen
   int Tiga[] = {10, 11, 12, 13,14 };    //array dengan 5 elemen

   int* pKBS[] = {Satu , Dua, Tiga};
   //array pointer, inisialisasi dilakukan menggunakan nama-nama array

   cout<<"Satu : "<<**pKBS<<"\t"<<*(*(pKBS)+1) <<"\t"<<*(*(pKBS)+2)<<"\t"
       <<*(*(pKBS)+3)<<endl; //mendapatkan elemen-elemen dari array Satu

   cout<<"Dua : "<<*(*(pKBS+1))<<"\t"<<*(*(pKBS+1)+1)<<"\t"<< *(*(pKBS+1)+2)
       <<endl; //mendapatkan elemen-elemen dari array Dua

   cout<<"Tiga : " <<*(*(pKBS+2))<<"\t" <<*(*(pKBS+2)+1)<<"\t"
          <<*(*(pKBS+2)+2)<<"\t"<<*(*(pKBS+2)+3)<<"\t"<<*(*( pKBS+2)+4)<<endl;
   //mendapatkan elemen-elemen dari array

   return 0 ;
}
KELUARAN
Satu : 6        8       5       4
Dua : 2 3       7
Tiga : 10       11      12      13      14



2.7 Pointer ke Array Multi-Dimensi
POINTER KE ARRAY DUA DIMENSI
Program 2.11 pada dasarnya adalah sebuah contoh dari array dua-dimensi, karena, sebuah array dengan elemen-elemen berupa array satu dimensi merupakan sebuah array dua dimensi. Pada deklarasi atas pointer ke array dua dimensi, Anda juga menugaskan alamat array menggunakan nama array yaitu alamat dari elemen pertama array. Deklarasi tersebut dilakukan sebagai berikut.

int A[n][m];         //A adalah sebuah array dua dimensi
int (*pA)[m] = A ;   //pointer ke array dua dimensi

Sebuah elemen dari array dua dimensi dengan indeks i dan j dapat diakses dengan berikut.

A[i][j]

Pada notasi pointer, elemen tersebut dapat diakses dengan ekspresi berikut.

*(*(A+ i) + j)

atau dengan menggunakan pointer pA berikut

*(*(pA +i)+j)

Program berikut mengilustrasikan deklarasi dan keluaran dari sebuah array dua dimensi.

Program 2.12 Mengilustrasikan pointer ke array dua dimensi

#include <iostream>
using namespace std;

int main()
{
   int KBS[3][4] = {6,8,5,4, 2,3,7,9, 10,11,12,13};
   int(*pKBS)[4] = KBS ; //deklarasi dari pointer ke KBS

   cout<<**pKBS<<"\t"<<*(*(pKBS)+1)<<"\t"<<*(*(pKBS)+2)<<"\t"
       <<*(*(pKBS)+3)<<endl;

   cout<<*(*(pKBS+1))<<"\t"<<*(*(pKBS+1)+1)<<"\t"<<*(*(pKBS+1)+2)<<"\t"
          << *(*(pKBS+1)+3) <<endl;

   cout<<*(*(pKBS+2))<<"\t"<<*(*(pKBS+2)+1)<<"\t"<<*(*(pKBS+2)+2)
       <<"\t"<<*(*( pKBS+2)+3)<<endl;

   return 0;
}
KELUARAN
6       8       5       4
2       3       7       9
10      11      12      13


Dari keluaran program, Anda dapat melihat bahwa A[i][j] dan pada notasi pointer *(*(pA+i)+j) adalah dua ekspresi yang ekivalen. Jadi, Anda bisa juga menggunakan ekspresi *(*(pA+i)+j) untuk menjelajah sebuah array dua dimensi atau matriks.


DEKLARASI POINTER KE ARRAY TIGA DIMENSI
Array tiga dimensi adalah sebuah array yang memuat matriks-matriks. Dimisalkan bahwa A adalah sebuah array tiga dimensi. Deklarasi pointer dan inisialisasinya dilakukan seperti berikut.

int A[2][3][4];
int (*pA)[3][4] = A;       //pointer ke array A

Di sini, (*pA)[3][4] adalah pointer yang menunjuk ke array A[2][3][4]. Sebuah elemen array dengan indeks i, j, dan k dapat diakses dengan ekspresi berikut.

A[i][j][k]

Dan pada notasi pointer, sebuah elemen dengan indeks i, j, dan k dapat diakses dengan ekspresi berikut.

*(*(*(A +i) + j) + k)


Pada program berikut, sebuah array tiga dimensi dideklarsikan. Untuk menampilkan isi dari array tersebut, Anda menggunakan notasi pointer sebagai sebuah array yang memuat dua matriks.

Program 2.13 Mengilustrasikan pointer ke array tiga dimensi

#include <iostream>
using namespace std;

int main()
{
   int KBS[2][3][4] = {6,8,5,4, 2,3,7,9, 1,2,3,4, 21,22,23,24, 31,32,33,34,
                        41, 42, 43, 44} ; //sebuah array tiga dimensi
   int(* pKBS )[3][4] = KBS; //deklarasi pointer

   for (int i = 0; i<2; i++)
   {
      for (int j =0; j <3; j++)
      {
         for (int k =0; k<4; k++)
            cout<<*(*(*(pKBS +i) + j) +k)<<" ";
         cout<<"\n";
      }
      cout<<"\n";
   }

   return 0;
}
KELUARAN
6 8 5 4
2 3 7 9
1 2 3 4

21 22 23 24
31 32 33 34
41 42 43 44


2.8 Pointer ke Fungsi
Pada bagian sebelumnya, Anda telah melihat bahwa nama array memuat nilai dari alamat dari elemen pertama array dan merupakan sebuah pointer konstan yang menunjuk ke array. Sama halnya, nama dari sebuah fungsi juga memuat alamat dari fungsi dan merupakan sebuah pointer yang menunjuk ke fungsi. Oleh karena itu, Anda dapat mendeklarasikan sebuah pointer yang menunjuk ke suatu fungsi dan menginisialisasinya dengan nama fungsi. Pointer yang menunjuk ke suatu fungsi dapat dideklarasikan sebagai berikut.

tipe (*pengenal_untuk_pointer)(tipe_parameter_fungsi);

Di sini, tipe mengacu pada tipe data yang dihasilkan oleh fungsi, pada kurung pertama terdapat operator indireksi yang diikuti oleh nama pointer. Kurung kedua memuat tipe data dari tiap parameter fungsi. Dimisalkan bahwa Fptr adalah nama pointer yang menunjuk ke sebuah fungsi Fung dengan tipe int dan yang memerlukan dua parameter integer, yaitu int Fung(int, int). Pointer yang menunjuk ke fungsi ini dideklarasikan sebagai berikut.

int (*Fptr) (int, int);

Deklarasi tersebut pada dasarnya diperuntukkan bagi sembarang fungsi yang memiliki nilai balik bertipe int dan memiliki dua parameter int. Dimisalkan bahwa int Fung1(int, int) dan int Fung2(int, int) merupakan dua fungsi yang memenuhi kriteria di atas. Deklarasi dari pointer tersebut dapat diterapkan kepada kedua fungsi ini. Jadi, jika Anda menugaskan nilai berikut kepada Fptr,

Fptr = Fung1;        //Fptr menunjuk ke Fung1

Pointer FPtr menunjuk ke Fung1. Fungsi Fung1 dapat dipanggil menggunakan operator dereferensi berikut.

int a , b;
(*Fptr)(a, b);       //memanggil fungsi

Pada dasarnya, operator dereferensi tidak diperlukan dan fungsi dapat dipanggil dengan berikut.

Fptr(a, b);

Sekarang, Anda dapat pula menginisialisasi FPtr dengan alamat dari Fung2.

Fptr = Fung2;              //pointer FPtr sekarang menunjuk ke Fung2

Dengan definisi tersebut, pointer Fptr sekarang menunjuk ke Fung2. Fungsi Fung2 dapat dipanggil dengan ekspresi (*Fptr)(i, d) atau dengan Fptr(i, d) dimana i dan d adalah integer. Ini memberikan fasilitas kepada user untuk memilih salah satu fungsi yang disediakan di dalam program yang sesuai dengan deklarasi pointer.

Pada deklarasi tersebut, *Fptr diapit di dalam kurung karena, kalau tidak, hanya akan ada satu kurung yang mengapit parameter, dan yang memiliki keutamaan lebih keutamaan daripada operator *. Jadi, ekspresi seperti int *Fptr(int, int) berarti bahwa fungsi Fptr memerlukan dua argumen int dan menghasilkan sebuah pointer yang menunjuk ke suatu integer. Oleh karena itu, adalah diperlukan untuk mengapit *Fptr di dalam kurung. Program berikut mengilustrasikan penggunaan dari pointer yang menunjuk ke fungsi. User dapat memilih salah satu dari keempat fungsi, dan pilihan itu difasilitasi oleh statemen switch.

Program 2.14 Mengilustrasikan pointer ke fungsi

#include <iostream>
using namespace std;

int F1(int n){return n;}          //menghasilkan argumen
int F2(int n){return n*n;}        //menghasilkan kuadrat dari argumen
int F3(int n){return n*n*n;}             //menghasilkan pangkat tiga dari argumen
int F4(int n){return n*n*n*n;}    //menghasilkan pangkat empat dari argumen

int main()
{
   int m;
   int (*Fptr)(int m);     //pointer ke fungsi-fungsi tersebut

   cout<<"Tuliskan sebuah integer: ";
   cin>>m ;

   int pilihanUser ; //user memilih fungsi
   cout<<"Berikan pilihan Anda antara 1 sampai 4: ";
   cin>>pilihanUser;

   switch (pilihanUser)
   {
      case 1:
         Fptr = F1 ; //memilih fungsi F1
         cout<<m<<" dipangkatkan 1 = "<<F1(m)<<endl ;
         break;

      case 2:
         Fptr = F2 ; //memilih fungsi F2
         cout<<m<<" dipangkatkan 2 = "<<F2(m)<<endl;
         break;

      case 3:
         Fptr = F3 ; //memilih fungsi F3
         cout<<m<<" dipangkatkan 3 = "<< F3(m)<<endl;
         break;

      case 4:
         Fptr = F4 ; //memilih fungsi F4
         cout<<m<<" dipangkatkan 4 = "<< F4(m)<<endl;
         break;

      default:
         cout<<"Berikan pilihan kedua antara 1 sampai 4"<<endl;
   }

   return 0;
}
KELUARAN
Tuliskan sebuah integer: 35
Berikan pilihan Anda antara 1 sampai 4: 4
35 dipangkatkan 4 = 1500625



2.9 Array yang Memuat Pointer-Pointer ke Fungsi-Fungsi
Fungsi tidak dapat menjadi elemen array. Namun Anda dapat memiliki sebuah array yang memuat pointer-pointer yang menunjuk ke fungsi-fungsi yang berbeda. Fungsi dapat dipanggil di dalam main() melalui pointer. Pada program berikut, Anda mendekalarasikan array yang memuat pointer-pointer yang menunjuk ke tiga fungsi yang semuanya bertipe int. Fungsi-fungsi didefinisikan di luar main(), karens sebuah fungsi tidak bisa didefinisikan di dalam fungsi lain. Fungsi pertama menghasilkan argumen, fungsi kedua menghasilkan kuadrat dari argumen, dan fungsi ketiga menghasilkan pangkat tiga dari argumen.

Program 2.15 Mengilustrasikan array yang memuat pointer-pointer ke fungsi-fungsi

#include<iostream>
using namespace std;

int fung1(int);      //prototipe fungsi dari fung1
int fung2(int) ;     //prototipe fungsi dari fung2
int fung3(int);      //prototipe fungsi dari fung3

int main()
{
   int P;
   int (*F[3])(int)={fung1, fung2, fung3}; //array yang memuat tiga pointer
   //inisialisasi dilakukan menggunakan nama-nama fungsi

   cout<<"Masukkan sebuah nilai: ";
   cin>>P;
  
   cout<<"Anda telah memasukkan nilai: "<<P<<endl;

   for(int i=0;i<3;i++) //loop for untuk memanggil fungsi-fungsi yang berbeda
      cout<<"Pangkat "<<i+1<<" dari nilai "<<P<<" = "<<(*F[i])(P)<<endl;

   return 0;
}

int fung1(int a) //definisi dari fung1
{
   return a;
}

int fung2(int a) //definisi dari fung2
{
   return a*a;
}

int fung3(int a) //definisi dari fung3
{
   return a*a*a;
}
KELUARAN
Masukkan sebuah nilai: 17
Anda telah memasukkan nilai: 17
Pangkat 1 dari nilai 17 = 17
Pangkat 2 dari nilai 17 = 289
Pangkat 3 dari nilai 17 = 4913



2.10 Pointer ke Fungsi Sebagai Parameter dari Fungsi Lain
Nama dari sebuah fungsi memuat alamat dari fungsi itu. Sebuah fungsi dapat memiliki fungsi lain sebagai salah satu dari parameternya. Jadi, sebuah fungsi dapat dilewatkan kepada fungsi lain sebagai argumennya menggunakan nama fungsi atau menggunakan pointer yang memuat alamat dari parameter fungsi tersebut. Dengan pointer ke fungsi sebagai parameter, user memiliki fasilitas untuk memilih fungsi-fungsi. Anda bisa mendapatkan lebih dari satu nilai dari suatu fungsi.

Pada program berikut, sebuah fungsi dengan nama Fungsi diberikan dengan tipe double yang menghasilkan suatu nilai double. Pointer ke fungsi-fungsi lain, yaitu double(*)(double, double, double) merupakan salah satu parameter. Tiga parameter fungsi lain adalah double, double, double. Pointer dipakai untuk memanggil dua fungsi, volume dan luas permukaan dari sebuah prisma kubik.

Program 2.16 Mengilustrasikan pointer ke fungsi sebagai parameter dari fungsi lain

#include <iostream>
using namespace std;

double Fungsi(double (*)(double, double, double), double, double, double);
//prototipe dari Fungsi()

double volume(double, double, double);   //prototipe dari fungsi volume()
double permukaan(double, double, double); //prototipe dari fungsi permukaan()

int main()
{
   cout<<"Luas permukaan dan volume dari bangun kubik dengan sisi-sisi 4.0,5.0,6.0:"<<endl;

   cout<<"Luas permukaan = "<<Fungsi(permukaan, 4.0,5.0,6.0)<<endl;
  
   cout<<"Volume = "<<Fungsi(volume,4.0,5.0,6.0)<<endl;

   return 0;
}

//definisi dari fungsi Fungsi
double Fungsi(double(*pF)(double k, double m, double n), double p, double q, double r)
{
   return (*pF)(p,q,r);
}

//berikut adalah definisi dari fungsi permukaan
double permukaan(double k, double m, double n)
{
   return 2*(m*k+ n*k+ m*n);
}

// berikut adalah definisi dari fungsi volume
double volume(double k, double m, double n)
{
   return k*m*n;
}
KELUARAN
Luas permukaan dan volume dari bangun kubik dengan sisi-sisi 4.0,5.0,6.0:
Luas permukaan = 148
Volume = 120



LATIHAN
1.       Apa itu pointer? Bagaimana ia dideklarasikan untuk sebuah integer?
2.   Sebuah variabel integer x memiliki nilai 50. Tuliskan kode untuk mendeklarasikan variabel itu, referensinya dengan nama xKu dan pointer dengan nama ptrx.
3.      Tuliskan sebuah program uji yang mendeklarasikan sebuah variabel float y, yang diinisialisasi dengan 0. Ciptakan sebuah referensi dengan nama refy. Sekarang ubah y menjadi 6.454. Carilah nilai dari refy dan lokasi memorinya.
4.      Apakah ukuran (dalam byte) dari ruang memori yang dialokasikan untuk pointer yang menunjuk ke
a.        sebuah nilai long int
b.       sebuah nilai float
c.        sebuah variabel karakter
d.       sebuah nilai double
5.       Tuliskan kode untuk mendeklarasikan pointer yang menunjuk ke
a.        array satu dimensi
b.       array dua dimensi
c.        array tiga dimensi
6.       Bagaimana Anda mendapatkan nilai dari variabel melalui pointer yang menunjuk ke pointer?
7.   Tuliskan sebuah program untuk mendeklarasikan sebuah variabel int dan pointernya dan untuk menentukan kuadrat dan pangkat tiga dari variabel itu menggunakan pointernya.
8.       Bagaimana Anda mendeklarasikan pointer yang menunjuk ke pointer untuk
a.        variabel int
b.       variabel double
c.        variabel float
9.       Apa yang salah dengan kode berikut.
a.        int* ptrn = n;
b.       double ptrnPI = 3.14159;
c.        char *ch = A;
10.    Apa perbendaan antara referensi dan pointer?
11.    Apa yang Anda pahami dari berikut.
a.        int (*Fungsi)(int, int);
b.       double(*Fungsi[])(int, int, double)
12.    Jelaskan perbedaan antara dua deklarasi berikut.
a.        int (*A)[6];
b.       int *A[6];
13.    Jelaskan perbedaan dari deklarasi-deklarasi berikut.
a.        const int* ptr;
b.       int * const ptr;
c.        const int * const ptr;
14.    PA adalah sebuah pointer yang menunjuk ke array A[10]. Mana sajakah yang benar untuk mengakses elemen berikutnya dari array?
a.        *PA + 1;
b.       *(PA + 1);
c.        *A++;
15.    Tuliskan sebuah program untuk mengilustrasikan kegunaan dari pointer untuk menjelajah sebuah array.





No comments: