storing to a map inside a function - c++

I'm trying to write a function that will input information into a map from a text file. My main code goes as follows:
int main(){
typedef map<int,student*> record;
record allstudents;
fileinput("inputtest.txt",allstudents);
//rest of code....
}
where the function 'fileinput' is defined as:
void fileinput(string datafile, record map){
fstream file1(datafile);
if(!file1.good()){
//error code
}
//Pulls information from file
student* S1= new physics(name,ID); //creates a new pointer
//(*S1).printinfo(); //Can print info if required for de-bug
map[ID]=S1; //store to map
entries++; //counts entries read in
}
cout<<"Import complete. "<<entries<<" new students entered."<<endl;
}
When I run this piece of code from a test file, it will read in the data and output it fine if I uncomment (*S1).printinfo(); and will correctly count the number of students that have been read in. However when I come back to my main function and output what is now stored in allstudents there appears to be nothing there?
Why is this occurring and does anybody know the way around this problem? I've cut a lot of code out to try and make it easier to read but if you need to see the rest I can always edit this.
Thanks.

This is because you are passing in map by value. Change the signature of the function to
void fileinput(string datafile, record &map)
Short explanation: when you pass by value, a copy of the argument (map) is made. Inside your function you perform modifications to that copy, but these modifications are lost when the function returns and the copy goes out of scope. They do not automatically propagate back to the "source" object.
For a detailed explanation, see Pass by Reference / Value in C++.

You are passing the map by value, so the function makes it's own copy and your original remains unchanged. Try passing by reference:
void fileinput(string datafile, record& map) { ... }
^ reference!

Related

Saving a struct array to an external file in c++

I have an assignment where I need to:
save the list that the user inputs to an external file.
load the info from the file previously saved.
I managed to write in the code for the 1st task, but since I have errors, I couldn't continue to the 2nd task. Please take a look and let me know what your thoughts are.
First Error:
When you create an array, the name of the array is a pointer to the beginning of where the array is in memory. In line 42, you cannot compare an int with a pointer like that. Instead, I assume you want to do this:
for (int i = 0; i < size; ++i) {
Second Error:
In line 43, you are trying to input an std::ofstream object into a function. In order to do this, std::ofstream must be copy-able. ofstream has a deleted copy constructor, meaning that it cannot be copied and thus cannot be passed as an input to a function. Instead, you could simply create the ofstream object and open the file within your pet::save function. Also, make sure you close the ofstream. As an example:
void pet::save()
{
ofstream file;
out.open("animal.txt");
if (!out.is_open())
cout << "Unable of open file." << endl;
file << pet_info << endl;
file.close();
}
You could also use a pointer to the ofstream as an input to your save function, since pointers can be copied (then use out->operator<<(pet_info) to input to the file). This would make it run faster, but this situation does not seem to prompt such optimization. The function prototype would look like
void pet::save(ofstream* file);
and you would pass &out as the input to the function.
Third Error:
You are trying to use the array called animal within your pet class. Since animal is an array of pets that is created outside of your pet class, the pet class does not have access to it (so animal was not declared in the scope of pet). I am guessing your pet class stores a string which contains a pet's information (which I call pet_info). Given that is true, you can call the above save function that I wrote for all of your pets in the animal array to save them to a file.
Fourth Error:
On line 109 of pet.cpp, it appears you are missing a semicolon. That could be why the bracket error is there, or you are just missing a bracket.

Store and Load objects from a file

I'm making this program for class and we are supposed to store objects from a class in a file and then load them. But I always get the last object stored instead of the first. Tried the seekp function but it doesn't work. Also shouldn't the size of an object be 38 bytes, instead of the 48 i'm getting?
void student::load()
{
fstream fin;
fin.open("StudentData.bin",ios::binary|ios::in);
fin.read((char*)this,sizeof(*this));
}
void student::store(int z)
{
fstream fout;
fout.open("StudentData.bin",ios::binary|ios::out);
//fout.seekp(38*z, fout.beg)
cout<<sizeof(*this);
fout.write((char*)this,sizeof(*this));
}
for(i=0;i<count;i++)
{
s[i].store(i);
}
cout<<"Done!";
student pleb;
pleb.load();
pleb.showstudent();
return 0;
}
Your fout.open() rewrites the file each time. If you want to append to file, that is, to have each store() call to write that student after all other students already written, then you can use the ios::app flag.
Or, better, do not open the file in store() at all. Make your store() actuall accept the stream as a parameter; then open the file in the main program (once per all students) and pass the stream to store(). Not only this will solve your problem, but will also make your student class more configurable as it will be easy to write to any file, or in general to any stream the user of student needs.
BTW, also make sure that it is correct to write your students this way. For example, if you have any pointers in your student (including, say, std::string members as they have pointers inside), you will not get what you expect.
As for the object size, it is impossibly to answer not seeing the whole declaration of student class.

Return a pointer from a function to an object initialized in main()

I have been struggling with this problem for a few hours now and I've searched for every term that made sense to me. I might even have already read through a relevant answer but didn't recognize it as such because I'm a little confused by pointers.
So, I have a struct that is part of an object which is part of a chain of objects that is "anchored" (if you can call it that) in another object, which is itself part of a chain which is "anchored" in an anchor object initialized in main.
struct values
{
double val, ues;
}
class small
{
public:
values vals;
}
class big
{
public:
small *small_anchor;
}
values &getPointerToStruct(big *con)
{
values *return_vals;
if(con->small_anchor->vals.val==10)
return_vals=con->small_anchor->vals;
return (&return_vals);
}
int main()
{
values *main_values=NULL;//This is supposed to be pointing to the "vals" struct contained inside the "small" object.
big *big_anchor;
big_anchor = new big;
big_anchor->small_anchor = new small;
big_anchor->small_anchor->vals.val=10;
big_anchor->small_anchor->vals.ues=5;
main_values = getPointerToStruct(&big_anchor);//now main_values should be pointing to the "vals" struct
//I want to manipulate the value INSIDE the object itself
main_values.val++;
}
I have tried every combination of &, * and no prefix I could come up with, but nothing would give the result I was hoping for. "Closest" I got was copying "vals" (from inside the object) into "main_values" so that I could manipulate the values there, which isn't of any use to me, as I want to manipulate the SOURCE of the variables.
Also please note that I left out the process of scrolling down the chains to get to the object I was trying to reach and that "return_vals" seems arbitrary, but it happens that there are two possible candidates that could be the struct my program is looking for and the "return_vals" contains the best candidate found so far and is overwritten when a better one is found, or returned when the routine ends.
You wrote
values &getPointerToStruct(big *con)
{
values *return_vals;
if(con->small_anchor->vals.val==10)
return_vals=con->small_anchor->vals;
return (&return_vals);
}
where I think you wanted
values *getPointerToStruct(big *con)
{
values *return_vals = 0;
if(con->small_anchor->vals.val==10)
return_vals=&con->small_anchor->vals;
return (return_vals);
}
But the . in main_values.val++; is wrong anyway. You need to be consistent about whether you wanted to work with a values* or a values&. You could make all this work with a values& if you like, but then main_values should be a values& and not declared until you are ready to initialize it. return_vals would not be practical as a values& because of the stated requirement that the full code gives it a tentative address that is conditionally modified later. But even with return_vals as a values* you could still return a values& if that is what you preferred.

Updating an Object's property in a Vector

I have a vector which contains objects. The objects have a property called first name. I want to update the first name in a property, in order to do that i have to pass the vector which the objects are saved, staff number which uniquely identifies each object and finally the new name taken from the user input.
My problem is it displays the update name in the loop which i use to set the new name but if i use a second loop or a new loop and iterate through the vector again, the new name isn't saved but the old name is displayed.
Here is what i have done :-
public: void updateFirstName(vector<Administrator> vectorUpdate,string staffNumber,string newName)
{
FileHandler<Administrator> adminTObj;
for(Administrator iter: vectorUpdate)
{
if(iter.getStaffNumber()==staffNumber)
{
iter.setFirstName(newName);
cout<<"Update"<<endl;
cout<<iter.getFirstName()<<endl;
//here it prints the updated name but if i use a different loop
//and iterate through the vector the new name is not saved.
}
}
}
What seems to be the problem here ? Thank you
You pass a vector by value
void updateFirstName(vector<Administrator> vectorUpdate,
string staffNumber,string newName)
so each time you call this function you will copy original vector into it and work on this copied vector inside the function. The result of this is the changes are made to local variable inside function. Instead you want to pass vector by reference:
void updateFirstName( vector<Administrator> &vectorUpdate,
string staffNumber,string newName)
In function body, here
for( Administrator iter: vectorUpdate)
you will experienced the same thing. You want to write:
for( Administrator& iter: vectorUpdate)

How to assign a filename with a pointer one?

I do have a function that I have created with a pointer as an argument.
That argument will be used to save at the end an image.
Every time when I would like to call that function with the desired parameter, I want that the saved image file would be with the specified name. I show you how:
void SaveImage(IplImage *img)
{
...
cvSaveImage("C:/img.png", img);
...
}
when calling the function: SaveImage(image1), I want to have an image on my C:/ whose name is image.png
Can you help me with that?
Apparently, you can't answer this question with the only answer that is actually viable, because you get downvoted...
So, I'll rephrase my answer:
You need to pass two variables to SaveImage:
void SaveImage(const char *name, IplImage *img)
{
...
cvSameImage(name, img);
}
Then your calling code will have to produce the correct name, such as:
SaveImage("c:\image.png", image);
SaveImage("c:\other.png", other);
Now, of course, if all you actually want is a unique name, rather than one that reflects the name of the variable in your code, then there are plenty of other possibilities, such as using a formatted string that contains a serial number, a random number, tmpnam() or other similar schemes.