SEbenARNYA blogger vyze di kampUs dapat tugas "memasukan data ke variabel dinamis (for to do)" tapi malas ngerjakan. wkwkwkw
nah ini aku ada dapat bahan materinya untuk pascal, mungkin bermanfaat untuk sobat gaptek yang pengen belajar pascal ato bagi sobat Vyze yang ambil jurusan ti..
so..
SILAHKAN DINIKMATI
ALGORITMA DAN PEMROGRAMAN 2
Oleh: Anis Cherid, MTI
VARIABEL STATIS DAN VARIABEL DINAMIS
Dalam
berbagai contoh pada modul sebelumnya, penggunaan variabel pointer
adalah penggunaan yang sia-sia. Mengapa demikian? Karena nilai suatu
variabel dapat diambil atau diubah secara langsung dengan menggunakan
nama variabel yang bersangkutan, tanpa perlu menggunakan variabel
pointer. Dalam berbagai contoh pada modul sebelumnya, variabel yang
dipergunakan adalah variabel statis, yaitu variabel yang memiliki 3 ciri penting, yang dapat diuraikan sebagai berikut:
- Variabel statis memiliki nama. Pemberian nama dilakukan dalam bagian deklarasi variabel (misalnya: var a, b:integer).
- Variabel statis menempati bagian memori yang disebut data segment, sehingga tidak bisa dihapus dari memori begitu program dieksekusi atau tidak bisa diubah ukuran elemennya jika variabel tersebut bertipe array.
- Variabel statis menempati bagian memori yang disebut data segment yang dibatasi ukurannya oleh compiler (maksimum 64 Kbyte).
Dengan demikian, ukuran maksimal dari sebuah variabel terstruktur (array dan record) yang bisa dideklarasikan dalam data segment (Turbo Pascal versi 5.5 dan 7.0) adalah 65.535 byte (64 Kilobyte). Sebuah array bertipe integer, maksimum hanya bisa terdiri dari 32.767 elemen (65.535/2 byte), sementara sebuah array bertipe real, maksimum hanya bisa terdiri dari 10.922 elemen (65.535/6 byte) . Jumlah elemen array yang bisa dibuat akan semakin sedikit jika tipe data yang disimpan dalam masing-masing elemen adalah tipe record. Misalnya jika kita mendeklarasikan variabel di bawah ini:
type
TMahasiswa = record
NIM : array [1..10] of '0'..'9';
Nama : string [40];
IPK : real;
end;
var arsipMahasiswa : array [1..maxNum] of TMahasiswa;
maka nilai maksimum konstanta maxNum adalah 1137. Dengan kata lain, hanya 1137 elemen dari array dengan tipe data record
di atas yang bisa dibuat. Jika kita membuat sebuah variabel terstruktur
di atas sebanyak 1137 elemen, maka tidak tersedia lagi tempat untuk
mendeklarasikan variabel lainnya.
Berbagai
keterbatasan ini bisa diatasi jika variabel terstruktur yang kita
butuhkan tidak kita tempatkan secara statis di dalam data segment, tetapi kita letakkan secara dinamis di dalam bagian memori yang disebut dengan heap. Memori heap adalah memori yang masih tersedia setelah program kita dimuat ke dalam memori dan alokasi memori untuk pendeklarasian variabel sudah dilakukan. Penempatan secara dinamis mengandung arti:
- Kita bisa membuat dan menghapus variabel yang kita inginkan kapan saja, meskipun program sudah dieksekusi.
- Ruang yang tersedia untuk pembuatan variabel menjadi jauh lebih banyak, karena yang menjadi batas bukanlah data segment, melainkan besarnya memori heap.
Kedua
butir di atas mengimplikasikan bahwa lebih beragam variabel yang bisa
kita masukkan dalam program yang kita buat, baik dari segi jenis dan
struktur maupun dari segi ukurannya. Dengan demikian, jika kita
diharuskan membuat program yang memiliki tugas-tugas yang lebih
kompleks, yaitu program yang kemungkinan besar akan membutuhkan jenis,
struktur dan ukuran data yang lebih beragam, tentu kita harus menggunakan variabel dinamis. Penggunaan variabel dinamis misalnya mutlak diperlukan jika kita harus membuat program yang menggunakan struktur data dinamis (misalnya linked-list). Contoh lain program yang membutuhkan variabel dinamis adalah program yang secara intensif membaca, mengolah dan menulis data ke dalam media penyimpanan sekunder (misalnya program pengolah kata dan basis data) atau program yang secara intensif berkomunikasi dengan komputer lain melalui sebuah saluran komunikasi [SHT00].
CONTOH 1
Di bawah ini adalah contoh mengalokasikan variabel dinamis di dalam memori heap:
program Contoh_1_Alokasi_Variabel_Dinamis;
type
string4=string[4];
var
alamatString:^string4;
begin
new(alamatString);
{Mengalokasikan sebuah variabel dinamis bertipe string...}
{...dalam memori heap. Variabel ini tidak memiliki nama...}
{...dan posisinya dalam memori ditunjuk oleh variabel...}
{...pointer alamatString.}
{Setelah statement di atas dilaksanakan, ruang kosong...}
{...dalam memori heap berkurang.}
alamatString^:='Budi';
{Mengisi lokasi memori yang sudah dialokasikan dengan...}
{...'Budi', atau dengan kata lain, mengisi variabel dinamis...}
{...yang ditunjuk pointer alamatString dengan 'Budi'.}
writeln(alamatString^);
{Menampilkan nilai variabel dinamis yang ditunjuk oleh...}
{...variabel pointer alamatString}
dispose(alamatString);
{Menghapus alamat yang dialokasikan, sehingga kondisi...}
{...memori heap kembali seperti sebelum dibuatnya...}
{...variabel dinamis}
end.
Untuk membebaskan memori yang sudah dialokasikan sehingga bisa digunakan untuk menyimpan variabel dinamis lainnya, kita menggunakan instruksi,
dispose (alamatString);
Seteleh statement dispose di atas dilaksanakan, blok memori heap yang sebelumnya dialokasikan untuk variabel dinamis yang ditunjuk oleh variabel pointer alamatString akan dikembalikan kepada sistem operasi, sehingga ukuran memori heap yang tersedia kembali seperti semula (yaitu seperti sebelum ada variabel dinamis yang dialokasikan). Namun demikian, alamat memori yang ditunjuk oleh variabel pointer alamatString, masih tetap alamat memori yang telah dialokasikan sebelumnya. Untuk memperjelas, perhatikan ilustrasi di bawah ini:
1. Kondisi memori heap sebelum alokasi variabel dinamis:
x+3
x
kosong
alamatString
HEAP
DATA SEGMENT
2. Kondisi memori heap sesudah pelaksanaan statement new(alamatString);
x+3
x
kosong
alamatString
HEAP
DATA SEGMENT
3. Kondisi memori sesudah pelaksanaan statement alamatString^:='Budi';
u
x+3
x
i
d
B
kosong
alamatString
HEAP
DATA SEGMENT
4. Kondisi memori sesudah pelaksanaan statement dispose(alamatString);
u
x+3
x
i
d
B
kosong
alamatString
HEAP
DATA SEGMENT
Variabel pointer alamatString
masih menunjuk alamat memori yang sebelumnya dialokasikan, meskipun
alamat tersebut sudah dianggap kosong oleh sistem operasi. Kekacauan
bisa muncul jika kita tidak mengosongkan nilai variabel pointer alamatString, seperti terlihat dalam contoh di bawah ini.
CONTOH 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
program Contoh_2_Nilai_Pointer_Tetap_Menunjuk_Alamat_Lama;
type
TName = string[20];
var
My_Name : ^TName;
My_Age : ^integer;
Her_Name : ^TName;
begin
My_Name := nil;
Her_Name := nil;
New (My_Name);
New (My_Age);
My_Name^ := 'Budi Raja';
My_Age^ := 15;
writeln ('My_Name^ = ',My_Name^);
{output: My_Name^ = Budi Raja}
writeln ('My_Age^ = ', My_Age^);
{output: My_Age^ = 15}
dispose(My_Name);
dispose(My_Age);
New (Her_Name);
Her_Name^ := 'Wati Ratu';
writeln('Her_Name^ = ', Her_Name^);
{output: Her_Name^ = Wati Ratu}
writeln('My_Name^ = ', My_Name^);
{output: My_Name^ = Wati Ratu}
My_Name^ := 'Budi SalahAlamat';
writeln ('Her_Name^ = ', Her_Name^);
{output: Her_Name^ = Budi SalahAlamat}
dispose (Her_Name);
end.
Dalam program di atas, meskipun memori yang dialokasikan untuk pointer My_Name sudah dibebaskan (dispose) pada baris ke 20, pointer My_Name masih menunjuk ke
alamat memori yang telah dibebaskan tersebut. Jika kita mengalokasikan
memori untuk pointer Her_Name dan mengisinya dengan sebuah nilai
(baris 23 – 24), maka memori yang dialokasikan untuk pointer Her_Name
adalah memori yang sebelumnya dialokasikan untuk My_name. Jika kita
berusaha menampilkan nilai dalam memori yang ditunjuk oleh pointer
My_Name (baris 27), maka nilai yang ditampilkan adalah nilai dari
Her_Name^. Dalam contoh di atas, Turbo Pascal tetap mengijinkan kita mengisi nilai ke
dalam memori yang ditunjuk oleh pointer My_Name (baris 28) dan bisa
menimbulkan kekacauan dalam program maupun dalam memori (dikenal dengan
istilah memory corruption). Karena itu, jadikanlah kebiasaan untuk mereset nilai pointer menjadi NIL,
jika memori yang dialokasikan untuk sebuah pointer sudah dibebaskan.
Dengan demikian, sebaiknya kita menyisipkan sebuah baris tambahan
sehingga baris 20 dan 21 menjadi sebagai berikut:
dispose(My_Name);
My_Name:= NIL;
dispose(My_Age);
My_Age:= NIL;
Variabel pointer yang memiliki nilai NIL,
tidak menunjuk alamat memori yang mana pun, sehingga jika kita
berusaha mengisi atau menampilkan isi memori yang ditunjuk oleh
variabel pointer tersebut (misalnya dengan instruksi My_Name:='Budi'), maka komputer akan menampilkan pesan kesalahan. Dengan demikian, mengisi variabel pointer yang memorinya sudah dibebaskan (dispose) dengan NIL, akan mencegah terjadinya memory corruption.
Variabel dinamis tidak memiliki nama dan dirujuk oleh variabel pointer yang digunakan sebagai parameter dari prosedur new.
Jika karena satu dan lain hal kita ingin menggunakan variabel pointer
tersebut untuk kebutuhan yang lain, kita harus menyimpan nilainya
dalam variabel pointer lainnya agar jangan sampai kita kehilangan jejak
terhadap alamat dalam memori heap yang menyimpan variabel dinamis tersebut. Selain itu, jangan lupa untuk melakukan dispose terhadap variabel dinamis
yang sudah tidak dibutuhkan lagi, agar memori yang sudah dialokasikan
bisa dipergunakan untuk kepentingan yang lain. Contoh berikut akan
memperjelas konsep ini.
CONTOH 3
program Heap_Overflow;
type
TName = array [1..65535] of char;
var
My_Name : ^TName;
i : word;
begin
i:=0;
while (true) do
begin
inc(i);
writeln(i);
new(My_Name);
end;
end.
Dalam
program di atas, kita melakukan loop yang tidak ada akhirnya dan pada
setiap loop kita mengalokasikan memori sebanyak 65.535 byte di dalam
memori heap untuk menyimpan karakter string. Setiap kali alokasi dibuat dengan statement new, pointer My_Name akan menunjuk ke
lokasi memori yang baru dialokasikan. Kita akan kehilangan jejak atas
posisi memori yang sebelumnya, meskipun lokasi memori tersebut tetap
dialokasikan oleh sistem operasi dan tidak bisa digunakan untuk
kepentingan lainnya. Peristiwa hilangnya bagian memori heap dari kendali program dikenal dengan istilah memory leak.
POINTER DAN ARRAY DINAMIS
Pointer bisa dipergunakan untuk mengalokasikan array secara dinamis di dalam memori heap. Keuntungan dari menggunakan array yang bersifat dinamis adalah jumlah elemennya bisa diubah-ubah sesuai kebutuhan. Di bawah ini adalah program Pascal yang dipergunakan untuk meminta operator memasukkan jumlah elemen array yang diinginkan. Kemudian program akan mengalokasikan array
dengan jumlah elemen sebanyak yang diminta operator dan mengisi
masing-masing elemen dengan nilai acak. Selama program berjalan, ukuran
array yang dialokasikan dalam memori heap berubah-ubah sesuai yang diminta operator.
Program_Pascal_Mengalokasikan_Array_Dinamis;
uses wincrt;
var
num,index:integer;
p, ptemp:^integer;
label keluar_loop;
begin
repeat
write('Berapakah jumlah data yang akan dimasukkan? ');
readln(num);
if num=0 then goto keluar_loop;
{*****
Mengalokasikan array secara dinamis
sebanyak #num# elemen
*****}
getmem(p, sizeof(integer) * num);
for index:= 0 to num-1 do begin
{*****
Menjadikan ptemp menunjuk alamat memori dari
masing-masing index
*****}
ptemp := ptr(seg(p^), ofs(p^) + index*sizeof(integer));
{*****
Mengisi alamat memori yang ditunjuk ptemp
dengan bilangan acak
*****}
ptemp^:= random(1000)+1;
end;
for index:=0 to num-1 do begin
{*****
Menjadikan ptemp menunjuk alamat memori dari masing-
masing index dan menampilkan isi dalam memori
*****}
ptemp := ptr(seg(p^), ofs(p^) + index*sizeof(integer));
writeln('Nilai ke-',index+1,': ',ptemp^);
end;
writeln('Sisa memori heap sesudah alokasi array: ', memavail);
writeln('Sisa memori heap maksimal yang bisa ',
'dialokasikan: ', maxavail);
{***** Membebaskan kembali memori yang sudah dialokasikan *****}
freemem(p, sizeof(integer) * num);
writeln;
until num<=0;
keluar_loop:
end.
Jika program di atas diimplementasikan menggunakan Bahasa C, hasilnya adalah demikian:
/* Program_C_Mengalokasikan_Array_Dinamis */
#include
#include
#include
#include /* dibutuhkan untuk fungsi alokasi memori */
void main(){
int num, index, *p;
randomize();
do {
printf("Berapakah jumlah data yang akan dimasukkan? ");
scanf("%d",&num);
if (num==0) break;
/*****
Mengalokasikan array secara dinamis
sebanyak #num# elemen
*****/
p = (int *) malloc (sizeof(int) * num);
for (index=0; index
/*****
Mengisi alamat memori yang ditunjuk ptemp
dengan bilangan acak
*****/
p[index] = random(1000)+1;
}
for (index=0; index
printf("Nilai ke-%d: %d\n", index+1, p[index]);
}
printf("Sisa memori heap sesudah alokasi array: %u",
coreleft());
/*****
Membebaskan kembali memori yang
sudah dialokasikan
*****/
free(p);
printf("\n");
} while (num>0);
}
Dalam contoh program berikut ini proses pengalokasian array secara dinamis juga diikuti dengan proses penyalinan isi elemen array dari array yang lama ke array yang baru dialokasikan. Berikut program dan penjelasannya [SHT00]:
1
2
3
4
5
6
7
8
9
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
#include
#include
#define NUM 3
int main(){
double nilai, total=0, *data=NULL, *temp=NULL;
int jumlah=0, ukuran=NUM, i;
data = (double *) malloc (sizeof(double)*ukuran);
do {
printf("Masukkan sebuah nilai (atau 0 untuk keluar): ");
scanf("%lf",&nilai);
if (nilai==0) break;
if (jumlah==ukuran){
ukuran = ukuran * 2;
temp = (double *) malloc(sizeof(double)*ukuran);
if (temp==NULL){
printf("Tidak tersedia ruang dalam memori heap: "
"nilai masukan dibatalkan\n");
break;
} else {
printf("Memori tambahan berhasil dialokasikan. "
"ukuran = %d\n",ukuran);
for (i=0;i
temp[i]=data[i];
}
free(data);
data=temp;
}
}
total+=nilai;
data[jumlah++]=nilai;
} while (1);
if (nilai!=0){
printf("Tidak tersedia ruang dalam memori:"
"nilai masukan dibatalkan\n");
printf("Nilai %f tidak disimpan\n",nilai);
}
printf("Jumlah %d masukan adalah %f\n",jumlah,total);
if (jumlah==0) return 0;
printf("No. Transaksi Nilai\n\n");
for (i=0;i
printf( "%3d. %5.2f\n",i,data[i]);
}
return 0;
}
PENJELASAN CARA KERJA PROGRAM
Ketika baris 7 selesai dilaksanakan:
data = (double *) malloc (sizeof(double)*ukuran);
dalam memori heap akan dialokasikan array untuk menampung nilai bertipe double sebanyak 3 elemen. Mengapa 3 elemen? Karena nilai ukuran=3.
Alamat elemen ke-0 dalam memori heap ditunjuk oleh variabel pointer data, sehingga gambar logis dari kondisi memori dapat dilihat dalam gambar di bawah ini:
data[2]
data[0]
data
data[1]
Ketika loop do/while dilaksanakan:
Putaran 1:
Baris 10 dilaksanakan: scanf("%lf",&nilai)
Diasumsikan bahwa operator memasukkan nilai 20, sehingga nilai=20
Dengan demikian kondisi pada baris 11: if (nilai==0)tidak terpenuhi, sehingga instruksi break tidak dilaksanakan.
Demikian pula kondisi pada baris 12: if (jumlah==ukuran) tidak terpenuhi karena jumlah=0 dan ukuran=3.
Pelaksanaan program berlanjut ke baris 29: total+=nilai
Dengan demikian, total=20.
Baris 30: data[jumlah++]=nilai artinya data[0]=20 dan jumlah=1
Selanjutnya loop do/while akan memasuki putaran 2.
Putaran 2:
Baris 10 dilaksanakan: scanf("%lf",&nilai)
Diasumsikan bahwa operator memasukkan nilai 10, sehingga nilai=10
Dengan demikian kondisi pada baris 11: if (nilai==0)tidak terpenuhi, sehingga instruksi break tidak dilaksanakan.
Demikian pula kondisi pada baris 12: if (jumlah==ukuran) tidak terpenuhi karena jumlah=1 dan ukuran=3.
Pelaksanaan program berlanjut ke baris 29: total+=nilai
Dengan demikian, total=30.
Baris 30: data[jumlah++]=nilai artinya data[1]=10 dan jumlah=2
Selanjutnya loop do/while akan memasuki putaran 3.
Putaran 3:
Diasumsikan operator memasukkan nilai 30, sehingga:
nilai=30 total=60 data[2]=30 jumlah=3
Sesudah putaran 3 selesai dilaksanakan, kondisi memori menjadi seperti gambar di bawah ini:
20
data[2]
data[1]
data[0]
data
30
10
Perhatikan bahwa sesudah putaran 3 ini, array yang ada dalam memori heap sudah terisi semua elemennya. Bagaimana cara program menyelesaikan masalah jika operator memasukkan sebuah nilai lagi? Jawabannya terdapat dalam putaran 4.
Putaran 4:
Diasumsikan operator memasukkan nilai 40, sehingga: nilai=40
Pada putaran 4 ini, kondisi pada baris 12 if (jumlah==ukuran)terpenuhi, sehingga pelaksanaan program akan berlanjut ke baris 13:
ukuran=ukuran*2 sehingga ukuran=6
Baris 14:
temp = (double *) malloc(sizeof(double)*ukuran)
Jika diasumsikan bahwa program berhasil mengalokasikan tempat dalam memori heap untuk array bertipe double sebanyak 6 elemen, maka kondisi dalam baris 15 if (temp==NULL) tidak akan terpenuhi dan kondisi memori akan berubah menjadi:
20
data[2]
data[1]
data[0]
data
30
10
temp
temp[1]
temp[0]
temp[2]
temp[4]
temp[5]
temp[3]
Selanjutnya program akan berlanjut ke baris 20 dan pada layar komputer ditampilkan tulisan:
Memori tambahan berhasil dialokasikan. ukuran = 6
Selanjutnya, pada baris 22 s/d 24 dilaksanakan for loop yang bertujuan menyalin semua isi elemen array data ke dalam array temp, sehingga setelah loop ini selesai dilaksanakan, kondisi memori menjadi:
20
data[2]
data[1]
data[0]
data
30
10
temp
temp[1]
temp[0]
30
10
20
temp[2]
temp[4]
temp[5]
temp[3]
Selanjutnya, pada baris 25 free(data) akan menyebabkan memori yang dialokasikan untuk array data dihapus dan pada baris 26 data=temp akan menyebabkan pointer data menunjuk alamat yang juga ditunjuk oleh pointer temp. Hal ini dapat digambarkan sebagai berikut:
20
data[2]
data[1]
data[0]
data
30
10
temp
temp[1]
temp[0]
30
10
20
temp[2]
temp[4]
data[5]
data[3]
temp[3]
temp[5]
data[4]
data[2]
data[1]
data[0]
Pelaksanaan program berlanjut ke baris 29: total+=nilai
Dengan demikian, total=100.
Baris 30: data[jumlah++]=nilai artinya data[3]=30 dan jumlah=4
Selanjutnya loop do/while akan memasuki putaran 5.
Putaran 5:
Baris 10 dilaksanakan: scanf("%lf",&nilai)
Diasumsikan bahwa operator memasukkan nilai 0, sehingga nilai=0
Dengan demikian kondisi pada baris 11: if (nilai==0) terpenuhi, sehingga instruksi break dilaksanakan dan loop do/while berakhir.
Kondisi pada baris 32: if (nilai!=0) tidak terpenuhi, sehingga pelaksanaan progam berlanjut ke baris 37.
Pada baris 37, program akan menampilkan tulisan:
Jumlah 4 masukan adalah 100
Kondisi pada baris 37: if (jumlah==0) tidak terpenuhi, sehingga instruksi return 0 tidak dilaksanakan.
Pelaksanaan progam berlanjut ke baris 39 dan kemudian melaksanakan for loop dari baris 40 s/d 42 sehingga pada layar komputer ditampilkan tulisan:
No. Transaksi Nilai
0. 20
1. 10
2. 30
3. 40
REFERENSI:
[SHT00] Victor Shtern. 2000. Core C++: A Software Engineering Approach. Prentice Hall.
0 komentar:
Posting Komentar