Menu

getline C++: Membaca Satu Baris, Input Terlewat, dan Membaca File

Cara std::getline membaca satu baris penuh ke dalam std::string: memakainya dengan cin, kenapa ia mengembalikan string kosong setelah cin >>, perbaikan dengan cin.ignore dan std::ws, delimiter sendiri, dan membaca file baris demi baris sampai akhir file.

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

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);
  • input adalah stream input apa pun: std::cin, file yang dibuka dengan std::ifstream, atau std::istringstream yang dibuat dari sebuah string.
  • text diganti (bukan ditambahkan) dengan karakter yang dibaca.
  • delim adalah karakter yang mengakhiri pembacaan. Default-nya '\n'. Delimiter dibuang dari stream dan tidak disimpan di text.
  • 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 2 tanpa \n, getline tetap 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 >> dan getline tanpa membuang baris baru. Tambahkan ignore(...) atau pakai std::ws di antara keduanya. Halaman input dan output menunjukkan masalah yang sama dengan std::cin dan cara memulihkannya saat pembacaan angka gagal.
  • Memanggil getline(std::cin, number) dengan int. getline hanya membaca ke dalam std::string. Baca barisnya, lalu konversi dengan std::stoi atau std::istringstream.
  • Melakukan perulangan berdasarkan eof(). Uji pemanggilan getline itu sendiri: while (std::getline(input, line)).
  • Lupa #include <string>. std::getline untuk 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::ifstream gagal 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.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai