03. Variabel, tipe data, dan masukan
Program yang berguna bekerja dengan data yang berubah-ubah. Bab ini memperkenalkan variabel, tipe-tipe data yang dipakai di lomba, operasi hitungnya, dan cara membaca masukan dengan format yang diterima penilai daring.
Variabel dan tipe
Di C++ setiap variabel diberi tipe saat dibuat. Tipe menentukan nilai apa yang boleh disimpan dan berapa besar memorinya.
int umur = 15;
long long penduduk = 8000000000LL;
double berat = 47.5;
char nilai = 'A';
bool lulus = true;
string nama = "Budi";Bayangkan variabel sebagai kotak berlabel di dalam memori. Labelnya adalah namanya, ukurannya ditentukan tipenya, dan isinya boleh diganti kapan saja — tetapi tipenya tidak.
Ada dua kejadian berbeda yang sering tertukar:
int umur = 15; // deklarasi: kotak baru dibuat, lalu diisi
umur = 16; // penugasan: kotak yang sudah ada, isinya diganti
int umur = 17; // error: kotak dengan nama itu sudah adaKotak yang dibuat tanpa diisi berisi nilai sampah, bukan nol:
int x;
cout << x << "\n"; // angka tak terduga, dan bisa berbeda tiap dijalankanCompiler tidak selalu memperingatkan. Biasakan mengisi setiap
variabel saat dibuat, misalnya int jumlah = 0; — terutama
variabel penampung yang akan ditambah di dalam perulangan nanti.
Aturan penamaan: boleh huruf, angka, dan garis bawah, tetapi tidak
boleh diawali angka dan tidak boleh memakai kata kunci C++ seperti
int atau return. Huruf besar-kecil dibedakan,
jadi nilai dan Nilai adalah dua kotak
berbeda.
Tipe yang perlu kamu kuasai untuk OSN:
| Tipe | Isi | Rentang kira-kira |
|---|---|---|
int |
bilangan bulat | −2.147.483.648 … 2.147.483.647 (±2 × 10⁹) |
long long |
bilangan bulat besar | ±9,2 × 10¹⁸ |
double |
bilangan pecahan | ±1,7 × 10³⁰⁸, 15–16 digit berarti |
char |
satu karakter | 'A', 'z', '7' |
bool |
benar atau salah | true atau false |
string |
teks | butuh #include <string> |
Ini sumber nilai nol yang paling sering di OSN: hasil perhitungan
melebihi rentang int, lalu nilainya "berputar" menjadi
angka negatif tanpa pesan error apa pun. Aturan praktis: kalau
hasil mungkin lebih dari 2 × 10⁹, pakai
long long.
int a = 2000000000;
int b = a + a; // meluap, hasilnya negatif
long long c = 2000000000LL + 2000000000LL; // benar: 4000000000Akhiran LL memberi tahu compiler bahwa angka itu sendiri
long long, bukan int yang kemudian disimpan ke
long long.
Kenapa luapan menghasilkan angka negatif
int menempati 4 byte, yaitu 32 bit, dan satu bit dipakai
untuk tanda. Yang muat hanyalah bilangan dari −2.147.483.648 sampai
2.147.483.647. Ketika hasil hitungan melewati ujung atas, nilainya tidak
berhenti di sana melainkan berputar ke ujung bawah,
persis seperti jarum jam yang melewati angka 12 lalu kembali ke 1:
int x = 2147483647; // nilai int terbesar
cout << x + 1 << "\n"; // -2147483648Dua contoh yang paling sering merusak jawaban di lomba:
| Perhitungan | Jawaban benar | Hasil bila disimpan di int |
|---|---|---|
2000000000 + 2000000000 |
4.000.000.000 | −294.967.296 |
50000 * 50000 |
2.500.000.000 | −1.794.967.296 |
1 + 2 + … + 1.000.000 |
500.000.500.000 | 1.784.293.664 |
Perhatikan baris kedua: 50000 sendiri kecil sekali,
tetapi hasil kalinya tidak. Yang menentukan adalah besarnya
hasil, bukan besarnya masukan.
Ada satu jebakan tambahan. Tipe hasil perkalian ditentukan oleh tipe kedua operandnya, bukan oleh tipe kotak tujuannya:
int a = 50000, b = 50000;
long long salah = a * b; // -1794967296: meluap sebelum disalin
long long benar = (long long)a * b; // 2500000000Perkalian a * b dihitung lebih dulu sebagai
int, meluap di situ, baru hasilnya yang sudah rusak disalin
ke long long. Memberi cast pada salah satu sisi
membuat seluruh perkalian dikerjakan sebagai long long.
Kebiasaan yang murah dan menyelamatkan banyak nilai: kalau
ragu, pakai long long. Program yang memakai
long long untuk semua bilangan bulat hanya sedikit lebih
lambat dan sedikit lebih boros memori, sedangkan program yang salah tipe
menghasilkan nol.
Aritmetika
| Operator | Arti | Contoh | Hasil |
|---|---|---|---|
+ |
tambah | 7 + 2 |
9 |
- |
kurang | 7 - 2 |
5 |
* |
kali | 7 * 2 |
14 |
/ |
bagi | 7 / 2 |
3 |
% |
sisa bagi (modulo) | 7 % 2 |
1 |
Perhatikan 7 / 2 menghasilkan 3, bukan
3.5. Kalau kedua sisi bilangan bulat, C++
memakai pembagian bulat: hasil pecahannya dibuang.
Untuk mendapat 3.5, minimal satu sisi harus pecahan:
cout << 7 / 2 << endl; // 3
cout << 7 / 2.0 << endl; // 3.5
cout << (double)7 / 2 << endl;// 3.5Bentuk (double)7 disebut cast: memaksa nilai
dibaca sebagai tipe lain.
Pembagian bulat memotong ke arah nol, jadi 7 / 2 menjadi
3 dan -7 / 2 menjadi -3 (bukan
-4).
double menyimpan bilangan pecahan sebagai hampiran
biner, jadi nilainya tidak selalu tepat:
cout << fixed << setprecision(17) << 0.1 + 0.2 << "\n";0.30000000000000004
Akibatnya, jangan pernah membandingkan dua
double dengan ==:
0.1 + 0.2 == 0.3 bernilai salah. Kalau perbandingan pecahan
benar-benar diperlukan, periksa selisihnya:
if (fabs(a - b) < 1e-9) (fabs ada di
<cmath>). Lebih baik lagi, hindari
double bila soalnya bisa dikerjakan dengan bilangan bulat —
dan sebagian besar soal OSN bisa.
Operator % hanya untuk bilangan bulat, dan sangat sering
dipakai:
cout << 17 % 5 << endl; // 2
cout << 10 % 2 << endl; // 0 -> 10 genap
cout << 123 % 10 << endl; // 3 -> digit terakhir
cout << 123 / 10 << endl; // 12 -> buang digit terakhirDua baris terakhir adalah trik yang dipakai berulang kali di soal OSN untuk memproses angka digit demi digit.
Untuk bilangan negatif, C++ membuat hasil % mengikuti
tanda bilangan yang dibagi: -7 % 3 bernilai
-1, bukan 2. Bab 14 membahas akibatnya dan
cara memperbaikinya.
Urutan pengerjaan
Seperti di matematika, *, /, dan
% dikerjakan lebih dulu daripada + dan
-. Yang setingkat dikerjakan dari kiri ke kanan.
cout << 2 + 3 * 4 << "\n"; // 14, bukan 20
cout << (2 + 3) * 4 << "\n"; // 20
cout << 100 / 10 / 2 << "\n"; // 5 (dibaca (100/10)/2)Di lomba, aturan praktisnya sederhana: kalau ragu, beri kurung. Kurung tambahan tidak memperlambat program sedikit pun, sedangkan salah urutan mengubah jawaban.
Penugasan singkat
int x = 10;
x += 5; // sama dengan x = x + 5 -> 15
x -= 3; // 12
x *= 2; // 24
x /= 5; // 4 (pembagian bulat)
x %= 3; // 1
x++; // 2 (tambah satu)
x--; // 1 (kurang satu)Membaca masukan dengan
cin
cin >> x membaca satu nilai dari masukan standar
dan menyimpannya di x. Spasi, tab, dan pindah baris
sama-sama dianggap pemisah.
int a, b;
cin >> a >> b;
cout << a + b << endl;Bayangkan masukan sebagai satu antrean karakter yang
panjang. Setiap cin >> x melakukan tiga hal
berurutan: melewati semua spasi, tab, dan pindah baris yang ada di
depan; membaca karakter berikutnya selama masih masuk akal untuk tipe
x; lalu berhenti tepat sebelum pemisah berikutnya dan
meninggalkannya di antrean.
Karena spasi dan pindah baris diperlakukan sama, program itu menerima
3 4 maupun:
3
4
Keduanya sama bagi cin.
Urutan pembacaan harus sama persis dengan urutan yang dijanjikan
soal. Kalau soal berkata "baris pertama berisi n, baris
kedua berisi n bilangan", maka n dibaca lebih
dulu, baru sisanya — dan jumlah cin >> yang
dijalankan harus tepat sebanyak angka yang tersedia. Kelebihan satu
cin >> membuat program menunggu masukan yang tidak
akan pernah datang.
cin >> x dengan x bertipe
int akan gagal kalau yang tersedia di
antrean bukan angka. Saat gagal, x tidak terisi dan seluruh
pembacaan berikutnya ikut gagal — biasanya terlihat sebagai program yang
mencetak angka sampah atau tidak mencetak apa pun. Kalau keluaranmu aneh
sejak awal, periksa dulu apakah urutan pembacaannya cocok dengan format
masukan soal.
Format masukan dan keluaran untuk penilai
Di OSN, program dinilai mesin. Karena itu ada aturan ketat:
- Jangan mencetak kalimat pengantar seperti
Masukkan dua bilangan:. Penilai membandingkan keluaranmu karakter demi karakter; kalimat tambahan membuat jawaban dianggap salah. - Cetak persis seperti yang diminta soal, tanpa teks tambahan.
- Spasi atau pindah baris di akhir biasanya dimaafkan, tetapi jangan mengandalkannya.
Jadi untuk soal "baca dua bilangan, cetak jumlahnya", jawaban yang benar adalah persis:
#include <iostream>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << a + b << "\n";
return 0;
}Saat menjalankannya di komputer sendiri, ketik angkanya lalu tekan Enter; layar akan terlihat kosong sampai kamu memasukkan semua angka yang diminta. Itu normal.
Buka
exercises/03/03-masukan.cpp,
compile, lalu jalankan dan ketik 10 3 diikuti Enter.
Perhatikan hasil / dan % untuk kedua angka
itu.
Membaca teks satu baris
cin >> nama berhenti di spasi pertama, jadi
Budi Santoso hanya terbaca Budi. Untuk membaca
satu baris penuh, pakai getline:
string baris;
getline(cin, baris);Kalau getline dipakai sesudah
cin >> n, baris pertama yang terbaca sering kosong:
cin >> meninggalkan karakter pindah baris di masukan.
Perbaikannya: panggil cin.ignore(); sebelum
getline.
Membaca sampai masukan habis
Sebagian soal tidak memberi tahu ada berapa angka. Pola bakunya:
int x;
while (cin >> x) {
// proses x
}cin >> x bernilai salah ketika masukan sudah
habis, jadi perulangannya berhenti sendiri.
Mencetak bilangan pecahan
Secara bawaan cout mencetak double dengan
enam digit berarti. Soal sering meminta jumlah angka di belakang koma
tertentu:
#include <iomanip>
double rata = 7.0 / 3.0;
cout << fixed << setprecision(2) << rata << endl; // 2.33fixed berarti "hitung digit setelah koma",
setprecision(2) menetapkan dua digit. Keduanya cukup
ditulis sekali; pengaruhnya berlaku untuk semua pencetakan
berikutnya.
Buka
exercises/03/04-pecahan.cpp.
Ubah setprecision(2) menjadi setprecision(6),
compile ulang, dan bandingkan keluarannya.
Pekerjaan rumah
Soal 1 — Jumlah dua bilangan
Buka
exercises/03/homework/01-jumlah-dua.cpp.
Baca dua bilangan bulat dari masukan standar, cetak jumlahnya. Tanpa
kalimat pengantar apa pun. Ini bentuk soal termudah yang ada di penilai
daring — pastikan kamu bisa mengirimkannya dengan benar.
Soal 2 — Rata-rata tiga nilai
Buka
exercises/03/homework/02-rata-rata.cpp.
Baca tiga bilangan bulat, cetak rata-ratanya dengan dua angka di
belakang koma. Hati-hati pembagian bulat.
Soal 3 — Ubah detik
Buka
exercises/03/homework/03-detik.cpp.
Baca satu bilangan bulat berisi jumlah detik, cetak dalam bentuk
jam menit detik dipisahkan spasi. Contoh: masukan
3725 menghasilkan 1 2 5. Pakai /
dan %.
Soal 4 — Digit terakhir dan sisanya
Buka
exercises/03/homework/04-digit.cpp.
Baca satu bilangan bulat positif, cetak dua baris: digit terakhirnya,
lalu bilangan itu tanpa digit terakhir. Contoh: masukan
4071 menghasilkan 1 lalu 407.
Tantangan — Deteksi luapan
Buka
exercises/03/homework/05-luapan.cpp.
File berisi perkalian dua bilangan besar yang hasilnya salah karena
disimpan di int. Jalankan dulu, catat hasil salahnya, lalu
perbaiki dengan long long sehingga keluarannya benar.
Tuliskan hasil sebelum dan sesudah perbaikan sebagai komentar di bagian
atas file.
Kesalahan yang paling sering
| Yang ditulis | Akibatnya |
|---|---|
int untuk hasil yang melebihi 2 × 10⁹ |
jawaban negatif tanpa pesan error apa pun |
long long x = a * b; dengan a,
b bertipe int |
meluap sebelum disalin; beri cast |
int rata = jumlah / n; |
pecahannya terbuang; pakai (double)jumlah / n |
if (a == b) pada dua double |
hampir selalu salah; bandingkan selisihnya |
cout << "Masukkan n: "; |
keluaran tambahan membuat penilai menyatakan salah |
getline langsung sesudah
cin >> n |
terbaca baris kosong; panggil cin.ignore() dulu |
| variabel dipakai sebelum diisi | nilai sampah, hasil berbeda tiap dijalankan |
Tips OSN
Baca batasan sebelum menulis kode. Bagian
Batasan pada soal OSN bukan hiasan: dari situlah tipe data
ditentukan. Urutannya selalu sama — lihat nilai terbesar yang mungkin
muncul, perkirakan hasil terbesarnya, baru pilih tipe. Yang menentukan
adalah besarnya hasil, bukan besarnya masukan: dua
bilangan int yang dikalikan sudah bisa melewati batas
int.
| Batasan pada soal | Tipe yang aman untuk hasilnya |
|---|---|
| jawaban ≤ 2 × 10⁹ | int |
| jawaban ≤ 9 × 10¹⁸ | long long |
| jawaban berupa pecahan | double dengan setprecision |
Luapan tidak memberi pesan error. Program yang
meluap tetap berjalan, tetap mencetak angka, dan tetap dinilai Wrong
Answer. Kalau jawabanmu tiba-tiba negatif pada uji berbatasan besar
padahal logikanya benar, tersangka pertama selalu int.
Hati-hati pada perkalian setengah jalan. Menyimpan
hasil ke long long tidak menolong kalau perkaliannya
sendiri dilakukan sebagai int:
int p = 1000000, l = 1000000;
long long luas = p * l; // salah: p * l dihitung sebagai int
long long benar = (long long)p * l; // benarCara paling aman di lomba: kalau ada kemungkinan sedikit saja
hasilnya besar, deklarasikan variabelnya long long sejak
awal. Biaya kecepatannya tidak berarti; biaya salah jawab jauh lebih
mahal.
Jangan memakai double untuk jawaban bilangan
bulat. double hanya tepat sampai sekitar 15 digit
berarti, jadi jawaban bulat besar bisa tercetak sebagai
1e+18. Pakai double hanya kalau soal memang
meminta pecahan, dan selalu dengan
fixed << setprecision(k) sesuai permintaan soal.
Soal menyebut berapa digit desimal yang diminta.
Kalau soal meminta dua angka di belakang koma, mencetak
82.5 dinilai salah walaupun nilainya sama.
fixed << setprecision(2) membuat 82.5
tercetak 82.50.
Soal yang meminta jawaban pecahan sering menyertakan kalimat "jawaban
dianggap benar jika selisihnya dengan jawaban juri tidak lebih dari
10⁻⁶". Kalimat itu berarti pembulatan kecil dimaafkan — tetapi format
keluarannya tetap harus sesuai. Baca bagian format keluaran sampai habis
sebelum menentukan setprecision.
Ringkasan
- Variabel adalah kotak berlabel; tipenya menentukan isi dan ukurannya.
intaman sampai sekitar ±2 × 10⁹; di atas itu pakailong long. Yang menentukan adalah besarnya hasil, bukan besarnya masukan./antara dua bilangan bulat membuang pecahannya;%memberi sisanya.n % 10dann / 10adalah pasangan untuk memproses digit.doubletidak tepat; jangan dibandingkan dengan==.cin >>melewati semua spasi dan pindah baris, lalu membaca satu nilai.- Program untuk penilai membaca dari masukan standar dan mencetak hanya jawaban yang diminta.
fixeddansetprecision(k)dari<iomanip>menetapkan banyaknya digit di belakang koma.
Latihan bergaya OSN
Tiga soal berikut sudah memakai masukan standar, persis seperti soal sungguhan. Uji jawabanmu dengan mengalirkan masukan dari terminal:
echo "10 7 3" | ./ubin
Kerangka ketiganya ada di
exercises/03/osn/.
Soal 1 — Ubin Lantai
Sebuah ruangan berbentuk persegi panjang berukuran P ×
L sentimeter akan dipasangi ubin berbentuk persegi dengan
sisi S sentimeter. Ubin dipasang mulai dari salah satu
sudut ruangan, sejajar dinding, dan tidak boleh
dipotong. Sisa lantai di tepi ruangan yang tidak tertutup ubin
utuh akan ditutup semen.
Hitung berapa ubin utuh yang terpasang dan berapa luas lantai yang harus ditutup semen.
Format masukan. Satu baris berisi tiga bilangan
bulat P, L, dan S.
Format keluaran. Satu baris berisi dua bilangan bulat: banyaknya ubin utuh, lalu luas sisa lantai dalam sentimeter persegi, dipisahkan satu spasi.
Batasan.
- 1 ≤
P,L≤ 10⁹ - 1 ≤
S≤ 10⁹
Contoh masukan
10 7 3
Contoh keluaran
6 16
Penjelasan. Ke arah panjang muat 10 / 3 = 3 ubin, ke arah lebar muat 7 / 3 = 2 ubin, jadi seluruhnya 3 × 2 = 6 ubin. Luas ruangan 10 × 7 = 70, luas tertutup 6 × 3 × 3 = 54, sisanya 70 − 54 = 16.
Kerangkanya:
exercises/03/osn/01-ubin-lantai.cpp
Soal 2 — Nilai Akhir
Nilai akhir satu mata pelajaran dihitung dari tiga komponen dengan bobot tetap: nilai tugas 30%, nilai UTS 30%, dan nilai UAS 40%.
Format masukan. Satu baris berisi tiga bilangan bulat: nilai tugas, nilai UTS, dan nilai UAS.
Format keluaran. Satu baris berisi nilai akhir dengan tepat dua digit di belakang koma.
Batasan. Ketiga nilai berada di antara 0 dan 100.
Contoh masukan
80 75 90
Contoh keluaran
82.50
Penjelasan. 0,3 × 80 + 0,3 × 75 + 0,4 × 90 = 24 +
22,5 + 36 = 82,5. Karena soal meminta dua digit di belakang koma,
jawabannya ditulis 82.50, bukan 82.5.
Kerangkanya:
exercises/03/osn/02-nilai-akhir.cpp
Soal 3 — Deret Aritmetika
Sebuah deret aritmetika dimulai dari suku pertama a dan
setiap suku berikutnya bertambah b dari suku sebelumnya.
Tentukan suku ke-n dan jumlah n suku
pertamanya.
Format masukan. Satu baris berisi tiga bilangan
bulat a, b, dan n.
Format keluaran. Satu baris berisi dua bilangan
bulat: suku ke-n dan jumlah n suku pertama,
dipisahkan satu spasi.
Batasan.
- −10⁶ ≤
a,b≤ 10⁶ - 1 ≤
n≤ 10⁶ - Kerjakan tanpa perulangan.
Contoh masukan
3 5 4
Contoh keluaran
18 42
Penjelasan. Deretnya 3, 8, 13, 18. Suku keempatnya 18, dan 3 + 8 + 13 + 18 = 42.
Larangan memakai perulangan di soal ini bukan gaya soal OSN — di OSN
yang dibatasi adalah waktu berjalan, bukan cara menulisnya. Larangan itu
dipasang karena perulangan baru dibahas di Bab 05, dan karena rumus
deret memang jawaban yang lebih baik: ia tetap cepat walaupun
n dinaikkan menjadi 10¹⁸.
Kerangkanya:
exercises/03/osn/03-deret-aritmetika.cpp
Bingung atau sudah selesai? Buka halaman pembahasan PR.