1. Pengenalan C

C adalah bahasa pemrograman prosedural yang dikembangkan oleh Dennis Ritchie antara tahun 1969-1973 di Bell Labs. C awalnya dikembangkan untuk menulis ulang sistem operasi UNIX.

Karakteristik Utama C:

  • Prosedural - Berbasis fungsi dan prosedur
  • Mid-level - Kombinasi high-level dan low-level
  • Static typing - Tipe data ditentukan saat kompilasi
  • Manual memory management - Programmer mengelola memory sendiri
  • Portable - Program C bisa dijalankan di berbagai platform
  • Fast - Sangat cepat karena dekat dengan hardware
Tahukah kamu? Sistem operasi seperti Linux, Windows, macOS kernel-nya ditulis dalam C. Juga database seperti MySQL, PostgreSQL, dan Redis ditulis dalam C.
Contoh program pertama: hello.c
#include <stdio.h>

int main() {
    // Menampilkan teks ke console
    printf("Hello, World!\n");
    printf("Selamat belajar C!\n");
    
    return 0; // Menandakan program sukses
}
Tips: #include <stdio.h> digunakan untuk mengimpor library standard input-output. Fungsi printf() berasal dari library ini. \n adalah newline (pindah baris).

2. Instalasi & Compiler

Compiler C yang populer:

GCC (GNU Compiler Collection) - Standard di Linux/macOS
Clang - Compiler dari LLVM, cepat dan error message bagus
MinGW - GCC untuk Windows
Turbo C++ - Compiler lawas untuk DOS (tidak direkomendasikan)

Instalasi GCC di berbagai OS:

Linux (Ubuntu/Debian)
sudo apt update
sudo apt install build-essential
gcc --version  # Cek versi
macOS
xcode-select --install  # Install Command Line Tools
# atau via Homebrew
brew install gcc
Windows (MinGW)
1. Download MinGW dari https://sourceforge.net/projects/mingw/
2. Jalankan installer
3. Pilih mingw32-gcc-g++ dan mingw32-base
4. Tambahkan C:\MinGW\bin ke PATH environment

Cara kompilasi dan menjalankan:

Perintah dasar GCC
# Kompilasi program
gcc program.c -o program

# Jalankan program
./program  # Linux/macOS
program.exe  # Windows

# Kompilasi dengan warning lengkap
gcc -Wall -Wextra program.c -o program

# Kompilasi dengan optimasi
gcc -O2 program.c -o program

# Kompilasi dengan debug symbols
gcc -g program.c -o program

3. Sintaks Dasar

Aturan dasar penulisan C:

  • File C berekstensi .c
  • Entry point adalah fungsi main()
  • Setiap statement diakhiri dengan titik koma (;)
  • Blok kode menggunakan kurung kurawal { }
  • Komentar: // untuk single line (C99), /* */ untuk multi-line
  • Case-sensitive (huruf besar/kecil dibedakan)
  • Setiap program harus memiliki fungsi main()
Return value main: Fungsi main() biasanya mengembalikan int. return 0; menandakan program sukses, selain 0 menandakan error.
Struktur dasar program C
/*
    Ini komentar multi-line
    Bisa untuk deskripsi program
    Author: alzzdevmaret
*/

// Single line comment
#include <stdio.h>  // untuk printf, scanf
#include <stdlib.h> // untuk fungsi umum

#define PI 3.14159  // Mendefinisikan konstanta

// Fungsi main - entry point
int main() {
    // Deklarasi variabel
    int umur = 20;
    
    // Menampilkan output
    printf("Hello, World!\n");
    printf("Umur: %d\n", umur);
    
    return 0;  // Program sukses
}  // Akhir blok main

4. Variabel & Tipe Data

Tipe data dasar di C:

Tipe Format Specifier Ukuran Range
char%c1 byte-128 s/d 127 atau 0-255
unsigned char%c1 byte0 s/d 255
short%hd2 bytes-32,768 s/d 32,767
unsigned short%hu2 bytes0 s/d 65,535
int%d4 bytes-2,147,483,648 s/d 2,147,483,647
unsigned int%u4 bytes0 s/d 4,294,967,295
long%ld8 bytes-2^63 s/d 2^63-1
unsigned long%lu8 bytes0 s/d 2^64-1
float%f4 bytes1.2E-38 s/d 3.4E+38
double%lf8 bytes2.3E-308 s/d 1.7E+308

Aturan penamaan variabel:

  • Bisa huruf, angka, underscore (_)
  • Tidak boleh diawali angka
  • Case-sensitive (umur != Umur)
  • Tidak boleh menggunakan keyword C (int, if, while, dll)
Contoh variabel dan tipe data
#include <stdio.h>

int main() {
    // Deklarasi dan inisialisasi variabel
    int umur = 20;
    float tinggi = 175.5;
    double pi = 3.14159265359;
    char grade = 'A';
    char nama[] = "Budi";  // Array of characters (string)
    
    // Menampilkan dengan format specifier
    printf("Umur: %d tahun\n", umur);
    printf("Tinggi: %.1f cm\n", tinggi);  // .1f = 1 desimal
    printf("Nilai pi: %.10lf\n", pi);     // .10lf = 10 desimal
    printf("Grade: %c\n", grade);
    printf("Nama: %s\n", nama);
    
    // Konstanta dengan const
    const int MAX_SISWA = 100;
    // MAX_SISWA = 200;  // ERROR! konstanta tidak bisa diubah
    
    // Multiple deklarasi
    int a, b, c;
    a = b = c = 10;
    
    // Inisialisasi langsung
    int x = 5, y = 10, z = 15;
    
    printf("x=%d, y=%d, z=%d\n", x, y, z);
    
    return 0;
}
Tips: Gunakan float untuk menghemat memory, double untuk presisi tinggi. Untuk integer, pilih tipe yang sesuai dengan range yang dibutuhkan.

5. Operator

Jenis-jenis operator di C:

Aritmatika

+ tambah - kurang * kali / bagi % modulus (sisa bagi)

Perbandingan

== sama dengan != tidak sama > lebih besar < lebih kecil >= lebih besar sama dengan <= lebih kecil sama dengan

Logika

&& AND || OR ! NOT

Penugasan

= assignment += a += b (a = a + b) -= a -= b *= a *= b /= a /= b %= a %= b

Increment/Decrement

++ increment (a++) -- decrement (a--)

Bitwise

& AND | OR ^ XOR ~ NOT << left shift >> right shift
Contoh operator
#include <stdio.h>

int main() {
    int a = 10, b = 3;
    
    // Aritmatika
    printf("a + b = %d\n", a + b);
    printf("a - b = %d\n", a - b);
    printf("a * b = %d\n", a * b);
    printf("a / b = %d\n", a / b);      // integer division = 3
    printf("a %% b = %d\n", a % b);     // modulus = 1
    
    // Perbandingan (menghasilkan 0 atau 1)
    printf("a == b? %d\n", a == b);
    printf("a != b? %d\n", a != b);
    printf("a > b? %d\n", a > b);
    
    // Logika
    int x = 1, y = 0;
    printf("x && y: %d\n", x && y);
    printf("x || y: %d\n", x || y);
    printf("!x: %d\n", !x);
    
    // Increment/Decrement
    int c = 5;
    printf("c = %d\n", c);
    printf("c++ = %d\n", c++);  // post-increment (tampilkan dulu, baru tambah)
    printf("setelah c++ = %d\n", c);
    
    int d = 5;
    printf("++d = %d\n", ++d);  // pre-increment (tambah dulu, baru tampilkan)
    
    // Operator penugasan
    int e = 10;
    e += 5;  // sama dengan e = e + 5
    printf("e += 5 = %d\n", e);
    
    e *= 2;
    printf("e *= 2 = %d\n", e);
    
    // Operator ternary (conditional)
    int umur = 18;
    char *status = (umur >= 17) ? "Boleh buat SIM" : "Belum boleh";
    printf("Status: %s\n", status);
    
    return 0;
}

6. Control Flow (Percabangan)

Struktur if-else:

if (kondisi) {
    // kode jika kondisi true
} else if (kondisi2) {
    // kode jika kondisi2 true
} else {
    // kode jika semua false
}

Struktur switch-case:

switch (ekspresi) {
    case nilai1:
        // kode
        break;
    case nilai2:
        // kode
        break;
    default:
        // kode default
}

Catatan: break penting untuk keluar dari switch. Tanpa break, akan lanjut ke case berikutnya (fall-through).

Contoh if-else dan switch
#include <stdio.h>

int main() {
    int nilai = 85;
    
    // if-else
    if (nilai >= 90) {
        printf("Grade A\n");
    } else if (nilai >= 80) {
        printf("Grade B\n");
    } else if (nilai >= 70) {
        printf("Grade C\n");
    } else if (nilai >= 60) {
        printf("Grade D\n");
    } else {
        printf("Grade E (Tidak lulus)\n");
    }
    
    // Nested if
    int umur = 20;
    int memilikiSIM = 1;  // 1 = true, 0 = false
    
    if (umur >= 17) {
        if (memilikiSIM) {
            printf("Boleh mengemudi\n");
        } else {
            printf("Boleh mengemudi tapi belum punya SIM\n");
        }
    } else {
        printf("Belum cukup umur untuk mengemudi\n");
    }
    
    // Switch case
    int hari = 3;
    
    switch (hari) {
        case 1:
            printf("Senin\n");
            break;
        case 2:
            printf("Selasa\n");
            break;
        case 3:
            printf("Rabu\n");
            break;
        case 4:
            printf("Kamis\n");
            break;
        case 5:
            printf("Jumat\n");
            break;
        case 6:
            printf("Sabtu\n");
            break;
        case 7:
            printf("Minggu\n");
            break;
        default:
            printf("Hari tidak valid\n");
    }
    
    // Contoh fall-through (tanpa break)
    int angka = 2;
    
    switch (angka) {
        case 1:
        case 2:
        case 3:
            printf("Angka antara 1-3\n");
            break;
        default:
            printf("Angka lain\n");
    }
    
    return 0;
}

7. Perulangan (Loops)

Jenis perulangan di C:

1. for loop

for (inisialisasi; kondisi; increment) {
    // kode
}

2. while loop

while (kondisi) {
    // kode
}

3. do-while loop

do {
    // kode (minimal dijalankan sekali)
} while (kondisi);

Kontrol loop:

  • break - keluar dari loop
  • continue - skip iterasi saat ini
Contoh perulangan
#include <stdio.h>

int main() {
    // 1. For loop
    printf("For loop: 1 s/d 5\n");
    for (int i = 1; i <= 5; i++) {
        printf("%d ", i);
    }
    printf("\n\n");
    
    // For loop dengan decrement
    printf("For loop mundur: 5 s/d 1\n");
    for (int i = 5; i >= 1; i--) {
        printf("%d ", i);
    }
    printf("\n\n");
    
    // 2. While loop
    printf("While loop:\n");
    int j = 1;
    while (j <= 5) {
        printf("%d ", j);
        j++;
    }
    printf("\n\n");
    
    // 3. Do-while loop
    printf("Do-while loop:\n");
    int k = 1;
    do {
        printf("%d ", k);
        k++;
    } while (k <= 5);
    printf("\n\n");
    
    // 4. Nested loop (perkalian)
    printf("Tabel perkalian 5x5:\n");
    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= 5; j++) {
            printf("%4d", i * j);
        }
        printf("\n");
    }
    printf("\n");
    
    // 5. Break dan continue
    printf("Contoh break (berhenti di 5):\n");
    for (int i = 1; i <= 10; i++) {
        if (i == 5) {
            break;  // keluar loop saat i = 5
        }
        printf("%d ", i);
    }
    printf("\n\n");
    
    printf("Contoh continue (lewati angka genap):\n");
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) {
            continue;  // skip angka genap
        }
        printf("%d ", i);
    }
    printf("\n");
    
    // 6. Infinite loop (hati-hati!)
    // while (1) {
    //     printf("Forever...\n");
    // }
    
    return 0;
}

8. Array

Array adalah kumpulan elemen dengan tipe data yang sama, disimpan dalam memori secara berurutan.

Cara deklarasi array:

tipe_data nama_array[ukuran];
tipe_data nama_array[] = {nilai1, nilai2, ...};

Indeks array dimulai dari 0.

Karakteristik array di C:

  • Ukuran fixed (tidak bisa diubah setelah deklarasi)
  • Semua elemen bertipe sama
  • Alokasi memori berurutan
  • Tidak ada bounds checking (hati-hati out of bounds!)
Contoh array
#include <stdio.h>

int main() {
    // Deklarasi array dengan ukuran
    int nilai[5];  // array 5 elemen (indeks 0-4)
    
    // Mengisi array
    nilai[0] = 80;
    nilai[1] = 85;
    nilai[2] = 90;
    nilai[3] = 75;
    nilai[4] = 95;
    
    // Mengakses array
    printf("Nilai pertama: %d\n", nilai[0]);
    printf("Nilai ketiga: %d\n", nilai[2]);
    
    // Looping array
    printf("Semua nilai:\n");
    for (int i = 0; i < 5; i++) {
        printf("nilai[%d] = %d\n", i, nilai[i]);
    }
    
    // Inisialisasi langsung
    int angka[] = {10, 20, 30, 40, 50, 60};  // ukuran otomatis 6
    int size = sizeof(angka) / sizeof(angka[0]);  // hitung jumlah elemen
    
    printf("Array angka (%d elemen):\n", size);
    for (int i = 0; i < size; i++) {
        printf("%d ", angka[i]);
    }
    printf("\n\n");
    
    // Array 2 dimensi (matriks)
    int matrix[3][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    printf("Matrix 3x3:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    
    // Array of characters (string)
    char nama[] = "Budi";
    printf("Nama: %s\n", nama);
    
    // Manual string (dengan null terminator \0)
    char kota[6] = {'J', 'a', 'k', 'a', 'r', '\0'};
    printf("Kota: %s\n", kota);
    
    // Mencari nilai maksimum
    int data[] = {45, 78, 23, 89, 12, 67};
    int n = sizeof(data) / sizeof(data[0]);
    int max = data[0];
    
    for (int i = 1; i < n; i++) {
        if (data[i] > max) {
            max = data[i];
        }
    }
    printf("Nilai maksimum: %d\n", max);
    
    return 0;
}
Peringatan: C tidak melakukan bounds checking! Jika Anda mengakses indeks di luar ukuran array (misal nilai[10]), program akan mengakses memory sembarangan (undefined behavior) dan bisa crash.

9. Functions

Fungsi adalah blok kode yang bisa dipanggil berulang kali.

Struktur fungsi:

return_type nama_fungsi(parameter1, parameter2) {
    // body
    return nilai;  // jika return_type bukan void
}

Prototype fungsi:

Deklarasi fungsi sebelum digunakan (biasanya di atas main).

return_type nama_fungsi(parameter_types);

Parameter passing:

  • Pass by value (default) - parameter di-copy
  • Pass by reference (menggunakan pointer) - bisa mengubah nilai asli
Contoh functions
#include <stdio.h>

// Function prototypes
int tambah(int a, int b);
double kali(double x, double y);
void sapa(char nama[]);
int faktorial(int n);
void swap(int *a, int *b);  // pass by reference

int main() {
    // Memanggil fungsi
    int hasil = tambah(10, 20);
    printf("10 + 20 = %d\n", hasil);
    
    double product = kali(3.5, 2.0);
    printf("3.5 * 2.0 = %.2lf\n", product);
    
    sapa("Budi");
    
    int f = faktorial(5);
    printf("5! = %d\n", f);
    
    // Pass by reference
    int x = 10, y = 20;
    printf("Sebelum swap: x=%d, y=%d\n", x, y);
    swap(&x, &y);  // kirim alamat (address)
    printf("Setelah swap: x=%d, y=%d\n", x, y);
    
    // Fungsi dengan array
    int angka[] = {1, 2, 3, 4, 5};
    int sum = sumArray(angka, 5);
    printf("Sum array: %d\n", sum);
    
    return 0;
}

// Definisi fungsi
int tambah(int a, int b) {
    return a + b;
}

double kali(double x, double y) {
    return x * y;
}

void sapa(char nama[]) {
    printf("Halo, %s!\n", nama);
    // void function tidak perlu return
}

// Fungsi rekursif
int faktorial(int n) {
    if (n <= 1) {
        return 1;
    } else {
        return n * faktorial(n - 1);
    }
}

// Pass by reference (menggunakan pointer)
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Fungsi dengan array parameter
int sumArray(int arr[], int size) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        total += arr[i];
    }
    return total;
}

// Fungsi dengan static variable
int counter() {
    static int count = 0;  // static: nilai tetap antar pemanggilan
    count++;
    return count;
}

// Fungsi inline (saran ke compiler)
inline int kuadrat(int x) {
    return x * x;
}

10. Pointer

Apa itu Pointer?

Pointer adalah variabel yang menyimpan alamat memori dari variabel lain. Ini adalah fitur paling powerful dan paling berbahaya di C.

Operator pointer:

  • & - address-of operator (mengambil alamat)
  • * - dereference operator (mengakses nilai di alamat)

Deklarasi pointer:

int *ptr;       // pointer ke integer
char *cptr;     // pointer ke char
double *dptr;   // pointer ke double
Konsep penting: Pointer memungkinkan kita untuk:
  • Memanipulasi data secara langsung di memory
  • Pass by reference ke fungsi
  • Membuat struktur data dinamis (linked list, tree)
  • Array dan string manipulation lebih efisien
Contoh dasar pointer
#include <stdio.h>

int main() {
    int x = 10;
    int *ptr;  // deklarasi pointer
    
    ptr = &x;  // ptr menyimpan alamat x
    
    printf("Nilai x: %d\n", x);
    printf("Alamat x: %p\n", &x);
    printf("Nilai ptr (alamat yang disimpan): %p\n", ptr);
    printf("Nilai yang ditunjuk ptr: %d\n", *ptr);  // dereference
    
    // Mengubah nilai melalui pointer
    *ptr = 20;
    printf("Setelah *ptr = 20, x menjadi: %d\n", x);
    
    // Pointer ke pointer
    int **ptr2 = &ptr;
    printf("ptr2 (alamat ptr): %p\n", ptr2);
    printf("**ptr2 = %d\n", **ptr2);
    
    // Pointer dan array
    int arr[] = {5, 10, 15, 20, 25};
    int *arrPtr = arr;  // nama array adalah pointer ke elemen pertama
    
    printf("\nAkses array dengan pointer:\n");
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d, *(arrPtr + %d) = %d\n", 
               i, arr[i], i, *(arrPtr + i));
    }
    
    // Pointer arithmetic
    printf("\nPointer arithmetic:\n");
    printf("arrPtr = %p\n", arrPtr);
    printf("arrPtr + 1 = %p (nilai: %d)\n", arrPtr + 1, *(arrPtr + 1));
    printf("arrPtr + 2 = %p (nilai: %d)\n", arrPtr + 2, *(arrPtr + 2));
    
    // Null pointer
    int *nullPtr = NULL;
    if (nullPtr == NULL) {
        printf("\nnullPtr adalah NULL pointer\n");
    }
    
    // Jangan dereference null pointer!
    // *nullPtr = 5;  // ERROR! akan crash
    
    return 0;
}
Pointer dan fungsi
#include <stdio.h>

void doubleValue(int *x) {
    *x = *x * 2;  // mengubah nilai asli
}

int* createArray(int size) {
    static int arr[100];  // static agar tidak hilang setelah fungsi selesai
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
    return arr;  // return pointer ke array
}

// Fungsi dengan pointer ke pointer
void allocateMemory(int **ptr, int size) {
    *ptr = (int*)malloc(size * sizeof(int));  // alokasi memory dinamis
    for (int i = 0; i < size; i++) {
        (*ptr)[i] = i * 5;
    }
}

// Function pointer
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }

int main() {
    int num = 10;
    printf("Sebelum: %d\n", num);
    doubleValue(&num);
    printf("Setelah doubleValue: %d\n", num);
    
    // Pointer ke array
    int *arr = createArray(5);
    printf("Array dari fungsi:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    // Dynamic allocation
    int *dynamicArr;
    allocateMemory(&dynamicArr, 5);
    printf("Dynamic array:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d ", dynamicArr[i]);
    }
    printf("\n");
    free(dynamicArr);  // jangan lupa free!
    
    // Function pointer
    int (*op)(int, int);  // deklarasi function pointer
    op = add;
    printf("add(5,3) = %d\n", op(5, 3));
    op = subtract;
    printf("subtract(5,3) = %d\n", op(5, 3));
    
    return 0;
}
Bahaya Pointer:
  • Dangling pointer - pointer ke memory yang sudah dibebaskan
  • Memory leak - lupa free memory yang dialokasikan
  • Buffer overflow - menulis melebihi alokasi
  • Null pointer dereference - akses NULL akan crash

11. String

Di C, string adalah array of characters yang diakhiri dengan null terminator (\0).

Deklarasi string:

char str1[] = "Hello";          // array, bisa diubah
char *str2 = "World";            // string literal (read-only)
char str3[20] = "C Programming"; // dengan ukuran tertentu

String functions (dari <string.h>):

  • strlen(s) - panjang string
  • strcpy(dest, src) - copy string
  • strcat(dest, src) - concatenate
  • strcmp(s1, s2) - compare (0 jika sama)
  • strchr(s, c) - mencari karakter
  • strstr(s, sub) - mencari substring
Contoh string manipulation
#include <stdio.h>
#include <string.h>

int main() {
    // Berbagai cara deklarasi string
    char str1[] = "Hello";
    char str2[20] = "World";
    char *str3 = "C Programming";
    
    printf("str1: %s\n", str1);
    printf("str2: %s\n", str2);
    printf("str3: %s\n", str3);
    
    // String functions
    char dest[50];
    
    strcpy(dest, str1);  // copy str1 ke dest
    printf("strcpy: %s\n", dest);
    
    strcat(dest, " ");   // tambah spasi
    strcat(dest, str2);  // gabung str2
    printf("strcat: %s\n", dest);
    
    printf("Panjang dest: %lu\n", strlen(dest));
    
    // String comparison
    if (strcmp(str1, "Hello") == 0) {
        printf("str1 sama dengan 'Hello'\n");
    }
    
    // Mencari karakter
    char *pos = strchr(dest, 'o');
    if (pos != NULL) {
        printf("Karakter 'o' ditemukan di posisi: %ld\n", pos - dest);
    }
    
    // Mencari substring
    char *sub = strstr(dest, "World");
    if (sub != NULL) {
        printf("'World' ditemukan: %s\n", sub);
    }
    
    // Manual string processing
    char text[] = "Hello, C Language";
    printf("\nManual processing:\n");
    for (int i = 0; text[i] != '\0'; i++) {
        printf("text[%d] = '%c' (ASCII: %d)\n", i, text[i], text[i]);
    }
    
    // Input string
    char input[100];
    printf("\nMasukkan nama: ");
    fgets(input, sizeof(input), stdin);  // aman, batasi input
    input[strcspn(input, "\n")] = 0;     // hapus newline
    printf("Halo, %s!\n", input);
    
    // Array of strings
    char *names[] = {"Alice", "Bob", "Charlie", "David"};
    int count = 4;
    
    printf("\nDaftar nama:\n");
    for (int i = 0; i < count; i++) {
        printf("%d. %s\n", i + 1, names[i]);
    }
    
    return 0;
}

12. Struct & Union

Struct (Structure)

Struct mengelompokkan variabel dengan tipe berbeda dalam satu kesatuan.

Deklarasi struct:

struct NamaStruct {
    tipe1 field1;
    tipe2 field2;
    // ...
};

Union

Union mirip struct, tapi semua field berbagi lokasi memory yang sama. Ukuran union = ukuran field terbesar.

Perbedaan struct vs union:

  • Struct: setiap field punya memory sendiri
  • Union: semua field berbagi memory yang sama
Typedef: Gunakan typedef untuk membuat alias, sehingga tidak perlu menulis struct setiap kali.
Contoh Struct dan Union
#include <stdio.h>
#include <string.h>

// Definisi struct
struct Mahasiswa {
    char nama[50];
    int umur;
    float ipk;
    char jurusan[30];
};

// Dengan typedef
typedef struct {
    char merk[50];
    int tahun;
    int harga;
} Mobil;

// Nested struct
struct Alamat {
    char jalan[100];
    char kota[50];
    int kodePos;
};

struct Pegawai {
    char nama[50];
    struct Alamat alamat;
    float gaji;
};

// Union
union Data {
    int i;
    float f;
    char str[20];
};

// Fungsi untuk menampilkan struct
void displayMahasiswa(struct Mahasiswa m) {
    printf("Nama: %s\n", m.nama);
    printf("Umur: %d\n", m.umur);
    printf("IPK: %.2f\n", m.ipk);
    printf("Jurusan: %s\n", m.jurusan);
    printf("---\n");
}

int main() {
    // Inisialisasi struct
    struct Mahasiswa mhs1;
    strcpy(mhs1.nama, "Budi Santoso");
    mhs1.umur = 20;
    mhs1.ipk = 3.75;
    strcpy(mhs1.jurusan, "Informatika");
    
    // Inisialisasi langsung
    struct Mahasiswa mhs2 = {
        "Ani Wijaya",
        21,
        3.90,
        "Sistem Informasi"
    };
    
    printf("Data Mahasiswa 1:\n");
    displayMahasiswa(mhs1);
    
    printf("Data Mahasiswa 2:\n");
    displayMahasiswa(mhs2);
    
    // Menggunakan typedef (tanpa struct keyword)
    Mobil mobil1 = {"Toyota", 2020, 250000000};
    printf("Mobil: %s %d, Harga: Rp%d\n", 
           mobil1.merk, mobil1.tahun, mobil1.harga);
    
    // Nested struct
    struct Pegawai pgw1;
    strcpy(pgw1.nama, "Joko");
    strcpy(pgw1.alamat.jalan, "Jl. Merdeka No. 1");
    strcpy(pgw1.alamat.kota, "Jakarta");
    pgw1.alamat.kodePos = 12345;
    pgw1.gaji = 5000000;
    
    printf("\nData Pegawai:\n");
    printf("Nama: %s\n", pgw1.nama);
    printf("Alamat: %s, %s %d\n", 
           pgw1.alamat.jalan, pgw1.alamat.kota, pgw1.alamat.kodePos);
    
    // Array of struct
    struct Mahasiswa kelas[3] = {
        {"Budi", 20, 3.5, "Informatika"},
        {"Ani", 21, 3.8, "Sistem Informasi"},
        {"Citra", 19, 3.9, "Teknik Komputer"}
    };
    
    printf("\nDaftar Kelas:\n");
    for (int i = 0; i < 3; i++) {
        printf("%d. %s - %s (IPK: %.2f)\n", 
               i+1, kelas[i].nama, kelas[i].jurusan, kelas[i].ipk);
    }
    
    // Pointer ke struct
    struct Mahasiswa *ptr = &mhs1;
    printf("\nAkses via pointer: %s, umur %d\n", 
           ptr->nama, ptr->umur);  // menggunakan operator ->
    
    // UNION
    printf("\n=== DEMO UNION ===\n");
    union Data data;
    
    data.i = 10;
    printf("data.i = %d\n", data.i);
    
    data.f = 220.5;
    printf("data.f = %.2f (i sekarang: %d, ter-overwrite)\n", data.f, data.i);
    
    strcpy(data.str, "Hello");
    printf("data.str = %s (i: %d, f: %.2f - semua berubah)\n", 
           data.str, data.i, data.f);
    
    // Ukuran struct vs union
    printf("\nUkuran struct Mahasiswa: %lu bytes\n", sizeof(struct Mahasiswa));
    printf("Ukuran union Data: %lu bytes\n", sizeof(union Data));
    
    // Struct bit field (untuk efisiensi)
    struct {
        unsigned int aktif : 1;   // 1 bit
        unsigned int role : 3;     // 3 bits (0-7)
        unsigned int umur : 8;     // 8 bits (0-255)
    } status;
    
    status.aktif = 1;
    status.role = 5;
    status.umur = 25;
    
    printf("\nBit fields: aktif=%d, role=%d, umur=%d\n",
           status.aktif, status.role, status.umur);
    printf("Ukuran bit field struct: %lu bytes\n", sizeof(status));
    
    return 0;
}
Memory Alignment: Compiler bisa menambahkan padding di struct untuk alignment. Urutan field mempengaruhi ukuran total struct.