How to create an iterator function - c++

So my task is to create a function with signature: list<Person>::iterator SearchPos(list<Person> &Mylist, Person &person). Which would later get the appropraite position for the person, in order of birth, to be inserted into the list. Its return type should be an Iterator.
I have tried doing the following :
list<Person>::iterator SearchPos(list<Person> &MyList, Person &person)
{
}
int main()
{
char Dot;
string Dummy;
string Name;
int Day, Month, Year;
fstream MyFile;
MyFile.open("Kontakte.txt");
list<Person> BirthdayList; // Creating list of type Person
if(MyFile.is_open()) {cout << "File opened successfully." << endl;};
getline(MyFile, Name, ','); //Get line until "," is reached
MyFile >> Day >> Dot;
MyFile >> Month >> Dot;
MyFile >> Year;
getline(MyFile, Dummy); //Gets rid of \n char.
Person P1 (Name, Day, Month, Year);
SearchPos(&BirthdayList, &P1);
but even without the body of SearchPos() function I get the error :
invalid initialization of non-const reference of type 'std::__cxx11::list<Person>&' from an rvalue of type 'std::__cxx11::list<Person>*'|
Edit
Thanks a lot for the help with that error message it would take me embarrasingly long to figure that one out. The answer to my orginal question is as follows
list<Person>::iterator SearchPos(list<Person> &MyList, Person &person)
{
list<Person>::iterator pos;
//body of the function
return pos;
}
This will make the function return an iterator as wanted by my task.

After some getting used to, the compiler error is actually clear. Maybe this will help you to decipher it.
invalid initialization of non-const reference of type 'std::__cxx11::list&' from an rvalue of type 'std::__cxx11::list*'|
std::__cxx11::list<Person> is actually list<Person> in your code. The standard library just adds some namespaces. Maybe if we switch the example to int, it is clearer.
int SearchPos(int& index){} // let's define a function taking a reference to `int`.
int main() {
int my_index;
SearchPos(&my_index);
}
would similarly result in
invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int*'|
So the problem is that you cannot convert int* to int&.
Why? Well, they are different types, and you cannot convert between them.
Where is int* coming from? You are getting the type int*, since the operator & returns an address to the int, thus a pointer to int (int*). (extra, the returned address is a rvalue, since it itself does not have an address.)
So either you make sure that the type you are inputting corresponds to the signature of the method:
int SearchPos(int* index){}
int main() {
int my_index;
SearchPos(&my_index);
}
, or, what you should do, since the signature is set, you make sure you pass a reference:
int SearchPos(int& index){}
int main() {
int my_index;
SearchPos(my_index);
}

You need to call the function like this:
SearchPos(BirthdayList, P1);
As mentioned in the comments you were passing the parameters as pointers when your function was looking for a reference. Using the ampersand (&) returns a pointer to your object. I know it may be confusing and seem like you need to pass in the address since your function accepts a reference but you don't need to do that. Declaring it as a reference in the function parameters is all you need to do.

Related

Can a class name be the name of an array?

I get a "type name not found" problem when I try to use this array for my function.
class dancer {
public:
dancer();
void swap(int, int, dancer[]);
};
void dancer::swap(int num1, int num2, dancer[])
{
int current = dancer[num1];
dancer[num1] = dancer[num2];
dancer[num2] = current;
}
I'm supposed to use the class name as my array type for my assignment. I believe I made an error on setting up the array. The error is at int current = dancer[num1];
dancer[num1] = dancer[num2];
dancer[num2] = current;
void dancer::swap(int num1, int num2, dancer[])
Since dancer is a type this gets parsed as an anonymous method parameter that's an array of dancer objects, and not as some array, of some type named 'dancer'. You have to name this parameter:
void dancer::swap(int num1, int num2, dancer values[])
and then some values[num1] with values[num2].
However it is fairly likely that you have fundamentally misunderstood something about your programming assignment. It makes no logical sense to have a non-static class method that takes, as a parameter, an array of other instances of its own class, for this purpose.
You should reread your programming task's description. You are likely missing some part or detail of it; however the above is the explanation for your compilation error.

Non-lvalue in assignment in class

I'm kinda of new at c++, so I need some help. I have to make a function tha books ticket for an event.
void Event::book(int row, int seat, Date date, char *name, char *note)
{
if(this->date==date && strcmp(this->name,name)==0)
{
if(hall.seatsInHall[row-1][seat-1].isFree()==true)
{
hall.seatsInHall[row-1][seat-1].isFree()=false; // here it gives me non-lvalue in assignment
hall.seatsInHall[row-1][seat-1].getNote()=note; // here it gives me non-lvalue in assignment
hall.seatsInHall[row-1][seat-1].getNote()=note; // here it gives me non-lvalue in assignment
cout<<"Seat Booked.";
}
else cout<<"This seat is already taken or bought.";
}
else cout<<"Error.";
}
What can I do to not show this mistake?
The problem arises because the stuff on the left side of the assignment statements are not lvalues i.e. you cannot assign values to them. The most likely cause is that getNote() and isFree() are returning-by-value. A function can return an lvalue if (and only if) it returns a reference.
You need to make sure that isFree() and getNote() return non-const references.
For the two functions having problems in your post, they could look like:
bool& isFree()
char*& getNote()
While this should fix your errors, in the case of getNote, it's not very pretty. Furthermore, it's not clear which object has ownership of the char* data and that could lead to memory leaks later. A nicer solution would be to change note to std::string instead of char*.
Your original function signature would then look like:
void Event::book(int row, int seat, Date date, char *name, std::string note)
And the signature of getNote() would be:
std::string& getNote()

Pointer pointed to string passed by function in C++

I have a question on the pointer used by string in a function. my code is below.
void printName(int *max,int *min,string *maxFirst, string *maxLast)
{
ifstream infile;
infile.open("input.txt");
string firstName,lastName;
float age;
infile>>firstName>>lastName;
while(firstName!="Term") {
infile>>age;
if(age==*max)
{
maxFirst=&firstName;
maxLast=&lastName;
cout<<*maxFirst<<' '<<*maxLast<<endl;
}
}
To use this function, in main(), I define it like
int main()
{
void printName(int *,int *,string *,string *);
int *pMaxAge, *pMinAge;
string *maxFirst,*maxLast;
pMaxAge=&maxAge;
pMinAge=&minAge;
printName(pMaxAge,pMinAge,maxFirst,maxLast);
cout<<"\nThe oldest employee is "<<*maxFirst<<' '<<
*maxLast<<endl;
}
I skip some part of my code. While the first cout works fine, the second one doesn't work. Is there any problem with my pointer passing please?
Thanks.
Your understanding of pointers is a complete mess. You should go and RTFM on pointers, from the ground up. Nothing you do here makes sense.
First you declare 4 pointers, not initialized to anything. Then you pass them to a function which takes pointer arguments by value, and expect changing the pointers' values to affect anything outside the function.
You should allocate these variables in your main function, and then pass them either by reference or by address, and assign to them properly when doing so.
For instance:
void printName(int *max,int *min,string *maxFirst, string *maxLast)
{
ifstream infile;
infile.open("input.txt");
string firstName,lastName;
float age;
infile>>firstName;
while(firstName!="Term") {
infile>>lastName>>age;
if(age==*max)
{
*max = (int)age;
*maxFirst=firstName;
*maxLast=lastName;
cout<<*maxFirst<<' '<<*maxLast<<endl;
}
infile>>firstName;
}
}
int main()
{
int MaxAge = 0, MinAge;
string maxFirst,maxLast;
printName(&MaxAge,&MinAge,&maxFirst,&maxLast);
cout<<"\nThe oldest employee is "<<maxFirst<<' '<<
maxLast<<endl;
}
In the printName function you need to assign to the content of the pointer:
*maxFirst = firstName;
*maxLast = lastName;
You also need to pass pointers to the existing variables as function arguments:
string maxFirst;
string maxLast;
printName(pMaxAge, pMinAge, &maxFirst, &maxLast);
The same probably applies to the integer arguments.

C++ Implementing Functions that don't utilize global declarations

My code is already working, seen here: http://pastebin.com/mekKRQkG
Right now, my functions work but utilizing information that I've declared globally, I guess, and I want to convert them so that they are in the format as seen on lines 11-15, but I'm unsure of how to convert them to do so. Simply put, I'm trying to convert my function of
"void add_county_election_file"
to be in the format of
"void add_county_election_file(const string, const vector &, const vector &, const vector &, const vector &)"
and I have no idea where to begin or how to even start.
Could someone please help me out and show me how I'd do this for the first function, so I can implement it across the board?
Thanks guys!
Your function declaration should look something like this:
void add_county_election_file(const string, vector<int>&, vector<string>..);
Make sure that your argument list for the vector template is correct(that's the type you put between <>)
Then match the implementation of you function to the declaration:
void add_county_election_file(const string, vector<int>&, vector<string>..){...}
Now call your function with apppropriate arguemtns in main:
string s;
vector<int> arg;
vector<string> sv;
void someFunction (s, arg, sv ...);
I think you are doing correct as the function you have declared
void add_county_election_file(const string, vector<int>&, vector<int>&,..);
so you just have to call the above function with the required arguments, as right now you are not passing the argument and your current definition doesn't accepts any arguments.
And as a good practice, in your int main() function you can use switch rather than going for if else.
Store your variables and functions in a class, overload operators and create functions to access these variables.
Declare all variables in int main() and set parameters to be passed into each function e.g.
void print_results() is modified to become
void print_results(std::vector<int> vec, int nCount, etc..)
Similar to the first one, create a struct to hold all data members, then pass the struct(by ref) into each function.
struct CountryTracker
{
std::vector<int> ID;
std::string name;
//etc...
}
`void print_results(CountryTracker& Obj) //pass single struct into functions`
The OOP way to do this is to create a class called perhaps ElectionInfo, where:
These would be its member fields:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
and these would be its member functions:
void add_county_election_file(const string);
void search_county(const string);
void print_results();
This way you don't have to pass the references to the vectors around at all, instead you can just do:
ElectionInfo an_elect_info;
char selection = get_menu_choice();
// some if-statements to decide which of the following to call:
an_elect_info.add_county_election_file(county_name);
an_elect_info.search_county(county_name);
an_elect_info.print_results();
But if you'd prefer to stay with the current functional approach:
Declare and initialize the following inside your main method:
vector <string> countyNameVector;
vector <int> countyNCount;
vector <int> countyFCount;
vector <int> countyOCount;
int NCount;
int FCount;
int OCount;
int NTotal;
int FTotal;
int OTotal;
The syntax for the commented out function declarations should be tweaked to look like this:
void add_county_election_file(const string, vector<string>&, vector<int>&, vector<int&, vector<int>&);
(Of course, the definition should follow suit)
You would invoke it like this:
add_county_election_file(countyname, countyNameVector, countyNCount, countyFCount, countyOCount);
Objects are automatically passed-by-reference.
The basic process of refactoring should at the first step involve only code grouping and placement and should only minimally involve writing new logic. Using this as a principle you can go about modifying the code in the following way at first.
string ReadInputString(const char* title)
{
string s
cout << title;
cin >> s;
}
void add_county_election_file(const std::string& filename
, std::vector<string>& countyNameVector
, std::vector<int>& countyNCount
, std::vector<int>& countyFCount
, std::vector<int>& countyOCount
)
{
int NCount = 0;
int FCount = 0;
int OCount = 0;
int NTotal = 0;
int FTotal = 0;
int OTotal = 0;
char vote;
std::ifstream input((filename).c_str());
string countyName;
if(input.is_open())
{
input >> countyName;
countyNameVector.push_back(countyName);
while(input >> vote)
{
if(vote == 'N' || vote == 'n')
{
NCount = NCount + 1;
}
else if(vote == 'F' || vote == 'f')
{
FCount = FCount + 1;
}
else
{
OCount = OCount + 1;
}
}
countyNCount.push_back(NCount);
countyFCount.push_back(FCount);
countyOCount.push_back(OCount);
}
cout << countyName << endl;
}
void add_county_election_file()
{
string fn = ReadInputString("Enter the county file to process: ");
add_county_election_file(fn,g_countyNameVector,g_countyNCount,g_countyFCount,g_countyOCount);
}
As you can see I have just extracted your code and moved them to individual functions and changed names to make some significance. Like in the function ReadInputString - the line "cin >> s" was originally "cin >> filename". The abstract name "s" is to signify that the ReadInputString has no knowledge or doesn't care what the semantic meaning of the string it is reading from console.
In order to not change your main function - I have added a overloaded add_county_election_file that calls one function followed by another. The idea is that you should keep something unchanged and change others (for good) and then alternate if need be.
And I have changed names of your global variable to differentiate them from the local variable using "g_" - the point is that "g_" should only be found at very few places in your code.

Passing user input to function with char* parameters

I'm new to this so I know this is probably something simple.
I have a function like this
void GroceryList::addRecord(char* itemName, char* itemType, char rating){
//do some code;
}
My problem is I am having trouble creating proper arguments to pass to the function.
I've tried something like
void main() {
string itemName;
cin >> itemName;
string itemType;
cin >> itemType;
string rating;
cin >> rating;
gradeBook.addRecord(itemName, itemType, rating);
}
I didn't expect it to work as the function is expecting char* but I can't for the life of me figure out how to get the user input into a variable that I can pass to the function. I've been search for literally 13 hours trying what I can find but no luck so far.
Well, don't use char*.
void GroceryList::addRecord(const std::string& itemName, const std::string& itemType, const std::string& rating) { /* ... */ }
You can get const char* (not char*) from string with c_str() member function, e.g. itemName.c_str(), but unless you're doing interop with C libraries, you don't need that.
Change the function prototype to
void GroceryList::addRecord(string itemName, string itemType, string rating){
//do some code;
}
I also recommend const correctness in your code, if you are not going to change the arguments, pass them by ref with const (for performance)
void GroceryList::addRecord(const string& itemName, const string& itemType, const string& rating){
//do some code;
}
All depends on the actual method body which you didn't describe.
Use std::string::c_str(); that's what it's for:
gradeBook.addRecord(itemName.c_str(), itemType.c_str(), rating.c_str());
This function returns a const char *. However, the addRecord function doesn't seem to be const-correct, so you need to fix that.
You can use string and then when passing just call c_str() on the string. For the rating you can just use a char.
Then calling the function looks like:
gl.addRecord(itemName.c_str(), itemType.c_str(), rating);
For this to work you'll need to change the function signature to const char* instead of char*.
The simple answer is that you can't. If you can modify
GroceryList::addRecord, change it to use std::string const&. If you
can't modify it, then you have to ask the question: why does it use
char*? There are two possible answers: the author didn't understand
const, or was too lazy to use it, and in fact doesn't modify the
pointed to strings. In this case, something like
const_cast<char*>( itemName.c_str() ) can be used; it's wordy, but
that's the price you pay when the code's author doesn't do his job
correctly. The other possible answer is that the code does modify
something through the pointer. In this case, the only solution involves
making a copy of the string into a char[], and passing it.