Menu

Struct di C: Mendefinisikan, Menginisialisasi, dan Memakai Struktur

Cara mengelompokkan nilai-nilai yang saling berkaitan menjadi satu tipe dengan struct di C: mendeklarasikannya, mengakses anggota dengan operator titik, designated initializer, array struct, struct bersarang, dan aturan salin-saat-dikirim yang mengejutkan semua orang.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Array menampung banyak nilai dengan satu tipe. struct melakukan kebalikannya: menampung beberapa nilai dengan tipe berbeda dan memperlakukannya sebagai satu kesatuan. Sebuah titik adalah x dan y. Seorang karyawan adalah nama, id, dan gaji. Tanpa struct, kamu harus membawa semua itu sebagai tiga variabel lepas dan berharap tidak pernah tertukar gaji siapa milik siapa.

Mendeklarasikan Tipe Struct

Deklarasi struct memberi nama sebuah tag dan mendaftar anggotanya di dalam kurung kurawal:

struct Point {
    int x;
    int y;
};

Titik koma setelah kurung kurawal penutup itu wajib. Lupa menulisnya menghasilkan salah satu pesan error paling membingungkan yang akan ditemui pemula C, karena compiler menyalahkan baris berikutnya.

Kode ini mendeklarasikan sebuah tipe, bukan variabel. Di C, nama lengkap tipenya adalah struct Point, termasuk kata kuncinya:

Anggota dibaca dan ditulis dengan operator titik, p.x. Variabel struct adalah variabel biasa: tinggal di stack, bisa di-assign ke struct lain bertipe sama dengan =, dan lenyap di akhir scope-nya.

Menulis struct Point di mana-mana cukup melelahkan, dan karena itulah hampir semua kode C sungguhan membungkus deklarasinya dengan typedef supaya tipenya cukup ditulis Point.

Menginisialisasi Struct

Kamu bisa mengisi struct tepat saat mendeklarasikannya. Bentuk posisional mendaftar nilai sesuai urutan deklarasi:

struct Point p = {3, 4};   // x = 3, y = 4

Designated initializer menyebut nama setiap anggota, sehingga lebih jelas dan lebih aman:

Tiga hal yang perlu diperhatikan:

  • Bentuk designated bisa mendaftar anggota dengan urutan apa pun, jadi menambah atau mengubah urutan anggota nanti tidak akan diam-diam menggeser nilai ke tempat yang salah.
  • Anggota yang tidak kamu sebut akan diinisialisasi dengan nol. {0} adalah cara idiomatis untuk mengisi seluruh struct dengan nol.
  • Anggota char name[32] adalah array sungguhan di dalam struct, jadi string-nya tersimpan di dalam struct itu sendiri, bukan di tempat lain. Itu juga berarti a.name = "Ada"; setelahnya tidak sah; kamu butuh strcpy (lihat fungsi string).

Struct tanpa inisialisasi berarti belum diinisialisasi, dan membaca anggotanya sebelum menulisnya adalah undefined behavior. = {0} tidak memakan biaya dan menghilangkan seluruh jenis bug itu.

Assignment dan Perbandingan

Assignment struct menyalin setiap anggota:

a tidak tersentuh: b mendapat salinannya sendiri. Tetapi perhatikan apa yang tidak diberikan C: tidak ada == untuk struct. if (a == b) tidak akan bisa di-compile. Membandingkan berarti membandingkan anggota-anggotanya:

if (a.x == b.x && a.y == b.y) { /* equal */ }

Jangan memakai memcmp sebagai jalan pintas. Compiler menyisipkan byte padding yang tidak terlihat di antara anggota demi alignment, dan byte itu bisa berisi nilai sampah, sehingga dua struct dengan anggota yang identik bisa dianggap berbeda jika dibandingkan byte per byte.

Array Struct

Karena struct adalah tipe seperti yang lain, kamu bisa membuat array darinya. Ini cara standar untuk menyimpan tabel berisi record.

staff[i].salary dibaca "elemen i, lalu anggota salary-nya". Pengindeksan mengikat lebih kuat daripada titik, jadi tidak perlu tanda kurung.

Struct Disalin Saat Dikirim ke Fungsi

Inilah aturan yang menjebak banyak orang. Saat kamu mengirim struct ke fungsi, C menyalinnya. Fungsi itu bekerja pada salinan pribadinya sendiri:

p tetap (3, 4). Membaca struct sebagai nilai, seperti yang dilakukan distance_from_origin, sama sekali tidak masalah dan sering menjadi pilihan paling jelas untuk struct kecil. Tetapi jika fungsinya harus mengubah struct milik pemanggil, atau jika struct-nya cukup besar sehingga menyalinnya jadi boros, kirim pointer. Itulah topik halaman struct dan pointer.

Mengembalikan struct sebagai nilai bekerja dengan cara yang sama dan sepenuhnya sah:

struct Point make_point(int x, int y) {
    struct Point p = {x, y};
    return p;
}

Struct Bersarang

Anggota struct bisa berupa struct juga. Rangkai titiknya untuk masuk ke dalam:

b.published.year masuk satu tingkat demi satu tingkat. Struct bersarang adalah cara membangun model data sungguhan di C. Struct bagian dalam disimpan di dalam struct luarnya, bukan ditunjuk, jadi seluruh Book adalah satu blok memori yang bersambung.

Ukuran, Padding, dan Urutan Anggota

sizeof memberitahumu seberapa besar sebuah struct, dan jawabannya sering lebih besar daripada jumlah ukuran anggotanya:

Di mesin pada umumnya, Wasteful berukuran 12 byte dan Tidy 8 byte, walaupun keduanya berisi tiga anggota yang sama. Compiler menyisipkan padding supaya setiap anggota berada di alamat yang disukai tipenya; sebuah int biasanya ingin kelipatan 4. Menaruh anggota yang lebih besar sebelum yang lebih kecil cenderung menghasilkan susunan yang lebih rapat.

Ini jarang penting (array berisi sejuta elemen, tata letak paket jaringan) dan tidak pernah memengaruhi kebenaran kodemu sendiri. Yang dijelaskannya adalah kenapa sizeof bisa mengejutkan, dan kenapa memcmp pada struct adalah ide yang buruk.

Pertanyaan yang sering diajukan

Bagaimana cara mendeklarasikan struct di C?

Tulis struct diikuti nama tag dan daftar anggota di dalam kurung kurawal: struct Point { int x; int y; };. Itu mendeklarasikan sebuah tipe, bukan variabel. Untuk membuat variabel, kamu lalu menulis struct Point p;. Kata struct adalah bagian dari nama tipenya di C, dan karena itulah kebanyakan kode memasangkannya dengan typedef.

Apa perbedaan . dan -> pada struct?

Pakai . jika kamu memegang struct-nya langsung (p.x) dan -> jika kamu memegang pointer ke struct itu (ptr->x). Operator panah adalah singkatan dari (*ptr).x. Lihat struct dan pointer untuk detailnya.

Apakah struct dikirim sebagai nilai atau sebagai referensi di C?

Selalu sebagai nilai. Mengirim struct ke fungsi akan menyalin setiap anggotanya, jadi perubahan di dalam fungsi tidak memengaruhi variabel milik pemanggil. Untuk mengubah aslinya, atau untuk menghindari penyalinan struct yang besar, kirim pointer.

Bagaimana cara menginisialisasi struct di C?

Bisa berdasarkan posisi, struct Point p = {3, 4};, atau dengan designated initializer, struct Point p = {.y = 4, .x = 3};. Bentuk designated menyebut nama setiap anggota, jadi tetap benar walaupun nanti ada yang mengubah urutan struct-nya, dan anggota yang tidak disebut akan diisi nol.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai