Read text file into string array (fstream)

Oct 5, 2019 at 12:49am
closed account (iy64Nwbp)
Hi guys.
I'm trying to figure out a way in which to read a text file into a string array. The text file holds six different cities with 3 being origin cities and 3 being the destination. Text file looks something like this:

Albuquerque, San Diego
Albuquerque, Paris
San Diego, Chicago

What I'm trying to figure out is a way to store all of them into a string array. From there I'm confused on how to make Albuquerque, Albuquerque and San Diego as the origin cities using a string variable. Same with San Diego, Paris and Chicago but as the destination cities. I feel a for loop would work well to store the cities into a string array.

This is what i have so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  fstream requestedRoutes;
  string originCity, destinationCity;
  bool correctPath;

  requestedRoutes.open("requestFile.txt", ios::in);
  char test;
  if (requestedRoutes.is_open()) {
	while (!requestedRoutes.eof()) {
		getline(requestedRoutes, originCity, ',');
			
		requestedRoutes.get(test);

		while (requestedRoutes.peek() == ' ') {
			requestedRoutes.get(test);
		}
		getline(requestedRoutes, destinationCity, '\n');
Oct 5, 2019 at 7:53am
Alas, your textbook/website/teacher has failed you badly here. Just about everything in that is wrong. (Sorry!)

Here you go (compile with C++17 enabled):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <ciso646>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>

// Helpful type alias
typedef std::unordered_multimap <std::string, std::string> Routes;

// Helpful function
std::string trim( const std::string& s )
{
  auto n = s.find_first_not_of( " \t" );
  if (n == s.npos) return "";
  return s.substr( n, s.find_last_not_of( " \t" ) + 1 - n );
}

int main()
{
  Routes requestedRoutes;
  {
    std::ifstream f{ "requestFile.txt" };
    while (true)
    {
      std::string originCity;
      if (!getline( f, originCity, ',' )) break;

      std::string destinationCity;
      if (!getline( f, destinationCity )) break;
      
      if (trim( originCity ).empty() or trim( destinationCity ).empty()) continue;

      requestedRoutes.emplace( trim( originCity ), trim( destinationCity ) );
    }
  }

  // Tada! Now you have an origin→destination city mapping.
  // Let’s print it out just for kicks:
  for (auto [originCity, destinationCity] : requestedRoutes)
    std::cout << trim( originCity ) << ", " << trim( destinationCity ) << "\n";
}

The important parts are:

  • Have a definite structure to store your cities.
    I used a multimap, which is designed exactly for these kinds of problems.

  • Keep your file streams as local objects in a local block. (Notice the curly braces.)
    When the file stream goes out of scope it will close automatically.

  • Don’t bother testing if the file is open. All I/O will fail if it is not open.

  • Don’t loop on EOF. This will get you a failure result in your list. Why?
    Because you did not test for failure immediately after an attempted read. Which leads us to:

  • Always test for failure after an attempted read. Since we are attempting to read TWO
    things with getline, and to better illustrate what is happening, I put both read attempts
    inside the loop and tested immediately for termination.

  • Only AFTER failure has NOT occurred do we mess with the extracted value(s).

So the basic construct is:

  1 Try to get originCity, bail if stream failure (due to EOF, probably)
  2 Try to get destinationCity, bail if stream failure (due to EOF, probably)
  3 Check that both cities are valid (not empty strings)
  4 Add the cities to the requestedRoute mapping

Hope this helps.
Last edited on Oct 5, 2019 at 7:54am
Topic archived. No new replies allowed.