reading a line from a file and creating a vector of words from it

hello all,

i am trying to create a function that reads a line from a file, creates a vector of strings with each word from that line in a different index, processing it and then continuing to the next line.

for instance, if i have the following line in the text file:"put abcd 3124323", then the first element of the vector will be "put", the second will be "abcd" and the third will be the number.

then it will first read the first line, make a vector of strings where each index contains a word from it, and then i'll pass it to an handler, probably clear the vector and so on until reaching end of file.

what i tried to do(using previous functions you've helped me with):





 



thank you very much, i'm learning so much from your comments and solutions. tried to apply them here as well
Last edited on
You probably should do the input in two steps:
1. Read one whole line (could have multiple words)
2. Read words from the line

Look at istringstream: http://www.cplusplus.com/reference/sstream/istringstream/istringstream/
Hello cppnoobie,

When I first looked at your code and then when I loaded it up and tried to compile it there are problems.

Is this code from "main" or a function?
Where are your header files?
Where is main?

It is more useful to post the whole program. This way people who would want to put the program into their IDE can do so without having to make something up just to get it to compile and run.

Looking at your code and then when I tried to compile it I had a problem with two lines: if (f.bad()). Where did "f" come from and why do you think you need it? It has no real value to the code and does nothing when reading the file.

In the while condition the "std::ws" will only skip white space at the beginning of the line and since there is none there is no need for this. The third parameter will extract up to and including the first white space it finds and discard the white space. But this does not solve your problem because the first ends with a new line character (\n) and this in not accounted for.

keskiverto has a good suggestion with the "istringstream". In simple terms think of the string stream as an internal file stream using memory as opposed to an external file stream. The other big difference is that the string stream is dealing with only one line not an entire file.

The string stream is the best solution, but if you can not use it there are different ways of breaking up the words. See code below.

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
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

int main()
{
	std::vector<std::string> parseLines();
	std::vector<std::string> setArgsFromFile;
	std::string line, word; // <--- Added word.

	std::ifstream input("commands.txt");

	if (!input.is_open()) { perror("error while opening file"); }
	//if (f.bad()) { perror("error while reading file"); }  // <--- Where did this come from and what is it for?

	//while (std::getline(input, line))
	//{
	//	std::istringstream ss(line);  // <--- Added.
	//	
	//	while (std::getline(ss, word, ' '))
	//		setArgsFromFile.emplace_back(word);  // <--- Changed.

	//	// do operations according to first word

	//	//setArgsFromFile.clear();  // <--- Do not need.
	//	//std::cout << std::endl;  // <--- Used for testing.
	//}

	while (input >>word)
		setArgsFromFile.emplace_back(word);

	//if (f.bad())  // <--- Where did this come from and what is it for?
	//	perror("error while reading file");

	return 0;  // Not necessary, but good form and a good break point in the IDE.
}


Your check of the file stream works, but consider this:
1
2
3
4
5
6
7
8
const std::string inFileName("commands.txt");

if (!input)
{
	std::cout << "\n File \"" << inFileName << "\" did not open" << std::endl;
	std::this_thread::sleep_for(std::chrono::seconds(3));  // <--- Needs header files chrono" and "thread".
	return 1;
}

If you put line 1 above line 5 in your original code you can use the variable name in place the constant string in the ()s.

I like this because if you enter the if statement yo will leave the program instead of continuing on when there is no need to.

Hope that helps,

Andy

Edit:
Last edited on
Thank you very much Andy, i'll post the whole program in a new thread, so it will be easier to see. i'll do that additionally because i've changed the behavior of the function and have added several other components and supporting functions to it, and i'll mention them in the that thread(i'll also refer to it here).

thank you again for your help
Hi, cppnoobie.
I glanced through your code on www.onlinegdb.com and I wonder weather it is either an exercise or an assignment, or is something you’re doing by your own. I mean, what’s the advantage of that linked list to store your data? Are there constraints that require it? And what’s bad in std::list? Are you required to write your own version?

Apart from the vintage C-style syntax
1
2
3
4
5
6
7
8
typedef struct TNode
{
    struct TNode* parent = nullptr;
    struct TNode* left = nullptr;
    struct TNode* right = nullptr;
    std::string* s_Name;
    int s_Id;
} TNode;

there are issues, for example:
1
2
3
4
5
class TBST
{
public:
    TBST();
    TNode *root;

TBST::TBST() is empty, so root is left uninitialised (a dangling pointer).

So, if I have understood correctly, you want to store some students’ data (name and id) and then perform on them operations that your going to read from a file. To achieve that, you have written your own container and than a number of functions to turn the operations you read on that file into something your container can understand.
I think you’ve done a great job, but in my opinion it is a big, hard to maintain and to reuse code.
If you are doing that to prove yourself or because you’re required to do it, that’s great; if you want to use your code for something practical… I might sound terribly harsh (sorry for that), but, as a C++ beginner, I’d suggest reconsidering the project from scratch.

Anyway, to get better help, in the future you could consider providing also an example of what your ‘operations file’ looks like.

Happy coding.
thank you very much for your reply. how should i correctly fix the given faults you've found? how should i do so in a correct and efficient way? really interested in learning the correct way to do it in a c++ fashion, and not archaic c.

thank you very much!
The C requires use of "full typename".
1
2
3
4
5
struct Foo {};

int main() {
  struct Foo x; // cannot write:  Foo x
}

Your example did use that:
1
2
3
struct Foo {
  struct Foo* y;
};

C++ does not require the struct/class/union in the typename:
1
2
3
struct Foo {
  Foo* y; // ok
};

The C does offer type aliases to avoid the use of "struct ":
1
2
3
4
5
6
struct Foo {};
typedef struct Foo Foo;

int main() {
  Foo x; // typedef expands the "Foo" into "struct Foo"
}

One can (as you did) define a struct and alias in one statement:
typedef struct Foo {} Foo;
As said, C++ does not require such trivial convenience typedefs.

You had actually an interesting mixture of styles in:
1
2
3
4
struct TNode
{
    struct TNode* parent = nullptr;
};

This default member initializer syntax did appear in C++11.
Before, you had to put the value into constructors:
1
2
3
4
5
6
struct TNode
{
    TNode* parent;

    TNode() : parent( nullptr ) {} // overridden default constructor
};

thank you very much for explaining. i'll approach this right after i get the main program functioning (i'll add enum and structs for the commands as well). right now i want to make it work and then i'll make it look better as much as i know
Topic archived. No new replies allowed.