Modul 4: Pointer dan Struct - dimasandhk/praktikum-atp-2024 GitHub Wiki
Setiap variabel, fungsi, struct, ataupun objek lain yang dibuat dalam program mempunyai lokasi masing-masing pada memori. Alokasi setiap variabel disimpan dalam alamat memori tertentu.
Misalnya:
Terdapat variabel bernama var
. Untuk mengetahui alamat memori dari variabel, digunakan operator address-of (&) di depan nama variabelnya.
int var = 5;
printf("%d\n", var);
printf("%p\n", &var);
Output:
5
0x7fffdeb3ed84
Output bisa berbeda-beda di tiap eksekusi.
0x7fffdeb3ed84 merupakan alamat memori dari variabel var
.
Pointer adalah variabel spesial yang menampung alamat memori, bukan nilai seperti variabel biasa.
Deklarasi variabel pointer menggunakan operator *
di antara tipe data dan nama variabelnya.
int *ptr;
atau
int* ptr;
Kedua cara deklarasi di atas merupakan sintaks yang valid.
Variabel ptr
di atas adalah variabel pointer yang bertipe int. Variabel pointer menampung alamat memori. Inisialisasi variabel pointer harus berupa alamat memori, bisa dari variabel lain atau alokasi secara dinamis.
int var = 55;
int *ptr = &var; // Inisialisasi menggunakan alamat dari var
Inisialisasi yang tidak sesuai akan menghasilkan error atau undefined behaviour.
// ERROR
int *ptr = 5;
// UNDEFINED BEHAVIOUR
int *ptr2 = 0x7fffdeb3ed84;
Cara melakukan assignment pada variabel pointer tidak sama dengan inisialisasinya.
int var, *ptr;
var = 55;
ptr = &var; // Assignment pada variabel pointer menggunakan alamat dari var
Assignment tidak perlu menggunakan simbol * di depan nama variabelnya. Berbeda pada saat deklarasi yang mana kita perlu memberitahu compiler bahwa variabel tersebut adalah variabel pointer.
Operator dereference menggunakan simbol yang sama dengan simbol operator perkalian, yakni * (simbol asterisk). Namun, fungsinya sangat berbeda. Operator dereference digunakan untuk mengakses nilai yang ditunjuk (pointed) dari sebuah variabel pointer.
Untuk mengakses nilai dari sebuah variabel pointer, digunakan operator dereference di depan nama variabel pointer.
int var = 55;
int *ptr = &var;
printf("%d\n", *ptr);
*ptr = 20;
printf("%d\n", *ptr);
printf("%d\n", var);
Output
55
20
20
Apa output dari program di bawah ini?
#include <stdio.h>
int main(void)
{
int x, y, z;
int *ptr1, *ptr2;
x = 5;
y = 6;
ptr1 = &x;
ptr2 = &y;
z = *ptr1 + *ptr2;
printf("%d\n", z);
return 0;
}
Variabel pointer juga dapat menunjuk variabel pointer lainnya. Hal ini disebut dengan double pointer (pointer to pointer). Untuk mendeklarasikan variabel double pointer, digunakan dua simbol *. Kegunaan paling umum dari variabel double pointer adalah untuk membuat array dua dimensi secara dinamis.
int **dbPtr;
Variabel dbPtr
di atas menyimpan alamat memori dari variabel pointer lainnya.
#include <stdio.h>
int main(void)
{
int var = 23;
int *ptr = &var;
int **dbPtr = &ptr;
printf("%d\n", **dbPtr);
return 0;
}
Kita sudah mengetahui bahwa array adalah kumpulan data yang disusun secara sekuensial. Karena disusun secara sekuensial, alamat-alamat memori tiap elemen array juga tersusun secara berurutan.
Bagaimana jika kita ingin mengetahui alamat memori dari array?
#include <stdio.h>
int main()
{
int arr[5] = {1, 2, 3, 4, 5};
int i;
for (i = 0; i < 5; ++i) {
printf("&arr[%d] => %p\n", i, &arr[i]);
}
printf("Address of arr => %p\n", arr);
return 0;
}
Output
&arr[0] => 0x7fffe85f0520
&arr[1] => 0x7fffe85f0524
&arr[2] => 0x7fffe85f0528
&arr[3] => 0x7fffe85f052c
&arr[4] => 0x7fffe85f0530
Address of arr => 0x7fffe85f0520
Dapat diperhatikan bahwa alamat dari &arr[0]
sama dengan alamat dari arr
. Dari hal ini dapat diketahui bahwa nama array menunjuk ke elemen pertama dari array tersebut. Karena &arr[0]
= arr
, maka dapat disimpulkan bahwa arr[0]
= *arr
, atau nilai dari elemen pertama dapat diakses dengan *arr
atau *(arr + 0)
.
arr[0] = *(arr + 0)
arr[1] = *(arr + 1)
arr[2] = *(arr + 2)
.
.
dst
Kesimpulan: Nama array merujuk pada alamat memori dari elemen pertama pada array. Berbekal dari hal tersebut, maka kita dapat melakukan hal demikian.
#include <stdio.h>
int main()
{
int arr[5] = {1, 2, 3, 4, 5}, i;
int *ptr = arr;
for (i = 0; i < 5; ++i) {
printf("%d ", *(ptr+i));
}
return 0;
}
Output
1 2 3 4 5
Dalam bahasa C, malloc
(memory allocation) adalah fungsi yang digunakan untuk mengalokasikan memori secara dinamis selama runtime. Fungsi ini memungkinkan kita untuk meminta alokasi memori dengan ukuran tertentu dan mengembalikan pointer ke awal blok memori yang baru dialokasikan. Memori yang dialokasikan dengan malloc
berada di area memori yang disebut heap, bukan di stack.
Untuk array, malloc
memungkinkan kita menentukan ukuran array pada saat runtime, alih-alih menentukan ukuran secara statis di awal program. malloc
mengalokasikan memori dalam bentuk blok memori kosong yang dapat diisi dengan tipe data apa pun.
Fungsi malloc
membutuhkan jumlah byte yang akan dialokasikan, dan mengembalikan pointer ke blok memori yang dialokasikan. Biasanya, kita menggunakan operator sizeof
untuk menentukan jumlah byte yang diperlukan untuk tipe data tertentu.
Sintaks umum untuk menggunakan malloc
dalam pembuatan array adalah sebagai berikut, dan int
bisa diganti dengan tipe data apapun yang diinginkan:
int *array = malloc(n * sizeof(int));
Sebelumnya kita sudah mengetahui bahwa fungsi dapat menerima parameter sebagai input. Penggunaan-penggunaan parameter fungsi selama ini sebenarnya menggunakan konsep pass by value. Selain menggunakan cara itu, terdapat cara lain untuk passing argumen pada fungsi.
Pass by Value berarti saat kita memasukkan (passing) argumen pada fungsi, nilai dari argumen tersebut akan disalin ke variabel yang berada pada parameter fungsi. Karena hanya nilainya saja yang diterima oleh fungsi, perubahan yang terjadi pada variabel parameter fungsi tidak akan berpengaruh terhadap variabel asalnya.
Contoh:
#include <stdio.h>
void change(int a, int b)
{
a = a + 5;
b = b + 5;
}
int main()
{
int x = 10, y = 6;
change(x, y);
printf("%d %d\n", x, y);
return 0;
}
Nilai pada variabel x
dan y
tidak berubah karena metode passing yang digunakan adalah Pass by Value.
Berbeda dengan sebelumnya, sesuai namanya, metode Pass by Address berarti argumen yang dimasukkan (passing) ke parameter fungsi adalah alamat memori variabel. Segala perubahan yang terjadi pada variabel tersebut, juga mempengaruhi langsung ke variabel asalnya. Hal ini terjadi karena argumennya adalah langsung berupa alamat memorinya.
#include <stdio.h>
void change(int *a, int *b)
{
*a = *a + 5;
*b = *b + 5;
}
int main()
{
int x = 10, y = 6;
change(&x, &y);
printf("%d %d\n", x, y);
return 0;
}
Karena parameternya menerima alamat memori, maka variabel parameternya harus berupa pointer.
Passing array sebagai parameter fungsi juga dapat dilakukan dengan pointer. Segala perubahan pada array akan berpengaruh pada array asalnya.
#include <stdio.h>
void printArr(int *arr)
{
// ...
// ...
}
int main()
{
int num[5] = {1, 2, 3, 4, 5}, i;
printArr(num);
// ...
// ...
return 0;
}
Dalam bahasa C, struct adalah salah satu tipe data turunan atau bisa disebut juga user defined data type yang dapat mengelompokkan beberapa variabel di bawah satu nama. Tidak seperti array yang hanya dapat menyimpan elemen dengan tipe data sama, struct dapat mengelompokkan elemen dengan tipe data yang berbeda-beda.
Contoh:
Perhatikan gambar di atas. Mahasiswa merupakan suatu entitas yang di dalamnya terdapat atribut-atribut berupa:
- Nama
- NRP
- Umur
- IPK
- Semester
- Status
Atribut-atribut inilah yang nantinya berperan sebagai member dari struct Mahasiswa
.
Seperti variabel, struct harus dideklarasikan terlebih dahulu sebelum bisa digunakan. Pendeklarasian struct menggunakan sintaks sebagai berikut.
struct <nama_struct> {
<tipe_data_member> <nama_member>;
<tipe_data_member> <nama_member>;
<tipe_data_member> <nama_member>;
.
.
.
};
Berikut adalah contoh deklarasi struct berdasarkan kasus Mahasiswa di atas.
struct Mahasiswa {
char nama[100];
char nrp[20];
int umur;
double ipk;
int semester;
int status;
};
Setelah dideklarasikan, sebuah struct akan menjadi tipe data baru. Maka dalam kasus ini, struct Mahasiswa
di sini menjadi tipe data baru dengan member-member berupa nama
, nrp
, umur
, ipk
, semester
, dan status
. Untuk membuat variabel dengan tipe data struct, dilakukan dengan sintaks berikut.
struct <nama_struct> <nama_variabel>;
Contoh:
struct Mahasiswa mhs1;
struct Mahasiswa mhs2;
Contoh di atas menunjukkan terdapat dua variabel mhs1
dan mhs2
bertipe struct Mahasiswa
.
Lalu bagaimana cara untuk mengakses member dari variabel struct yang telah dibuat? Untuk mengakses member-member dari struct, digunakan operator dot (.) setelah nama variabelnya.
<nama_variabel>.<member_struct>
Contoh:
mhs1.umur = 19;
mhs1.semester = 3;
mhs2.umur = 20;
mhs2.semester = 5;
Contoh program untuk mendemonstrasikan Struct:
#include <stdio.h>
#include <string.h>
struct Mahasiswa {
char nama[100];
char nrp[20];
int umur;
double ipk;
int semester;
int status;
};
int main(void)
{
struct Mahasiswa mhs1;
strcpy(mhs1.nama, "Ahmad");
strcpy(mhs1.nrp, "05111940000012");
mhs1.umur = 18;
mhs1.ipk = 3.94;
mhs1.semester = 3;
mhs1.status = 1;
printf("Nama\t: %s\n", mhs1.nama);
printf("NRP\t: %s\n", mhs1.nrp);
printf("Umur\t: %d\n", mhs1.umur);
printf("IPK\t: %.2lf\n", mhs1.ipk);
printf("Sem\t: %d\n", mhs1.semester);
printf("Status\t: %s\n", (mhs1.status == 1 ? "Aktif" : "Tidak Aktif"));
return 0;
}
Kita juga dapat membuat array dengan tipe data struct. Caranya sama persis dengan deklarasi array pada umumnya.
#include <stdio.h>
struct Point {
int x, y;
};
int main()
{
struct Point arr[3];
arr[0].x = 2, arr[0].y = 3;
arr[1].x = 5, arr[1].y = 3;
arr[2].x = 2, arr[2].y = 8;
printf("%d %d\n", arr[0].x, arr[0].y);
printf("%d %d\n", arr[1].x, arr[1].y);
printf("%d %d\n", arr[2].x, arr[2].y);
return 0;
}
Reynold adalah salah satu peserta kontes porgramming. Dia ingin mengetahui apakah scorenya sudah diatas peserta yang lain. Bantulah Reynold menemukan nilai dari seluruh pemain dan tentukan apakah nilai Reynold lebih dari atau sama dengan nilai pemain tertinggi
Input Format:
n m
name1 soal1 score1
name2 soal2 score2
.
.
namen soaln scoren
- n adalah banyak data yang akan dimasukkan
- m adalah total nilai yang dimiliki Reynold
- name ke n adalah nama peserta
- soal ke n adalah soal yang dikerjakan, peserta hanya bisa mengerjakan satu kali untuk setiap soal
- score ke n adalah score yang didapatkan peserta pada soal tersebut
Constraints:
- 0 < n < 100
- Agar memudahkan input soal, maka name hanya terdiri dari satu string tanpa spasi
- Soal terdiri dari satu huruf
- 0 < score < 1000
Output-nya:
- Jika total nilai Reynold lebih dari atau sama dengan nilai tertinggi peserta lain
YES MENANG
- Jika tidak
NICE TRY
Sample Input
7 330
Amoes C 100
Rafi C 90
Haidar A 90
Rafi B 50
Amoes E 100
Haidar C 100
Haidar D 100
Sample Output
YES MENANG
Buatlah struct untuk menyimpan data nilai UN mahasiswa yang berisi nama, nilai Matematika, nilai IPA, nilai Bahasa Indonesia, dan nilai Bahasa Inggris. Setelah itu buat program yang dapat memasukkan list data nilai UN lalu menampilkan data sesuai nama.
Keterangan: urutan pemasukan nilai adalah Matematika, IPA, Bahasa Indonesia, Bahasa Inggris. Berikut merupakan contoh input dan output. 4 kelompok data di awal merupakan jumlah data nilai UN yang akan dimasukkan. Angka 3 di akhir merupakan jumlah nama yang akan dicari.
Sample Input
4
Hope
100
90
20
90
Ricky
80
70
80
90
Maden
100
100
100
100
Tenten
90
80
99
100
3
Maden
Dennis
Tenten
Sample Output
Nilai Maden
Matematika : 100
IPA : 100
Bahasa Indonesia : 100
Bahasa Inggris : 100
Nilai Dennis tidak ditemukan
Nilai Tenten
Matematika : 90
IPA : 80
Bahasa Indonesia : 99
Bahasa Inggris : 100
Buatlah fungsi bernama reverse() untuk me-reverse array of integer menggunakan pointer. Fungsinya dapat digunakan seperti berikut.
int arr[5]
.
.
//input
reverse(arr, 5);
.
.
//print isi arr
Sample Input:
5
8 4 2 3 1
Sample Output:
1 3 2 4 8