getline C++: read line from stream

Hey there! In this article, we’re diving into the std::getline function from C++‘s standard library. This function lets us read a line from any input stream.

We’ll kick things off by exploring different ways to use this function. We’ll also touch on the possible errors it can throw our way. And to wrap things up, I’ve got some exercises to make sure you really get the hang of things.

Illustration of getline in C++

Using getline to read a line from a stream

getline is part of the <string> header file. It comes in two flavors:

istream& getline (istream& is, string& str);
istream& getline (istream& is, string& str, char delim);

This function will read the is stream until it reaches the delimiter. By default, it’s the newline character \n, but you can specify a different one with delim.

Whatever getline reads, it’ll store in the str argument, which is of the std::string type. Be cautious though, anything previously in that string will be replaced with what’s read from the input stream is.

The function then returns the stream it read the line from, which is our first parameter is.

Let’s see this function in action:

#include <iostream>
using namespace std;

int main() {
  string input;

  getline(cin, input);

  cout << "input = \"" << input << "\"" << endl;

  return 0;
}

Program output:

reading to the end of the line
input = "reading to the end of the line"

In this simple example, we read the first line from the standard input. Here, it’s "reading to the end of the line".

Want to switch things up? You can change the character you read up to:

#include <iostream>
using namespace std;

int main() {
  string input;

  getline(cin, input, ';');

  cout << "input = \"" << input << "\"" << endl;

  return 0;
}
first part; second part
input = "first part"

Here, we added a third argument, ';'. That’s why we only got whatever was before the semicolon.

You can even read multiple lines with a single getline call:

first 
part; 
input = "first
part"

Here, getline kept reading, even after the first line ended, and a new one began.

Under what circumstance will the following program output “Read successfully”?

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int main() {
  string input;
  ifstream file("text.txt");
  
  getline(file, input, '*');

  if(input == "test")
    cout << "Read successfully" << endl;
  else
    cout << "Read error" << endl;

  return 0;
}

Assuming the text.txt file exists and is readable, what should its content be?

test*rest of the file
test;
testing
*test

In the examples above, we read a line from the standard input. But getline isn’t picky. It lets us read from any stream. Now, let’s see how to get a line from a file.

Reading from a file with getline

Since getline can read from any input stream, let’s pair it up with the ifstream class to read from a file:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
  ifstream shows_file("shows.txt");
  string show;

  getline(shows_file, show);

  cout << "show = \"" << show << "\"" << endl;

  return 0;
}

shows.txt:

Rick and Morty
Stranger Things
Game of Thrones

Program output:

show = "Rick and Morty"

Above, we swapped out getline’s first argument from cin (standard input stream) to shows_file (file input stream).

Using while loop with getline

Why stop at the first show? Let’s read all the lines from the shows.txt file. You can do this using the while loop:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
  ifstream shows_file("shows.txt");
  string show;

  while (getline(shows_file, show)) {
    cout << "show = \"" << show << "\"" << endl;
  }

  return 0;
}

shows.txt:

Rick and Morty
Stranger Things
Game of Thrones
show = "Rick and Morty"
show = "Stranger Things"
show = "Game of Thrones"

As you can see, to read the entire file, you can simply use the return value of getline as the condition for the while loop. This works because ifstream supports casting to bool.

When converting to bool, ifstream returns true if reading can continue and false if it can’t:

cout << "can read: " << (bool)shows_file << endl;

while (getline(shows_file, show)) {
  cout << "show = \"" << show << "\"" << endl;
}

cout << "can read: " << (bool)shows_file << endl;

As expected, we can’t continue reading after “Game of Thrones” (nothing follows it in the file).

Errors when working with getline

Errors can always occur when dealing with input streams. To understand what went wrong, you can check the stream’s flags:

  1. stream.good(): returns true if all went well.
  2. stream.eof(): input stream ended.
  3. stream.fail(): there was an error or the read data can’t be interpreted as a string.
  4. stream.bad(): an error occurred.

Let’s add error checking to our example above:

#include <fstream>
#include <iostream>
using namespace std;

int main() {
  ifstream shows_file("shows.txt");
  string show;

  while (getline(shows_file, show)) {
    cout << "show = \"" << show << "\"" << endl;
  }

  if (shows_file.bad()) {
    cout << "Something went wrong. 😭" << endl;
  }

  return 0;
}

Now, if there’s an error, you’ll see the message in the console:

show = "Rick and Morty"
show = "Stranger Things"
Something went wrong. 😭

Sample program using getline

Imagine wanting to create a todo-list program. Users can input their tasks, and the program will display them. We’ll use std::getline to get tasks from users:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main() {
  vector<string> todo_list;  // Storing the task list
  string input;              // Temporary string for user input

  cout << "Welcome to the ToDo List program!" << endl;
  cout << "Enter your tasks. Type 'exit' to stop." << endl;

  // Infinite loop for task input until the user types 'exit'
  while (true) {
    cout << "New task: ";
    getline(cin, input);  // Getting a line from the user

    if (input == "exit") {
      break;  // Exit the loop if 'exit' is typed
    }

    todo_list.push_back(input);  // Add the task to the list
  }

  cout << "\nYour task list:" << endl;
  for (int i = 0; i < todo_list.size(); i++) {
    cout << i + 1 << ". " << todo_list[i] << endl;  // Display user tasks
  }

  return 0;
}

This example shows how you can use std::getline to read lines from the console. You can also adapt this code to read data from files or other input sources.

Exercises for getline

  1. Simple data input using getline:
    Write a C++ program that prompts the user for their first and last name. Use the getline function to read the data. Afterwards, the program should display a greeting with the user’s full name. For instance, “Hello, [First Name Last Name]!“.

  2. Using getline with a delimiter:
    Modify the program from the first point so that the user enters their first and last name separated by a semicolon. Your task is to read the input data and split it into first and last names using getline with the appropriate delimiter.

  3. Reading from a file using getline:
    Create a text file named students.txt with student names, each on a new line. Write a program that reads all the names from the file and displays them in the format: “Student [number]: [Name]“.

Discussion

© 2023, codelessons.dev