PPP2 Chapter 11 Exercise 13

Okay, here's another one. Reading a text file and then writing out the words in reverse order. I'm having trouble printing out the words in reverse order. How do I read strings from a file in reverse order them in a vector? Maybe that'll help.

Anyway, this is what I have right now (I've included the Exercise Specs in comments at the top of the file, as always):
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
42
43
44
45
46
47
48
49
50
// chapter11ex13.cpp : Defines the entry point for the console application.
// Osman Zakir
// 3 / 9 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 13
// Exercise Specifications:
/**
 * Reverse the order of words (defined as whitespace-separated strings) in a
 * file. For example, Norwegian Blue parrot becomes parrot Blue Norwegian .
 * You are allowed to assume that all the strings from the file will fit into
 * memory at once.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>

int main()
{
	using namespace std;
	cout << "Please enter name of input file: ";
	string ifname;
	cin >> ifname;
	ifstream ifs{ ifname };
	if (!ifs)
	{
		cout << "Error: cannot open input file " << ifname << '\n';
		keep_window_open();
		return 1;
	}

	string file_input;
	vector<string> input_vector;
	while (getline(ifs, file_input))
	{
		input_vector.push_back(file_input);
		reverse(input_vector.begin(), input_vector.end());
	}

	for (auto i = input_vector.rbegin(); i != input_vector.rend(); ++i)
	{
		
		cout << *i;
	}
	cout << '\n';
	keep_window_open();
}


Right now, the input file's contents are printed out as is.
draw the flow diagram, let's start from there.


> Reverse the order of words (defined as whitespace-separated strings)
¿where are you getting each word?
you're reading the whole line but you need to read it in word by word so that you can reverse it later on. so stringstream the line, stream >> temp_string (which parses on whitespace), push_back(temp_string) into std::vector<std::string> and then apply the reverse iterators to print
@gunnerfunner: Great advice, thanks. I'll see if I can do that without asking for further help (I'll try to finish it myself, but if I can't, I'll try asking again).

So basically I need to define an istringstream and read words with it one by one in a loop, and then push them back into the vector?

@me555: I have an input file. It's a really short file, though:
The Norwegian Blue parrot is a parrot that, obviously, would be from Norway if it existed.


Edit: Okay, I did it without istrinstream since I didn't get how to do that while also actually reading from the input file I want to read from. This is my current code (and it works perfectly as far as I can see):
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// chapter11ex13.cpp : Defines the entry point for the console application.
// Osman Zakir
// 3 / 9 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 13
// Exercise Specifications:
/**
 * Reverse the order of words (defined as whitespace-separated strings) in a
 * file. For example, Norwegian Blue parrot becomes parrot Blue Norwegian .
 * You are allowed to assume that all the strings from the file will fit into
 * memory at once.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> fill_v(std::istream &is);
void print_strings_v(const std::vector<std::string> &str_v);

int main()
{
	using namespace std;
	cout << "Please enter name of input file: ";
	string ifname;
	cin >> ifname;
	ifstream ifs{ ifname };
	if (!ifs)
	{
		cout << "Error: cannot open input file " << ifname << '\n';
		keep_window_open();
		return 1;
	}
	vector<string> input_v = fill_v(ifs);
	print_strings_v(input_v);
	keep_window_open();
}

std::vector<std::string> fill_v(std::istream &is)
{
	using namespace std;
	string input;
	vector<string> input_v;
	while (is >> input)
	{
		input_v.push_back(input);
	}
	return input_v;
}

void print_strings_v(const std::vector<std::string> &str_v)
{
	using namespace std;
	for (auto i = str_v.rbegin(); i != str_v.rend(); ++i)
	{
		cout << *i << ' ';
	}
	cout << '\n';
}


Anyone have a long input file I can test this baby out on?
Last edited on
closed account (48T7M4Gy)
Anyone have a long input file I can test this baby out on?


Why not just find a suitable amount on an online newspaper and cut and paste into a .txt file.
Maybe try an ebook at Gutenberg.org
to avoid reallocation of the vector during read what's the best way to reserve vector memory at the outset, depending on the file size?
the example here http://www.cplusplus.com/reference/istream/istream/tellg/ suggests a char array depending on the file size but how'd that translate to std::vector<std::string> as we're using in this case?
How would I specify the size of a vector beforehand?
How would I specify the size of a vector beforehand?

this is quite easily done but the question I raised was how to get this size before-hand:
1
2
3
4
5
6
7
8
9
#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::vector<std::string> myVec(1000);
    std::cout << myVec.size()<<"\n";
}
Actually Dragon it might be better to use the reserve() method just to allocate memory to prevent future reallocations. Giving an initial size to the vector means any subsequent push_back or emplace_back would start from the end of the sized vector:
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::vector<std::string> myVec{};
    myVec.reserve(1000);
    std::cout << myVec.size()<<"\n";//prints 0
}
So, like this?
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// chapter11ex13.cpp : Defines the entry point for the console application.
// Osman Zakir
// 3 / 9 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 11 Exercise 13
// Exercise Specifications:
/**
 * Reverse the order of words (defined as whitespace-separated strings) in a
 * file. For example, Norwegian Blue parrot becomes parrot Blue Norwegian .
 * You are allowed to assume that all the strings from the file will fit into
 * memory at once.
 */

#include "../../cust_std_lib_facilities.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> fill_v(std::istream &is);
void print_strings_v(const std::vector<std::string> &str_v);

int main()
{
	using namespace std;
	cout << "Please enter name of input file: ";
	string ifname;
	cin >> ifname;
	ifstream ifs{ ifname };
	if (!ifs)
	{
		cout << "Error: cannot open input file " << ifname << '\n';
		keep_window_open();
		return 1;
	}
	ifs.seekg(0, ifs.end);
	size_t length = ifs.tellg();
	ifs.seekg(0, ifs.beg);
	vector<string> input_v;
	input_v.reserve(length);
	input_v = fill_v(ifs);
	print_strings_v(input_v);
	keep_window_open();
}

std::vector<std::string> fill_v(std::istream &is)
{
	using namespace std;
	string input;
	vector<string> input_v;
	while (is >> input)
	{
		input_v.push_back(input);
	}
	return input_v;
}

void print_strings_v(const std::vector<std::string> &str_v)
{
	using namespace std;
	for (auto i = str_v.rbegin(); i != str_v.rend(); ++i)
	{
		cout << *i << ' ';
	}
	cout << '\n';
}


By the way, how much of a chance do you guys think there is for the Networking TS to be standardized? I really want it to happen, but I can't go and participate in committee meetings (I probably shouldn't even if I could, though, since I'm still learning).
size_t length = ifs.tellg();

tellg() return type is std::streampos http://www.cplusplus.com/reference/ostream/ostream/tellp/
You should be able to convert the result from tellp to a std::string::size_type by casting.

http://stackoverflow.com/questions/5262027/how-do-all-the-different-size-types-relate-to-each-other
tellp() has the same return type as tellg() http://www.cplusplus.com/reference/ostream/ostream/tellp/ which means that the solution offered through above link should also be applicable here
in turn, you could 'optimize' this a bit further by making a reasonable assumping about the average length of words - say its 4 - therefore input_v.reserve would be scaled down by a factor of 4 from static_cast<std::string::size_type>(length)
and this link is also very useful for reading really large files beyond the size of your RAM:
http://stackoverflow.com/questions/34751873/how-to-read-huge-file-in-c
ps: i must also add the disclaimer that i've not had to read in very large files, so if anybody has a better/different suggestion do chip in
Yeah, thanks for those.

I'll read up on those later. But for now I think I can mark this as "solved".

@gunnerfunner: You think you could come over to the thread I made for Chapter 12 Exercise 11 (it's the one that mentions equilateral triangles in the title)? I have a runtime error about two polygons lying in a straight line, and apparently my y-axis values are all outside the window. I don't know how to best points in a GUI, I guess.
You think you could come over to the thread I made for Chapter 12 Exercise 11

thanks for the invite but I'd be utterly useless at GUI stuff and need to learn myself, good luck!
Topic archived. No new replies allowed.