Setelah sebuah variabel struct dideklarasikan dan diisi, kita perlu membaca atau menulis nilai tiap member. Di C terdapat dua operator khusus untuk hal tersebut: operator titik (.) dipakai saat kita memiliki variabel struct langsung, dan operator panah (->) dipakai saat kita memiliki pointer ke struct. Pemilihan operator bukan gaya—keduanya tidak saling menggantikan, dan memakai operator yang salah akan memicu compile error. Pada chapter ini kita akan menelusuri kapan memakai . dan kapan memakai ->, serta mengapa pola pointer sangat penting saat ingin memodifikasi struct dari dalam fungsi.
Operator Titik (.) untuk Akses Langsung #
Operator titik dipakai ketika kita memiliki variabel struct itu sendiri (bukan pointer). Sintaksnya: nama_variabel.nama_member. Operator ini mengakses member pada offset yang sesuai dari alamat awal variabel. Untuk variabel lokal, akses langsung lewat . adalah cara tercepat dan paling alami.
Mekanisme kerja operator titik: ketika compiler melihat mhs.umur, compiler menghitung alamat member umur sebagai &mhs + offset_umur, lalu membaca atau menulis pada alamat tersebut. Karena offset ditentukan saat kompilasi, tidak ada overhead runtime.
#include <stdio.h>
#include <string.h>
struct Mahasiswa {
char nama[50];
int umur;
float ipk;
};
/* Fungsi yang menerima struct by value */
void cetak_langsung(struct Mahasiswa m) {
printf("[by value] %s, umur %d, IPK %.2f\n", m.nama, m.umur, m.ipk);
}
/* Fungsi yang menerima pointer ke struct */
void cetak_pointer(const struct Mahasiswa *m) {
/* Akses member via operator arrow */
printf("[by pointer] %s, umur %d, IPK %.2f\n", m->nama, m->umur, m->ipk);
}
/* Fungsi yang mengubah member via pointer */
void ulang_tahun(struct Mahasiswa *m) {
m->umur += 1;
}
int main(void) {
struct Mahasiswa mhs = {"Budi Santoso", 20, 3.60f};
/* Akses langsung pakai operator titik */
printf("Nama : %s\n", mhs.nama);
printf("Umur : %d\n", mhs.umur);
printf("IPK : %.2f\n", mhs.ipk);
/* Modifikasi member langsung */
mhs.ipk = 3.75f;
printf("IPK baru: %.2f\n", mhs.ipk);
/* Pass ke fungsi: by value */
cetak_langsung(mhs);
/* Pass ke fungsi: by pointer */
cetak_pointer(&mhs);
/* Modifikasi via pointer */
ulang_tahun(&mhs);
printf("Setelah ulang tahun: umur %d\n", mhs.umur);
return 0;
}Output yang Dihasilkan:
Nama : Budi Santoso
Umur : 20
IPK : 3.60
IPK baru: 3.75
[by value] Budi Santoso, umur 20, IPK 3.75
[by pointer] Budi Santoso, umur 20, IPK 3.75
Setelah ulang tahun: umur 21Mari kita telaah baris-baris kode di atas:
- Baris 14-16 (
cetak_langsung(struct Mahasiswa m)): fungsi menerimastructby value. Seluruh isistructdisalin ke parameter lokalm. Di dalam fungsi, kita pakai operator titik (m.nama) karenamadalah variabelstruct, bukan pointer. - Baris 20-22 (
cetak_pointer(const struct Mahasiswa *m)): fungsi menerima pointer ke struct bertipeconst. Di dalam fungsi, kita pakai operator panah (m->nama) karenamadalah pointer. Kata kunciconstmenjamin fungsi tidak akan memodifikasistructyang ditunjuk. - Baris 26-28 (
ulang_tahun(struct Mahasiswa *m)): menerima pointer non-const. Fungsi menambahm->umurlewat operator panah. Karena yang ditunjuk adalah variabelmhsdimain, perubahan ini terlihat setelah pemanggilan. - Baris 35 (
printf("Nama : %s\n", mhs.nama);): akses membernamalewat operator titik karenamhsvariabel langsung. - Baris 41 (
cetak_pointer(&mhs);): mengoper alamatmhs(&mhs) ke fungsi yang menerima pointer. - Baris 44 (
ulang_tahun(&mhs);): pointer&mhsmembuat fungsiulang_tahunbisa mengubahmhs.umurdari dalam fungsi—sesuatu yang tidak mungkin jika kita mengoperstructby value.
Operator Panah (->) untuk Akses via Pointer #
Operator panah adalah singkatan dari kombinasi dereference dan akses member. Ekspresi ptr->member sepenuhnya setara dengan (*ptr).member. Operator panah hadir agar kita tidak perlu menulis tanda kurung yang berantakan; *ptr.member memiliki arti berbeda (akan mencoba dereference hasil ptr.member, yang biasanya tidak valid).
#include <stdio.h>
struct Titik {
int x;
int y;
};
int main(void) {
struct Titik p = {3, 4};
struct Titik *ptr = &p; /* ptr menunjuk ke p */
/* Tiga cara ekivalen untuk membaca member y */
printf("p.y = %d\n", p.y);
printf("(*ptr).y = %d\n", (*ptr).y);
printf("ptr->y = %d\n", ptr->y);
/* Tiga cara ekivalen untuk menulis member x */
p.x = 10;
(*ptr).x = 20;
ptr->x = 30;
printf("Setelah modifikasi: p.x = %d, p.y = %d\n", p.x, p.y);
return 0;
}Output yang Dihasilkan:
p.y = 4
(*ptr).y = 4
ptr->y = 4
Setelah modifikasi: p.x = 30, p.y = 4Pada contoh di atas, p.y, (*ptr).y, dan ptr->y menghasilkan nilai yang sama persis karena ptr memang menunjuk ke p. Hal yang sama berlaku untuk penulisan: tiga assignment terakhir (p.x = 10; (*ptr).x = 20; ptr->x = 30;) semua menulis ke p.x. Karena eksekusi berurutan dari atas ke bawah, nilai akhir p.x adalah 30—nilai dari penulisan terakhir.