1. Pengenalan C Programming
C adalah bahasa pemrograman general-purpose yang dikembangkan oleh Dennis Ritchie di Bell Labs pada tahun 1972. C merupakan salah satu bahasa pemrograman yang paling berpengaruh dalam sejarah komputer dan menjadi dasar bagi banyak bahasa modern seperti C++, Java, C#, dan Python.
C dirancang sebagai bahasa tingkat menengah yang menggabungkan kemampuan bahasa tingkat rendah (hardware access) dengan fitur bahasa tingkat tinggi (structured programming). C digunakan secara luas di sistem operasi (Linux, Windows kernel), embedded systems, game engines, compiler, dan berbagai aplikasi high-performance.
Mengapa Belajar C?
| Keunggulan | Penjelasan |
|---|---|
| Sangat Cepat | C menghasilkan kode mesin yang sangat efisien, cocok untuk aplikasi yang membutuhkan performa tinggi |
| Low-Level Access | Bisa langsung memanipulasi memori melalui pointer dan alamat memori |
| Portabel | Kode C bisa dikompilasi dan dijalankan di hampir semua platform |
| Foundation | Memahami C membantu memahami bahasa lain seperti C++, Java, Rust |
| Embedded Systems | Menjadi bahasa utama untuk mikrokontroler, IoT, dan sistem embedded |
| Operating Systems | Kernel Linux, Windows, dan macOS ditulis dengan C |
C vs Bahasa Lain
| Aspek | C | Python | Java |
|---|---|---|---|
| Tipe | Compiled | Interpreted | Compiled + JIT |
| Typing | Static | Dynamic | Static |
| Kecepatan | π’ Sangat Cepat | π‘ Sedang | π’ Cepat |
| Memory | Manual | Garbage Collection | Garbage Collection |
| Sintaks | π‘ Sedang | π’ Sangat Mudah | π΄ Verbose |
| Cocok untuk | System, Embedded | AI, Data, Otomasi | Enterprise, Android |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β PROSES KOMPILASI C PROGRAM β β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β β Source β β Pre- β β Compiler β β β β Code βββββΆβ ProcessorβββββΆβ (Translate to β β β β .c file β β (#includeβ β Assembly) β β β ββββββββββββ β #define)β ββββββββββ¬ββββββββββ β β ββββββββββββ β β β βΌ β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β β β Executableβββββ Linker βββββ Assembler β β β β Program β β (Combine β β (Object Code β β β β (.exe) β β libs) β β .o / .obj) β β β ββββββββββββ ββββββββββββ ββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. Instalasi dan Setup
Untuk memulai programming C, Anda membutuhkan compiler. GCC (GNU Compiler Collection) adalah compiler C yang paling populer dan tersedia di semua platform.
Instalasi di Windows
# Opsi 1: MinGW-w64 (GCC untuk Windows) # 1. Download dari https://www.mingw-w64.org/ # 2. Instal dan tambahkan ke PATH # 3. Verifikasi: gcc --version # Opsi 2: MSYS2 (recommended) # 1. Download dari https://www.mys2.org/ # 2. Instal, buka MSYS2 terminal: pacman -S mingw-w64-x86_64-gcc # 3. Tambahkan C:\msys64\mingw64\bin ke PATH # Opsi 3: WSL (Windows Subsystem for Linux) wsl --install # Di dalam WSL: sudo apt install gcc build-essential -y
Instalasi di Linux
# Instal GCC dan build tools sudo apt update sudo apt install gcc build-essential gdb -y # Verifikasi gcc --version # Output: gcc (Ubuntu 13.2.0-23ubuntu4) 13.2.0 # Instal editor/code editor # VS Code (recommended): sudo snap install code --classic # Atau vim: sudo apt install vim -y
Program C Pertama
#include <stdio.h>
int main() {
printf("Halo, dunia!\n");
printf("Selamat datang di C Programming!\n");
printf("Belajar C di BeebaneLabs\n");
return 0;
}
// Kompilasi dan jalankan:
// gcc hello.c -o hello
// ./hello
//
// Output:
// Halo, dunia!
// Selamat datang di C Programming!
// Belajar C di BeebaneLabs
Anatomy Program C
// 1. Preprocessor directives β diawali dengan #
#include <stdio.h> // Library standar input/output
#include <stdlib.h> // Library standar (malloc, exit, dll)
// 2. Deklarasi fungsi (opsional, untuk forward declaration)
int tambah(int a, int b);
// 3. Fungsi main β titik awal eksekusi program
int main(int argc, char *argv[]) {
// Kode program Anda di sini
int hasil = tambah(5, 3);
printf("5 + 3 = %d\n", hasil);
return 0; // 0 = program berhasil
}
// 4. Definisi fungsi
int tambah(int a, int b) {
return a + b;
}
Selalu akhiri setiap statement dengan titik koma (;). Gunakan \n di akhir printf() untuk pindah baris. Jangan lupa return 0; di akhir fungsi main() untuk menandakan program berakhir dengan sukses.
3. Variabel dan Tipe Data
Di C, setiap variabel harus dideklarasikan dengan tipe data secara eksplisit sebelum digunakan. Ini berbeda dengan Python yang menggunakan dynamic typing.
Tipe Data Dasar
| Tipe | Ukuran | Rentang | Contoh |
|---|---|---|---|
char | 1 byte | -128 s/d 127 | 'A', 'z', '\n' |
int | 4 byte | -2.1 miliar s/d 2.1 miliar | 42, -10, 0 |
float | 4 byte | Β±3.4 Γ 10^38 | 3.14f, -0.5f |
double | 8 byte | Β±1.7 Γ 10^308 | 3.14159265358979 |
short | 2 byte | -32768 s/d 32767 | 100, -50 |
long | 8 byte | Β±9.2 Γ 10^18 | 1234567890L |
unsigned int | 4 byte | 0 s/d 4.2 miliar | 42U |
Deklarasi dan Inisialisasi Variabel
#include <stdio.h>
#include <string.h>
int main() {
// Deklarasi variabel
int umur = 25;
float tinggi = 175.5;
char grade = 'A';
double pi = 3.14159265358979;
// Deklarasi string (array of char)
char nama[50] = "Budi Santoso";
// Multiple declaration
int a = 10, b = 20, c = 30;
// Konstanta β tidak bisa diubah
const int MAKS_PESERTA = 100;
#define PI 3.14159 // Preprocessor constant
// sizeof β cek ukuran tipe data
printf("Ukuran int: %lu byte\n", sizeof(int));
printf("Ukuran float: %lu byte\n", sizeof(float));
printf("Ukuran double: %lu byte\n", sizeof(double));
printf("Ukuran char: %lu byte\n", sizeof(char));
// Menampilkan nilai
printf("Nama: %s\n", nama);
printf("Umur: %d tahun\n", umur);
printf("Tinggi: %.1f cm\n", tinggi);
printf("Grade: %c\n", grade);
printf("Pi: %.15f\n", pi);
// Format specifier umum:
// %d = integer, %f = float/double, %c = char
// %s = string, %x = hexadecimal, %o = octal
// %p = pointer address, %lu = unsigned long
return 0;
}
Operator di C
#include <stdio.h>
int main() {
int a = 15, b = 4;
// Aritmatika
printf("a + b = %d\n", a + b); // 19
printf("a - b = %d\n", a - b); // 11
printf("a * b = %d\n", a * b); // 60
printf("a / b = %d\n", a / b); // 3 (integer division!)
printf("a %% b = %d\n", a % b); // 3 (modulus)
// Perbandingan β menghasilkan 0 (false) atau 1 (true)
printf("a == b: %d\n", a == b); // 0
printf("a != b: %d\n", a != b); // 1
printf("a > b: %d\n", a > b); // 1
// Logika
// && (AND), || (OR), ! (NOT)
printf("AND: %d\n", (a > 10 && b > 2)); // 1
printf("OR: %d\n", (a > 20 || b > 2)); // 1
// Increment/Decrement
int x = 10;
x++; // x sekarang 11
x--; // x kembali 10
++x; // x = 11 (prefix)
printf("x = %d\n", x); // 11
// Bitwise operator
int p = 5; // 0101
int q = 3; // 0011
printf("p & q = %d\n", p & q); // 1 (0001)
printf("p | q = %d\n", p | q); // 7 (0111)
printf("p ^ q = %d\n", p ^ q); // 6 (0110)
printf("p << 1 = %d\n", p << 1); // 10 (1010)
return 0;
}
4. Pointer
Pointer adalah salah satu fitur paling powerful dan penting di C. Pointer menyimpan alamat memori dari variabel lain, bukan nilainya. Memahami pointer adalah kunci untuk menguasai C.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CARA KERJA POINTER β
β β
β Variabel 'x' Pointer 'ptr' β
β ββββββββββββββ ββββββββββββββ β
β β nilai: 42 β β alamat: ββββββββ β
β β addr: 0x100ββββββββββ 0x100 β β β
β ββββββββββββββ ββββββββββββββ β β
β β β
β int x = 42; int *ptr = &x; β β
β printf("%d", x); printf("%d", *ptrβ); β
β // Output: 42 // Output: 42 β β
β βΌ β
β ptr menyimpan alamat x (0x100), β β
β *ptr mengakses nilai di alamat tersebut β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Dasar Pointer
#include <stdio.h>
int main() {
int x = 42;
int *ptr = &x; // ptr menyimpan alamat x
// & (address-of) β mendapatkan alamat variabel
// * (dereference) β mendapatkan nilai dari alamat
printf("Nilai x: %d\n", x); // 42
printf("Alamat x: %p\n", (void*)&x); // 0x7ffd...
printf("Nilai ptr (alamat): %p\n", (void*)ptr); // sama
printf("Nilai *ptr: %d\n", *ptr); // 42
// Mengubah nilai melalui pointer
*ptr = 100;
printf("x setelah diubah via pointer: %d\n", x); // 100
// Pointer ke pointer
int **pptr = &ptr;
printf("**pptr = %d\n", **pptr); // 100
// Pointer NULL
int *null_ptr = NULL;
if (null_ptr == NULL) {
printf("Pointer ini tidak menunjuk ke mana-mana\n");
}
return 0;
}
Pointer dan Fungsi (Pass by Reference)
#include <stdio.h>
// Pass by value β tidak mengubah variabel asli
void tukar_salah(int a, int b) {
int temp = a;
a = b;
b = temp;
// Perubahan hanya di dalam fungsi ini!
}
// Pass by reference (via pointer) β MENGUBAH variabel asli
void tukar_benar(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
// Perubahan langsung ke alamat memori asli!
}
// Fungsi yang mengembalikan beberapa nilai via pointer
void hitung(int a, int b, int *hasil_tambah, int *hasil_kali) {
*hasil_tambah = a + b;
*hasil_kali = a * b;
}
int main() {
int x = 10, y = 20;
printf("Sebelum tukar: x=%d, y=%d\n", x, y);
tukar_salah(x, y);
printf("Setelah tukar_salah: x=%d, y=%d\n", x, y); // Tidak berubah!
tukar_benar(&x, &y);
printf("Setelah tukar_benar: x=%d, y=%d\n", x, y); // Berubah!
int tambah, kali;
hitung(5, 3, &tambah, &kali);
printf("5+3=%d, 5*3=%d\n", tambah, kali);
return 0;
}
Pointer yang tidak diinisialisasi (dangling pointer) dan pointer yang sudah di-free tapi masih dipakai (use-after-free) adalah sumber bug yang paling berbahaya di C. Selalu inisialisasi pointer ke NULL dan set ke NULL setelah free().
5. Array dan String
Array adalah kumpulan elemen dengan tipe data yang sama yang disimpan secara berurutan di memori. Di C, array memiliki ukuran tetap yang ditentukan saat deklarasi.
Array Satu Dimensi
#include <stdio.h>
int main() {
// Deklarasi array
int nilai[5] = {90, 85, 78, 92, 88};
int angka[10] = {0}; // Semua elemen = 0
int arr[5]; // Uninitialized (bahaya!)
// Mengakses elemen (index dimulai dari 0)
printf("Nilai ke-0: %d\n", nilai[0]); // 90
printf("Nilai ke-3: %d\n", nilai[3]); // 92
// Mengubah elemen
nilai[2] = 95;
// Loop melalui array
int jumlah = 0;
for (int i = 0; i < 5; i++) {
printf("nilai[%d] = %d\n", i, nilai[i]);
jumlah += nilai[i];
}
printf("Rata-rata: %.2f\n", jumlah / 5.0);
// Ukuran array
printf("Jumlah elemen: %lu\n", sizeof(nilai) / sizeof(nilai[0]));
// Array dan pointer β nama array adalah pointer ke elemen pertama
printf("Alamat array: %p\n", (void*)nilai);
printf("Alamat elemen[0]: %p\n", (void*)&nilai[0]);
printf("Nilai via pointer: %d\n", *nilai); // 90
printf("Nilai via pointer+2: %d\n", *(nilai + 2)); // 95
return 0;
}
Array Dua Dimensi (Matrix)
#include <stdio.h>
int main() {
// Matrix 3x3
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Menampilkan matrix
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");
}
// Transpose matrix
int transpose[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
transpose[j][i] = matrix[i][j];
}
}
printf("\nTranspose:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", transpose[i][j]);
}
printf("\n");
}
return 0;
}
String di C
#include <stdio.h>
#include <string.h>
int main() {
// String = array of char yang diakhiri null terminator '\0'
char nama[] = "Budi"; // Ukuran otomatis: 5 (4 + '\0')
char kota[50] = "Jakarta"; // Ukuran 50, isi "Jakarta\0"
// Fungsi string dari string.h
printf("Panjang nama: %lu\n", strlen(nama)); // 4
// strcpy β menyalin string
char salinan[50];
strcpy(salinan, nama);
printf("Salinan: %s\n", salinan);
// strcat β menggabungkan string
char greeting[100] = "Halo, ";
strcat(greeting, nama);
strcat(greeting, "!");
printf("%s\n", greeting); // Halo, Budi!
// strcmp β membandingkan string
// return 0 jika sama, <0 jika str1 < str2, >0 jika str1 > str2
printf("strcmp: %d\n", strcmp("apel", "jeruk")); // negatif
// sprintf β menulis ke string (bukan ke layar)
char buffer[200];
sprintf(buffer, "Nama: %s, Umur: %d, Kota: %s", nama, 25, kota);
printf("%s\n", buffer);
// Input string dari user
char input[100];
printf("Masukkan nama: ");
fgets(input, sizeof(input), stdin); // Lebih aman dari gets()
input[strcspn(input, "\n")] = 0; // Hapus newline
printf("Hello, %s!\n", input);
return 0;
}
6. Fungsi
Fungsi adalah blok kode yang bisa dipanggil berulang kali. Fungsi membantu memecah program menjadi bagian-bagian kecil yang reusable dan mudah di-maintain.
Definisi dan Pemanggilan Fungsi
#include <stdio.h>
#include <math.h>
// Fungsi tanpa return (void)
void sapa(char nama[]) {
printf("Halo, %s! Selamat datang.\n", nama);
}
// Fungsi dengan return value
int tambah(int a, int b) {
return a + b;
}
// Fungsi dengan banyak parameter
float hitung_rata(int nilai[], int jumlah) {
int total = 0;
for (int i = 0; i < jumlah; i++) {
total += nilai[i];
}
return (float)total / jumlah;
}
// Rekursif β fungsi yang memanggil dirinya sendiri
long faktorial(int n) {
if (n <= 1) return 1; // Base case
return n * faktorial(n - 1); // Recursive case
}
// Fungsi rekursif β Fibonacci
int fibonacci(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// Function pointer β menyimpan alamat fungsi
int operasi(int a, int b, int (*func)(int, int)) {
return func(a, b);
}
int kali(int a, int b) { return a * b; }
int bagi(int a, int b) { return b != 0 ? a / b : 0; }
int main() {
sapa("Budi");
int hasil = tambah(10, 20);
printf("10 + 20 = %d\n", hasil);
int data[] = {80, 90, 75, 85, 95};
printf("Rata-rata: %.2f\n", hitung_rata(data, 5));
printf("Faktorial 5! = %ld\n", faktorial(5)); // 120
printf("Fibonacci(10) = %d\n", fibonacci(10)); // 55
// Function pointer
printf("3 * 4 = %d\n", operasi(3, 4, kali));
printf("10 / 3 = %d\n", operasi(10, 3, bagi));
return 0;
}
Setiap fungsi rekursif harus memiliki base case (kondisi berhenti) untuk mencegah infinite recursion. Terlalu dalam rekursi bisa menyebabkan stack overflow. Untuk kasus sederhana, pertimbangkan menggunakan iterasi (loop) sebagai alternatif yang lebih efisien.
7. Struct dan Union
Struct adalah tipe data yang memungkinkan Anda mengelompokkan beberapa variabel dengan tipe berbeda menjadi satu kesatuan. Struct adalah cikal bakal dari class di C++.
Struct Dasar
#include <stdio.h>
#include <string.h>
// Definisi struct
struct Mahasiswa {
char nama[50];
int umur;
float ipk;
char jurusan[50];
};
// Struct dengan typedef β tidak perlu 'struct' lagi
typedef struct {
float x;
float y;
} Titik;
typedef struct {
Titik posisi;
float radius;
} Lingkaran;
// Fungsi yang menerima struct
void cetak_mahasiswa(struct Mahasiswa m) {
printf("Nama : %s\n", m.nama);
printf("Umur : %d tahun\n", m.umur);
printf("IPK : %.2f\n", m.ipk);
printf("Jurusan : %s\n", m.jurusan);
}
// Fungsi dengan pointer ke struct (lebih efisien)
void ubah_ipk(struct Mahasiswa *m, float ipk_baru) {
m->ipk = ipk_baru; // Arrow operator untuk pointer
}
int main() {
// Membuat instance struct
struct Mahasiswa mhs1;
strcpy(mhs1.nama, "Budi Santoso");
mhs1.umur = 20;
mhs1.ipk = 3.75;
strcpy(mhs1.jurusan, "Teknik Informatika");
cetak_mahasiswa(mhs1);
// Struct initialization
struct Mahasiswa mhs2 = {"Ani Putri", 21, 3.90, "Sistem Informasi"};
printf("\n--- Mahasiswa 2 ---\n");
cetak_mahasiswa(mhs2);
// Pointer ke struct
struct Mahasiswa *ptr = &mhs1;
printf("\nAkses via pointer: %s\n", ptr->nama);
ubah_ipk(&mhs1, 3.85);
printf("IPK baru: %.2f\n", mhs1.ipk);
// Array of struct
struct Mahasiswa kelas[3] = {
{"Andi", 19, 3.50, "DKV"},
{"Sari", 20, 3.80, "Akuntansi"},
{"Dedi", 21, 3.65, "Hukum"}
};
printf("\n--- Daftar Kelas ---\n");
for (int i = 0; i < 3; i++) {
printf("%d. %s (IPK: %.2f)\n", i+1, kelas[i].nama, kelas[i].ipk);
}
// Typedef struct
Titik p1 = {3.0, 4.0};
Lingkaran c1 = {{0.0, 0.0}, 5.0};
printf("\nTitik: (%.1f, %.1f)\n", p1.x, p1.y);
printf("Lingkaran: pusat(%.1f,%.1f) r=%.1f\n",
c1.posisi.x, c1.posisi.y, c1.radius);
return 0;
}
Enum dan Bit Field
#include <stdio.h>
// Enum β tipe data dengan nilai bernama
enum Hari { SENIN, SELASA, RABU, KAMIS, JUMAT, SABTU, MINGGU };
// SENIN=0, SELASA=1, dst.
enum Status { AKTIF = 1, NONAKTIF = 0, SUSPEND = -1 };
// Bit field β menghemat memori untuk flag boolean
struct Flags {
unsigned int is_active : 1; // 1 bit
unsigned int is_admin : 1; // 1 bit
unsigned int level : 3; // 3 bit (0-7)
unsigned int reserved : 3; // 3 bit
};
int main() {
enum Hari hari_ini = RABU;
printf("Hari ke-%d\n", hari_ini); // 2
switch (hari_ini) {
case SENIN: case SELASA: case RABU:
case KAMIS: case JUMAT:
printf("Hari kerja\n");
break;
case SABTU: case MINGGU:
printf("Weekend!\n");
break;
}
struct Flags f = {1, 1, 5, 0};
printf("Active: %u, Admin: %u, Level: %u\n",
f.is_active, f.is_admin, f.level);
printf("Ukuran struct Flags: %lu byte\n", sizeof(struct Flags));
return 0;
}
8. Kontrol Alur
Kontrol alur menentukan jalannya eksekusi program berdasarkan kondisi atau pengulangan.
If-Else dan Switch
#include <stdio.h>
int main() {
int nilai = 85;
// If-else 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\n");
}
// Ternary operator
char *status = (nilai >= 60) ? "Lulus" : "Tidak Lulus";
printf("Status: %s\n", status);
// 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;
default: printf("Weekend\n"); break;
}
return 0;
}
Loop (Perulangan)
#include <stdio.h>
int main() {
// For loop
printf("For loop: ");
for (int i = 1; i <= 5; i++) {
printf("%d ", i);
}
printf("\n");
// While loop
printf("While loop: ");
int j = 1;
while (j <= 5) {
printf("%d ", j);
j++;
}
printf("\n");
// Do-while loop β minimal dieksekusi 1x
printf("Do-while: ");
int k = 10;
do {
printf("%d ", k);
k++;
} while (k <= 5); // Tetap cetak 10 sekali
printf("\n");
// Nested loop β membuat pola bintang
printf("\nPola segitiga:\n");
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= i; j++) {
printf("* ");
}
printf("\n");
}
// Break dan Continue
printf("\nAngka ganjil (1-10): ");
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) continue; // Skip genap
printf("%d ", i);
}
printf("\n");
// Infinite loop dengan break
int count = 0;
while (1) {
if (count >= 5) break;
printf("Iterasi %d\n", count);
count++;
}
// Goto (hindari penggunaan kecuali sangat perlu)
goto selesai;
printf("Ini tidak akan dieksekusi\n");
selesai:
printf("Program selesai!\n");
return 0;
}
9. File I/O
C menyediakan fungsi-fungsi untuk membaca dan menulis file melalui library stdio.h. File I/O sangat penting untuk menyimpan data secara persisten.
Menulis dan Membaca File Teks
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
// ===== MENULIS FILE =====
fp = fopen("data.txt", "w"); // "w" = write (overwrite)
if (fp == NULL) {
printf("Error: Tidak bisa membuka file!\n");
return 1;
}
fprintf(fp, "Nama: Budi Santoso\n");
fprintf(fp, "Umur: 25\n");
fprintf(fp, "IPK: 3.75\n");
fclose(fp);
printf("File berhasil ditulis!\n");
// ===== APPEND (menambah di akhir) =====
fp = fopen("data.txt", "a"); // "a" = append
if (fp != NULL) {
fprintf(fp, "Jurusan: Teknik Informatika\n");
fclose(fp);
}
// ===== MEMBACA FILE =====
// Cara 1: fgets β baca baris per baris
fp = fopen("data.txt", "r"); // "r" = read
if (fp == NULL) {
printf("Error: File tidak ditemukan!\n");
return 1;
}
char buffer[256];
printf("\n=== Isi File ===\n");
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
// Cara 2: fscanf β baca dengan format
fp = fopen("data.txt", "r");
if (fp != NULL) {
char nama[50], jurusan[50];
int umur;
float ipk;
// Skip "Nama: ", baca nama
fscanf(fp, "Nama: %[^\n]\n", nama);
fscanf(fp, "Umur: %d\n", &umur);
fscanf(fp, "IPK: %f\n", &ipk);
fscanf(fp, "Jurusan: %[^\n]\n", jurusan);
printf("\nParsed: %s, %d, %.2f, %s\n", nama, umur, ipk, jurusan);
fclose(fp);
}
// ===== MODE FILE =====
// "r" β read only
// "w" β write only (overwrite, buat baru jika tidak ada)
// "a" β append (tambah di akhir)
// "r+" β read + write
// "w+" β read + write (overwrite)
// "a+" β read + append
return 0;
}
File Binary
#include <stdio.h>
#include <string.h>
typedef struct {
char nama[50];
int umur;
float ipk;
} Mahasiswa;
int main() {
// Menulis struct ke file binary
Mahasiswa data[] = {
{"Budi", 20, 3.75},
{"Ani", 21, 3.90},
{"Dedi", 19, 3.50}
};
FILE *fp = fopen("mahasiswa.bin", "wb"); // wb = write binary
if (fp == NULL) return 1;
// Tulis jumlah data dulu
int jumlah = 3;
fwrite(&jumlah, sizeof(int), 1, fp);
// Tulis array struct
fwrite(data, sizeof(Mahasiswa), jumlah, fp);
fclose(fp);
printf("Data binary berhasil ditulis!\n");
// Membaca struct dari file binary
fp = fopen("mahasiswa.bin", "rb"); // rb = read binary
if (fp == NULL) return 1;
int count;
fread(&count, sizeof(int), 1, fp);
Mahasiswa hasil[count];
fread(hasil, sizeof(Mahasiswa), count, fp);
fclose(fp);
printf("\n=== Data dari Binary File ===\n");
for (int i = 0; i < count; i++) {
printf("%d. %s (Umur: %d, IPK: %.2f)\n",
i+1, hasil[i].nama, hasil[i].umur, hasil[i].ipk);
}
return 0;
}
10. Preprocessor dan Header
Preprocessor di C berjalan sebelum proses kompilasi. Semua direktif preprocessor diawali dengan #.
Directives Umum
// ===== Include Guards (mencegah double inclusion) =====
// mathutils.h
#ifndef MATHUTILS_H
#define MATHUTILS_H
// Deklarasi fungsi
int tambah(int a, int b);
int kurang(int a, int b);
#endif // MATHUTILS_H
// ===== Macro =====
#define PI 3.14159265358979
#define MAX_SIZE 100
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
// Conditional compilation
#ifdef DEBUG
#define LOG(msg) printf("[DEBUG] %s\n", msg)
#else
#define LOG(msg) // Tidak melakukan apa-apa
#endif
// Stringification
#define STRINGIFY(x) #x
#define CONCAT(a, b) a##b
#include <stdio.h>
int main() {
printf("PI = %f\n", PI);
printf("5^2 = %d\n", SQUARE(5));
printf("Max(10, 20) = %d\n", MAX(10, 20));
LOG("Program dimulai"); // Hanya aktif jika -DDEBUG
printf("STRINGIFY: %s\n", STRINGIFY(hello world));
int xy = 100;
printf("CONCAT: %d\n", CONCAT(x, y)); // xy β 100
// Predefined macros
printf("File: %s\n", __FILE__);
printf("Line: %d\n", __LINE__);
printf("Date: %s\n", __DATE__);
printf("Time: %s\n", __TIME__);
return 0;
}
Dynamic Memory Allocation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// malloc β alokasi memori tanpa inisialisasi
int *arr = (int*)malloc(5 * sizeof(int));
if (arr == NULL) {
printf("Alokasi memori gagal!\n");
return 1;
}
// Gunakan memori
for (int i = 0; i < 5; i++) {
arr[i] = (i + 1) * 10;
}
printf("Array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// calloc β alokasi dengan inisialisasi 0
int *zeros = (int*)calloc(5, sizeof(int));
printf("Calloc[0] = %d\n", zeros[0]); // 0
// realloc β ubah ukuran memori
arr = (int*)realloc(arr, 10 * sizeof(int));
for (int i = 5; i < 10; i++) {
arr[i] = (i + 1) * 10;
}
printf("Array setelah realloc: ");
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// free β bebaskan memori!
free(arr);
free(zeros);
arr = NULL; // Good practice
zeros = NULL;
// Linked list sederhana menggunakan dynamic memory
typedef struct Node {
int data;
struct Node *next;
} Node;
Node *head = NULL;
for (int i = 5; i >= 1; i--) {
Node *new_node = (Node*)malloc(sizeof(Node));
new_node->data = i * 10;
new_node->next = head;
head = new_node;
}
printf("\nLinked List: ");
Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
// Bebaskan linked list
current = head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}
return 0;
}
11. Best Practices
Berikut beberapa best practices saat menulis program C untuk menghindari bug dan masalah keamanan.
| Praktik | Penjelasan |
|---|---|
| Inisialisasi variabel | Selalu inisialisasi variabel saat deklarasi untuk menghindari garbage value |
| Check NULL pointer | Selalu cek hasil malloc/calloc/fopen apakah NULL |
| Free memory | Selalu free() memori yang sudah dialokasikan setelah selesai |
| Avoid gets() | Gunakan fgets() karena gets() rentan buffer overflow |
| Bounds checking | Selalu cek indeks array agar tidak out-of-bounds |
| Const correctness | Gunakan const untuk pointer/variabel yang tidak berubah |
| Compiler warnings | Kompilasi dengan -Wall -Wextra untuk menangkap potensi bug |
| Include guards | Selalu gunakan #ifndef/#define/#endif di header file |
// Kompilasi dengan warning flags:
// gcc -Wall -Wextra -Werror -std=c11 -o program program.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Gunakan const untuk parameter input
void cetak(const char *pesan) {
printf("%s\n", pesan);
}
// Selalu cek return value
int baca_angka(const char *prompt) {
char buffer[32];
printf("%s", prompt);
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
return -1;
}
return atoi(buffer);
}
// Safe string copy
void safe_strcpy(char *dest, const char *src, size_t dest_size) {
strncpy(dest, src, dest_size - 1);
dest[dest_size - 1] = '\0';
}
int main() {
// Contoh safe coding
int *data = (int*)malloc(100 * sizeof(int));
if (data == NULL) {
fprintf(stderr, "Gagal alokasi memori!\n");
return EXIT_FAILURE;
}
// ... gunakan data ...
free(data);
data = NULL; // Hindari dangling pointer
cetak("Program selesai dengan aman!");
return EXIT_SUCCESS;
}
12. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang C Programming: