Membaca Satu Baris Penuh
cin >> text membaca satu kata: ia berhenti di spasi pertama. Untuk membaca semua yang diketik pengguna sampai tombol Enter, termasuk spasinya, pakai std::getline dari header <string>:
#include <iostream>
#include <string>
int main() {
std::string name;
std::cout << "Full name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << "!\n";
}
Mengetik Ada Lovelace akan mencetak Hello, Ada Lovelace!. Dengan std::cin >> name yang tercetak adalah Hello, Ada! dan Lovelace tertinggal menunggu di input.
Signature-nya:
std::istream& std::getline(std::istream& input, std::string& text);
std::istream& std::getline(std::istream& input, std::string& text, char delim);
inputadalah stream input apa pun:std::cin, file yang dibuka denganstd::ifstream, ataustd::istringstreamyang dibuat dari sebuah string.textdiganti (bukan ditambahkan) dengan karakter yang dibaca.delimadalah karakter yang mengakhiri pembacaan. Default-nya'\n'. Delimiter dibuang dari stream dan tidak disimpan ditext.- Nilai kembaliannya adalah stream itu sendiri, dan itulah yang membuatmu bisa mengujinya dalam sebuah kondisi.
Karena getline bekerja sama pada setiap stream input, contoh yang bisa dijalankan di halaman ini membaca dari std::istringstream berisi teks tetap. Dengan begitu output-nya bisa ditebak tanpa perlu mengetik apa pun. Untuk membaca dari keyboard, ganti variabel stream-nya dengan std::cin.
Output:
[Ada Lovelace]
[Alan Turing]
Kurung siku menunjukkan bahwa baris baru bukan bagian dari kedua string itu.
getline Setelah cin >> Mengembalikan String Kosong
Inilah masalah getline yang paling umum. Kamu membaca angka dengan >>, lalu satu baris dengan getline, dan getline itu seolah dilewati:
Output:
age: 30
city: []
input >> age membaca karakter 30 dan berhenti di karakter pertama yang tidak bisa menjadi bagian dari angka, yaitu baris baru. Baris baru itu tetap tertinggal di stream. getline lalu membaca sampai baris baru berikutnya, langsung menemukannya, dan mengembalikan string kosong. Dengan std::cin, akibatnya program tidak pernah berhenti untuk menunggu jawaban kedua.
Ada dua perbaikan standar. Keduanya ditaruh di antara >> dan getline.
Perbaikan 1: buang sisa baris dengan ignore.
Output:
age: 30
city: [Paris]
ignore(n, '\n') membuang karakter sampai ia membuang satu baris baru atau n karakter, mana yang lebih dulu tercapai. Memberikan std::streamsize terbesar yang mungkin berarti "sampai baris baru, sejauh apa pun letaknya". Ini juga membuang apa pun yang diketik pengguna setelah angka di baris yang sama, seperti spasi di belakangnya. Untuk keyboard, barisnya adalah std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, dan butuh #include <limits>.
std::cin.ignore() tanpa argumen membuang tepat satu karakter. Ini berhasil kalau baris baru langsung mengikuti angka, dan gagal begitu ada spasi sebelumnya.
Perbaikan 2: lewati whitespace di depan dengan std::ws.
Output:
age: 30
city: [Paris]
std::ws adalah manipulator yang menghabiskan semua whitespace (spasi, tab, baris baru) di posisi saat ini. input >> std::ws mengembalikan stream-nya, jadi bisa langsung dimasukkan ke getline. Ia juga melewati baris kosong dan spasi di depan, yang praktis untuk nama dan kota, tetapi salah kalau spasi di depan atau baris kosong adalah input yang bermakna. Dalam kasus itu, pakai ignore.
Membaca Sampai Akhir Input
getline mengembalikan stream-nya, dan sebuah stream dikonversi menjadi false begitu pembacaan gagal. Saat tidak ada baris lagi, getline gagal, jadi while loop di sekelilingnya membaca setiap baris dan berhenti di akhir:
Output:
1: [apples 3]
2: [bread 1]
3: []
4: [milk 2]
read 4 lines
Ada dua detail dari output itu:
- Baris kosong tetap dihitung sebagai pembacaan yang berhasil. Hasilnya string kosong dan loop terus berjalan. Hanya mencapai akhir input yang menghentikannya.
- Baris terakhir tidak butuh baris baru di belakangnya. Kalau teksnya diakhiri
milk 2tanpa\n,getlinetetap mengembalikannya, dan pemanggilan berikutnya akan gagal.
Dengan std::cin, loop yang sama membaca sampai input berakhir. Itu terjadi saat input dialirkan dari file (./program < data.txt), atau saat pengguna menekan Ctrl+D di macOS dan Linux, atau Ctrl+Z lalu Enter di Windows.
Hindari pola while (!input.eof()) { std::getline(input, line); ... }. eof() baru bernilai true setelah sebuah pembacaan sudah menabrak akhir input, jadi isi loop berjalan satu kali ekstra dengan pembacaan yang gagal dan line yang usang. Taruh pemanggilan getline di dalam kondisi.
Membaca File Baris demi Baris
File memakai loop yang sama. Buka file dengan std::ifstream dari <fstream>, cek bahwa file berhasil terbuka, lalu baca:
Output:
1. Ada 92
2. Grace 88
3. Alan 95
if (!file) menangkap file yang tidak ada atau path yang salah sebelum loop. Tanpa itu, loop hanya membaca nol baris, yang terlihat seperti file kosong alih-alih sebuah error. File tertutup otomatis saat file keluar dari scope di akhir main.
File yang disimpan di Windows mengakhiri setiap baris dengan \r\n. Saat file seperti itu dibaca di Linux atau macOS, getline membuang \n tetapi mempertahankan \r, sehingga setiap baris diakhiri carriage return yang tidak terlihat dan merusak perbandingan seperti line == "done". Buang karakter itu setelah membaca:
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
Memakai Delimiter Sendiri
Argumen ketiga mengganti karakter yang mengakhiri setiap pembacaan. Pemakaian yang umum adalah memecah satu baris berdasarkan koma. Baca barisnya dulu, lalu pecah lewat std::istringstream:
Output:
fields: 3
[Ada Lovelace]
[36]
[London]
Koma dibuang dari stream dan tidak disimpan, sama seperti baris baru pada bentuk default-nya. Perhatikan bahwa dengan delimiter sendiri, baris baru menjadi karakter biasa. Kalau kamu memanggil std::getline(file, field, ',') langsung pada file yang berisi banyak baris, field terakhir dari satu baris dan field pertama dari baris berikutnya akan kembali tergabung, seperti "London\nGrace Hopper". Membaca satu baris setiap kali lalu memecah setiap baris secara terpisah menghindari masalah itu. Halaman string stream membahas std::istringstream lebih mendalam, termasuk mengonversi field seperti "36" menjadi angka.
std::getline vs cin.getline
Ada juga member function dengan nama yang mirip:
char buffer[20];
std::cin.getline(buffer, 20); // member function, fixed-size char array
std::string text;
std::getline(std::cin, text); // free function, std::string
cin.getline menulis ke dalam array char dan menyimpan paling banyak size - 1 karakter plus penutup '\0'. Baris yang lebih panjang membuat stream masuk ke keadaan gagal, dan setiap pembacaan sesudahnya dilewati sampai kamu memanggil std::cin.clear(). std::getline dengan std::string tidak punya batas panjang yang perlu diurus. Pakai itu kecuali kamu bekerja dengan API yang mewajibkan array char.
Kesalahan Umum
- Mencampur
>>dangetlinetanpa membuang baris baru. Tambahkanignore(...)atau pakaistd::wsdi antara keduanya. Halaman input dan output menunjukkan masalah yang sama denganstd::cindan cara memulihkannya saat pembacaan angka gagal. - Memanggil
getline(std::cin, number)denganint.getlinehanya membaca ke dalamstd::string. Baca barisnya, lalu konversi denganstd::stoiataustd::istringstream. - Melakukan perulangan berdasarkan
eof(). Uji pemanggilangetlineitu sendiri:while (std::getline(input, line)). - Lupa
#include <string>.std::getlineuntuk string dideklarasikan di<string>. Beberapa compiler membiarkannya lolos lewat<iostream>, lalu kodenya gagal di compiler lain. - Tidak mengecek apakah file berhasil terbuka. Path yang salah membuat
std::ifstreamgagal diam-diam dan loop pembacaan berjalan nol kali.
Pertanyaan yang sering diajukan
Apa fungsi getline di C++?
std::getline(stream, text) membaca karakter dari stream ke dalam std::string text sampai bertemu baris baru, lalu membuang baris baru itu dari stream tanpa menyimpannya. Berbeda dengan cin >> text, getline mempertahankan spasi, jadi ia membaca satu baris utuh seperti nama lengkap atau sebuah kalimat.
Kenapa getline terlewat setelah cin >> di C++?
cin >> number berhenti membaca di baris baru yang kamu ketik setelah angka, dan meninggalkan baris baru itu di buffer input. getline berikutnya langsung menemukannya dan mengembalikan string kosong. Buang dulu dengan std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');, atau panggil std::getline(std::cin >> std::ws, text) untuk melewati whitespace di depannya.
Bagaimana cara memakai getline dengan delimiter selain baris baru?
Berikan delimiter sebagai argumen ketiga: std::getline(stream, field, ','). Fungsi ini membaca sampai koma berikutnya, menyimpan teks sebelumnya, dan membuang komanya. Baris baru lalu diperlakukan sebagai karakter biasa, jadi cara ini biasanya dipadukan dengan std::stringstream yang dibuat dari satu baris.
Bagaimana cara membaca file baris demi baris di C++?
Buka file dengan std::ifstream file("data.txt"); lalu lakukan perulangan dengan while (std::getline(file, line)) { ... }. getline mengembalikan stream-nya, yang dikonversi menjadi false begitu tidak ada baris lagi, jadi loop berhenti di akhir file.
Apa perbedaan cin.getline dan getline?
std::getline(std::cin, text) adalah fungsi bebas yang membaca ke dalam std::string, yang bisa membesar untuk menampung baris sepanjang apa pun. std::cin.getline(buffer, size) adalah member function yang membaca ke dalam array char berukuran tetap dan gagal kalau barisnya lebih panjang dari size - 1 karakter. Pakai std::getline dengan std::string kecuali kamu punya alasan untuk memakai array mentah.