ShiZero

Hey everyone.

Solved - Read at the bottom

I'm usually not prone to ask for help with my coding issues, mainly because I'm at a very basic level of C++ programming and, so far, I've managed to find the answers to what I need after a bit of researching, both online and through my books. But this time, everything has failed me. Perhaps because it's a rather specific subject I'm asking about, and maybe because I don't know what to look for - anyway, asking away is my last resort. After four hours of trying to solve this problem, I'm completely out of ideas.

The heart of the problem is that I need a Vector of type DICT_ENTRY, which has KEY and VALUE as objects. The vector, called DB, needs to be able to hold both values so it can be tested against input. Specifically, KEY will host the type or attribute of a word ( A noun, a verb or likewise ) and VALUE will hold the word that fits that attribute. The problem I'm facing is reading into them from a dictionary file. For example, as an array:

Code Block

...

DICT_ENTRY A[30];

int i = 0;

in.open(filename.c_str());

while (!in.eof() && i < 30)

{

in >> A[i].KEY >> A[i].VALUE;

i++;

}

...

But because Vectors need to be initialized, unlike an Array, I need to use the push_back(); function of the Vector class to add new values into my vector, correct I have managed to do that with a string-type vector, but not with my DICT_ENTRY-type vector.

Here, this is my DICT_ENTRY class and the code I'm trying to use so that the values are added into the vector.

Code Block

class DICT_ENTRY

{

public:

string KEY, VALUE;

};

Code Block

LIB_CLASS::LIB_CLASS()

{

string story_file = "story.txt", dict_file = "dictionary.txt";

string word;

ifstream s_in, d_in;

int i = 0;

s_in.open(story_file.c_str());

d_in.open(dict_file.c_str());

if (!s_in.fail())

{

i = 0;

// Read the story file

while (!s_in.eof()) // size is a vector type, not a vector of a class.

{

s_in >> word;

story.push_back(word);

cout << story[i];

i++;

}

}

if (!d_in.fail())

{

i = 0;

while (!d_in.eof())

{

d_in >> word;

DB[i].KEY.push_back(1);

DB[i].KEY = word;

cout << DB[i].KEY;

d_in >> word;

DB[i].VALUE.push_back(1);

DB[i].VALUE = word;

i++;

}

cout << "Files read successfully." << endl;

}

else

{

cout << "The files could not be opened.";

}

s_in.close();

d_in.close();

}

The text in boldface is what is making the program crash. I've tested it without it and everything else runs fine.

Code Block
DB[i].VALUE.push_back(word);

returns

error C2664: 'std::basic_string<_Elem,_Traits,_Ax>:: push_back' : cannot convert parameter 1 from 'std: Tongue Tiedtring' to 'char'

But while push_back(1) doesn't give me any errors, the program still crashes.

I'm completely out of ideas as to what would be the better approach to doing this.

Thanks in advance for any help. I greatly appreciate it.

Edit:

Phew, alright. Seems like I got it, at least for the moment. This sounded a bit strange at first and the idea didn't sink very well. But then I tried it, and it worked. Here's basically what I did:

In my default constructor, I added a variable called "entry" of type DICT_ENTRY. Then, for the reading process, I used:

Code Block

while (!d_in.eof())

{

d_in >> entry.KEY;

DB.push_back(entry);

d_in >> entry.VALUE;

DB.push_back(entry);

}

And it worked perfectly. DBIdea.KEY contains the keys and DBIdea.VALUE contains the values, just as they were supposed to. I'm not sure if this will come in handy to someone, but I will leave the whole topic intact nonetheless. Hopefully it will.

Now, to make up for those five hours lost.



Re: Visual C++ General Vector of an Object - [Solved]

Andreas Masur

Actually, you are not far off...I will provide some information however, you can implement it on your own...first let's start with the vector. It contains element of type 'DICT_ENTRY'. Whether this type contains 2 member elements or 500 is not important to the vector itself. It sees this simply as one element. Thus, if you want to add one element, you only do it once:

#include <vector>

std::vector<DICT_ENTRY> vec;
DICT_ENTRY entry;

vec.push_back(entry);

The above will add one element to the vector which will contain empty strings (since by default the string class will initialize the string to an empty one). You could now access the individual strings of the just added object, however, you don't know the element index. Thus, it certainly would make more sense to initialize the strings *before* adding the element to the vector wouldn't it So, let's go ahead:

#include <vector>

std::vector<DICT_ENTRY> vec;
DICT_ENTRY entry;

entry.KEY = "MyKey";
entry.VALUE = "MyVal";
vec.push_back(entry);


Now, this looks much better...no the one element actually contains meaningful values. Note, that you only add the element once....

Of course there is room for optimization...wouldn't it be nice if you could simply read in both values and then add them to the vector automatically initializing your structure with the read values Well...let's see....in order to provide a way to initialize the structure at creation you need to provide an appropriate constructor:

#include <string>

struct DICT_ENTRY
{
string KEY;
string VALUE:

DICT_ENTRY(const char* key = 0, const char* val = 0)
{
if(key)
KEY = key;

if(val)
VALUE = val;
}
};


Now, you can actually create an instance of your structure and initialize it at the same time:

DICT_ENTRY entry("MyKey", "MyVal");
DICT_ENTRY entry2; // Still works due to the default arguments for the parameters


So, this is the first step...the second step is simply putting everything together:

#include <vector>

std::vector<DICT_ENTRY> vec;

vec.push_back(DICT_ENTRY("MyKey", "MyVal"));


The above does the same as the example shown earlier just in a more optimized way....it creates a (temporary) instance of the 'DICT_ENTRY' structure, initializes both member elements accordingly and then adds the structure to the vector...nice


Having said all this....your original problem was that you called 'push_back()' on the string element of your structure...which is not an error itself since the string class also provides the member function. However, the string class is basically nothing else than an array of type 'char' thus 'push_back()' expects a 'char' while you provided an integer (1) hence the error message....





Re: Visual C++ General Vector of an Object - [Solved]

Andreas Masur

ShiZero wrote:

Code Block

while (!d_in.eof())

{

d_in >> entry.KEY;

DB.push_back(entry);

d_in >> entry.VALUE;

DB.push_back(entry);

}


Although you solved your problem while I was writing my first reply....I still doubt that the above is the solution you were after...the above will create two elements in the vector for each KEY/VALUE pair:


The first element will have the 'KEY' string set, but an empty 'VALUE' string while the second element will contain both. Just eliminate the first 'push_back()' and you should have solved your original problem:



Code Block

while (!d_in.eof())

{

d_in >> entry.KEY >> entry.VALUE;

DB.push_back(entry);

}







Re: Visual C++ General Vector of an Object - [Solved]

Simple Samples

ShiZero wrote:

The heart of the problem is that I need a Vector of type DICT_ENTRY, which has KEY and VALUE as objects. The vector, called DB, needs to be able to hold both values so it can be tested against input. Specifically, KEY will host the type or attribute of a word ( A noun, a verb or likewise ) and VALUE will hold the word that fits that attribute.

I am confused, since the code you show uses DICT_ENTRY yet you say DB. I will assume you meant to say DICT_ENTRY. The problem is that "DICT_ENTRY A[30];" is a C-style array, not a std :: vector.

ShiZero wrote:
But because Vectors need to be initialized, unlike an Array, I need to use the push_back(); function of the Vector class to add new values into my vector, correct

Incorrect. You can size a std :: vector using it's size() member. That could simplify your code, since you then could access each item using a subscript, syntactically the same as C-style arrays.






Re: Visual C++ General Vector of an Object - [Solved]

ShiZero

@Andreas Masur:

Oh wow!

I don't have words to express my gratitude. Seems like I was too eager to get back to programming that I forgot to check my input. And it's just as you said - there were duplicate entries and the whole vector was a complete mess. It's my first time using Vectors, so I still find it a bit difficult to picture what is going on inside them beforehand.

But really, thanks a lot. I just fixed it and it works like a charm. I'll try using your method afterwards, mainly for learning purposes, since I'm actually rather sick of the vector thing at the moment . It's working, and that's what matters.

Kudos to you.

@Simple Samples:

I am confused, since the code you show uses DICT_ENTRY yet you say DB. I will assume you meant to say DICT_ENTRY. The problem is that "DICT_ENTRY A[30];" is a C-style array, not a std :: vector.

Oh, sorry for not specifying. The first bit of code I posted was just to illustrate how I would do it using an Array of type DICT_ENTRY, whereas the third bit of code - my default constructor - actually uses the vector<DICT_ENTRY> DB; Vector listed in my LIBS class. That was my mistake, I apologize.

And I see. Unfortunately, I can't use the size(); function for this specific program because I don't know how many elements there'll be in the text file. I know I could probably initialize it to a certain value and increase it according to necessity, but I think it would be unnecessary in this case.

Still, thanks for the helpful information.





Re: Visual C++ General Vector of an Object - [Solved]

Andreas Masur

Simple Samples wrote:

Incorrect. You can size a std :: vector using it's size() member. That could simplify your code, since you then could access each item using a subscript, syntactically the same as C-style arrays.


Actually, the above is not true. 'size()' only returns the current size of the vector (that is the number of elements currently in the vector). To actually resize a vector you need to call the corresponding named function 'resize()' (Or use one of the specialized constructors).





Re: Visual C++ General Vector of an Object - [Solved]

Andreas Masur

ShiZero wrote:

But really, thanks a lot. I just fixed it and it works like a charm. I'll try using your method afterwards, mainly for learning purposes, since I'm actually rather sick of the vector thing at the moment . It's working, and that's what matters.


In case you start to like the vector class again and want to learn more about it....the following is a nice introduction to it...






Re: Visual C++ General Vector of an Object - [Solved]

Simple Samples

Andreas Masur wrote:

Actually, the above is not true. 'size()' only returns the current size of the vector (that is the number of elements currently in the vector). To actually resize a vector you need to call the corresponding named function 'resize()' (Or use one of the specialized constructors).

Correct, I was wrong.

Yes, there is also a constructor that allows the size to be specified. The following shows the syntax for doing that.

Code Block

#include "stdafx.h"

struct Struct {int Key; std::string Value;};

int main(int argc, char* argv[]) {
std::vector<Struct> v(2);
// v.resize(2);
v[0].Key = 1;
v[0].Value = "First";
v[1].Key = 2;
v[1].Value = "Second";
std::cout << v[0].Key << ' ' << v[0].Value << '\n';
std::cout << v[1].Key << ' ' << v[1].Value << '\n';
return 0;
}







Re: Visual C++ General Vector of an Object - [Solved]

Simple Samples

Is there a reason why this was asked in the VC general forum instead of the VC language forum