Dasar struct

Mendefinisikan dan mendeklarasikan struct, operator titik, serta pengantar memory padding.

Daftar isi

Data satu siswa, satu tanggal, atau satu titik koordinat biasanya terdiri atas beberapa nilai yang saling berkaitan. struct mengelompokkan beberapa variabel dengan tipe yang berbeda maupun sama menjadi satu kesatuan bernama. Topik ini membahas cara mendefinisikan struct, mendeklarasikan variabelnya, dan mengakses anggota dengan operator titik. Bagian akhir mengenalkan memory padding, yaitu penyebab ukuran struct sering lebih besar daripada penjumlahan anggotanya.

Mendefinisikan struct#

Definisi struct dimulai dengan kata kunci struct, diikuti nama tag, daftar anggota di dalam kurung kurawal, dan tanda titik koma di akhir. Setiap anggota ditulis sebagaimana deklarasi variabel biasa, lengkap dengan tipenya. Definisi hanya mendeskripsikan susunan anggota dan belum memesan memori, sehingga definisi biasanya ditempatkan di bagian atas berkas agar dapat digunakan oleh semua fungsi di dalamnya.

c Bentuk umum definisi struct
// tidak-dijalankan
struct NamaStruct {
    tipe anggota_pertama;
    tipe anggota_kedua;
};

Nama pada definisi di atas disebut tag, yaitu label yang mengidentifikasi struct tersebut. Tag inilah yang dipakai pada saat mendeklarasikan variabel dengan bentuk struct NamaStruct namaVariabel;. Kata kunci struct wajib menyertai setiap deklarasi karena tag belum menjadi tipe mandiri. Satu definisi boleh dimiliki banyak variabel, dan seluruh variabel itu menyusun anggotanya dengan pola yang sama.

Tipe anggota tidak dibatasi pada tipe dasar. Array, pointer, dan struct lain boleh menjadi anggota, sehingga data yang berlapis dapat disusun bertingkat.

c Struct dengan anggota bertipe struct lain
// tidak-dijalankan
struct Acara {
    struct Tanggal mulai;
    struct Tanggal selesai;
    char tempat[32];
};

Definisi struct Acara di atas harus diletakkan setelah definisi struct Tanggal yang menjadi tipenya, karena kompiler membaca berkas dari atas ke bawah. Anggota bertingkat diakses dengan operator titik yang disambung berurutan, misalnya acara.mulai.tahun untuk membaca tahun tanggal mulai. Prinsip yang sama berlaku berapa pun tingkat penulisannya, dan setiap sambungan titik menunjuk satu anggota pada tingkatnya.

Deklarasi variabel dan operator titik#

Variabel struct dideklarasikan dengan menuliskan struct, tag, lalu nama variabelnya, sebagaimana pendeklarasian tipe lain. Nilai awal dapat diberikan sekaligus menggunakan kurung kurawal, dan urutan nilainya mengikuti urutan anggota pada definisi. Anggota individual diakses menggunakan operator titik (.) yang disisipkan antara nama variabel dan nama anggotanya, baik untuk membaca maupun untuk menulis nilai. Variabel yang tidak diberi nilai awal berisi sisa data memori sebelumnya, sehingga setiap anggota yang diperlukan sebaiknya diisi terlebih dahulu sebelum dibaca.

Program berikut mendefinisikan struct Tanggal, mendeklarasikan dua variabelnya, lalu mengisi dan membaca anggotanya.

c tanggal.c
#include <stdio.h>

struct Tanggal {
    int hari;
    int bulan;
    int tahun;
};

int main(void) {
    struct Tanggal upacara;
    struct Tanggal libur = {17, 8, 2026};

    upacara.hari = 1;
    upacara.bulan = 10;
    upacara.tahun = 2026;

    printf("Upacara : %d/%d/%d\n", upacara.hari, upacara.bulan, upacara.tahun);
    printf("Libur   : %d/%d/%d\n", libur.hari, libur.bulan, libur.tahun);

    struct Tanggal salin = libur;
    salin.hari = 18;
    printf("Salin   : %d/%d/%d\n", salin.hari, salin.bulan, salin.tahun);
    printf("Libur   : %d/%d/%d\n", libur.hari, libur.bulan, libur.tahun);

    return 0;
}
text Keluaran
Upacara : 1/10/2026
Libur   : 17/8/2026
Salin   : 18/8/2026
Libur   : 17/8/2026

Baris struct Tanggal salin = libur; memperlihatkan sifat penting struct. Penugasan satu variabel struct ke variabel lain menyalin seluruh anggotanya sekaligus. Setelah salin.hari diubah menjadi 18, variabel libur tetap menampilkan tanggal 17. Kedua variabel kini menyimpan data yang berdiri sendiri, sehingga perubahan pada salah satunya tidak memengaruhi yang lain.

Ukuran struct dan memory padding#

Ukuran sebuah struct tidak selalu sama dengan penjumlahan ukuran anggotanya. Kompilator menyisipkan byte pengisi yang disebut memory padding di antara anggota agar setiap anggota menempati alamat yang memenuhi kebutuhan perataan (alignment) tipenya. Pada Linux x86-64, anggota bertipe int ditempatkan pada alamat kelipatan 4 dan double pada kelipatan 8, sehingga ruang kosong muncul apabila urutan anggota meninggalkan celah.

Program berikut membandingkan dua struct yang anggotanya sama tetapi urutannya berbeda.

c padding.c
#include <stdio.h>

struct Rapat {
    char a;
    int b;
    char c;
};

struct Sekat {
    char a;
    char c;
    int b;
};

int main(void) {
    printf("sizeof(char)          = %zu\n", sizeof(char));
    printf("sizeof(int)           = %zu\n", sizeof(int));
    printf("sizeof(struct Rapat)  = %zu\n", sizeof(struct Rapat));
    printf("sizeof(struct Sekat)  = %zu\n", sizeof(struct Sekat));

    return 0;
}
text Keluaran
sizeof(char)          = 1
sizeof(int)           = 4
sizeof(struct Rapat)  = 12
sizeof(struct Sekat)  = 8

Struct Rapat memuat char (1 byte), int (4 byte), dan char (1 byte) dengan total isi 6 byte, tetapi sizeof melaporkan 12 byte. Anggota a menempati offset 0, dan tiga byte padding mengikutinya di offset 1 sampai 3. Anggota b menempati offset 4 sampai 7, sedangkan anggota c menempati offset 8. Dua byte padding menutup struct di offset 9 sampai 11 agar ukuran totalnya menjadi kelipatan 4. Diagram berikut menggambarkan tata letak tersebut.

struct Rapat12 byteabcpaddingpaddingoffset 04812anggotapadding6 byte isi, 6 byte padding
Tata letak memori struct Rapat berukuran 12 byte

Struct Sekat menyusun anggota yang sama dengan urutan berbeda dan menghasilkan 8 byte. Dua anggota char berdampingan di offset 0 dan 1, dua byte padding mengikuti, lalu int menempati offset 4 sampai 7. Bahasa C mempertahankan urutan anggota sesuai deklarasinya dan tidak menyusunnya ulang. Karena itu, mengelompokkan anggota bertipe kecil agar berdampingan merupakan cara manual yang efektif untuk mengurangi padding.

Kesalahan umum#

Tanda titik koma setelah kurung kurawal penutup definisi struct wajib ditulis. Apabila tanda itu terlupa, error justru muncul pada baris berikutnya yang tampak tidak bersalahkan, sehingga letak kesalahannya mudah diduga keliru. Kebiasaan yang mencegahnya adalah menuliskan }; sebagai satu kesatuan setiap kali definisi struct selesai.

Kekeliruan kedua adalah menganggap sizeof(struct) selalu sama dengan penjumlahan ukuran anggotanya. Perhitungan manual semacam itu mengabaikan padding, sehingga hasilnya tidak cocok dengan keluaran program. Gunakan sizeof langsung terhadap tipenya setiap kali ukuran diperlukan, misalnya saat menghitung jumlah elemen array atau memesan memori.

Ringkasan#

  • Definisi struct membuat tipe baru yang anggotanya tersusun berurutan, sedangkan memori baru dipesan ketika variabelnya dideklarasikan.
  • Operator titik (.) membaca dan menulis satu anggota, dan penugasan antarvariabel struct menyalin seluruh anggotanya sekaligus.
  • Kompilator menyisipkan memory padding agar setiap anggota menempati alamat yang memenuhi aturan perataan tipenya.
  • Urutan anggota memengaruhi ukuran struct, dan sizeof terhadap tipe tetap menjadi cara yang andal untuk mengetahuinya.

Referensi#