Pointer pointed to string passed by function in C++ - 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.

Related

One warning and main() returned garbage value

Multiple students can associate with a single Department and single student can
associate with multiple Departments, but there is no ownership between the objects
and both have their own lifecycle. Both can create and delete independently.
WAP in C++ to model the relationships.
I have implemented this code as follows
#include<iostream>
#include<cstring>
using namespace std;
class Student
{
char* name_p;
public:
Student(char *sName)
{
cout<<"Student constructor called\n";
name_p=new char(sizeof(strlen(sName)));
name_p=sName;
}
~Student()
{
cout<<"Student destructor called\n";
delete name_p;
};
char* sName()
{
return name_p;
}
};
class Department
{
char* name_p;
public:
Department(char *dName)
{
cout<<"Department destructor called\n";
name_p=new char(sizeof(strlen(dName)));
name_p=dName;
}
~Department()
{
cout<<"Department destructor called\n";
delete name_p;
}
char* dName()
{
return name_p;
}
};
class Course
{
Student* std_p;
Department* dept_p;
char* courseName_p;
static unsigned int index;
static Course *courseList_p[4];
public:
Course(char* crseName,Student* student,Department* dept)
{
cout<<"Course constructor called\n";
std_p=student;
dept_p=dept;
if(index<4)
{
courseName_p=new char(sizeof(strlen(crseName)));
courseName_p=crseName;
courseList_p[index]=this;
++index;
}
else
{
cout<<"Cannot accomodate any more Course\n";
}
};
~Course()
{
cout<<"Course destructor called\n";
delete courseName_p;
};
static char* findStudent(char *crseName, char* deptName)
{
for(int i=0; i<index; i++)
{
if ( (courseList_p[i]->getCourseName() == crseName) &&
(courseList_p[i]->getDeptName() == deptName) )
{
return(courseList_p[i]->getStdName());
}
}
}
char* getStdName()
{
return std_p->sName();
};
char* getDeptName()
{
return dept_p->dName();
};
char* getCourseName()
{
return courseName_p;
};
};
unsigned int Course::index =0;
Course* Course::courseList_p[4]={0,0,0,0};
int main()
{
int i;
cout<<"\nExample of Association class\n";
cout<<"-----------------------------------\n\n";
cout<<"We have got 4 students\n";
Student *studentNames[4] = {new Student("Meera"), new Student("Moina"), new Student("Teena"), new Student("Mridula")} ;
cout<<"\n";
cout<<"We have got 2 Departments\n";
Department *departNames[2] = {new Department("Mathematics"), new Department("ComputerSceince")} ;
cout<<"\n";
cout<<"Here class Course Associates Student and Department, with a Course name\n";
Course course1("DataStructure",studentNames[0], departNames[1]);
Course course2("Maths",studentNames[3], departNames[0]);
Course course3("Geometry",studentNames[2], departNames[0]);
Course course4("CA",studentNames[1], departNames[1]);
cout<<"\n";
cout<<"Finding a Student using Course and Department\n";
cout<<"Student who has taken Maths Course in Mathematics Department is:"<<Course::findStudent("Maths", "Mathematics")<<endl;
cout<<"\n";
cout<<"Deletion of objects\n\n";
for(i=0;i<4;i++)
{
delete studentNames[i];
}
cout<<"\n";
for(i=0;i<2;i++)
{
delete departNames[i];
}
cout<<"\n";
return 0;
}
The code is showing warnings in main function i.e. ISO C++ forbids converting a string constant to char* and also the main() function is not returning 0 but a garbage value. Please help me in rectify these errors and warnings.
Also I don't want to use this pointer in class course, can I implement the code without using this pointer.
There are a couple of problems with your code. Mostly they are related to the use of char* instead of string. I'm amazed to see that some teacher still are found of this practice.
c-string allocation problems
The first problem causes memory corruption. This could explain that your main() returns garbage instead of 0. For example:
name_p=new char(sizeof(strlen(dName))); // OUCH!!!
In the statement you allocate it wrong. If you want to allocate an array, you must use new[...]. Moreover, keep in mind that a c-string allways needs 1 char more for the trailing null. So it should be:
name_p=new char[strlen(dName)+1];
would already improve the situation.
Last but not the least, if you allocate an array you must delete an array with delete[]
c-string copying issue
Then, you can copy C++ string with an assignment operator just as in:
name_p=sName; // OUCH
However, for char*, this just overwrites the pointer that new returned and you are not sure that the c-string it points to will still be valid when it's used.
If you want to assign a c-string, you need to go for:
strcpy (name_p, sName); // C-style
copy (sName, sName+strlen(sName)+2, name_p); // Safer C++ alternative
c-string comparison issue
Suppose you have two pointers to c string, say pa and pb. Comparing the pointers looks at the memory address, not at the content. So yu could have two identical strings but the comparison could nevertheless fail. THis kind of comparison would work perfectly well for c++ string, but for cstring, you need to to
strcmp(pa, pb)==0 // instead of pa == pb
c-strings in classes and structures
Whenever you have some pointers that you allocate in a class, you need to think of the rule of 3. Meaning that you'd need to add a copy constructor and an assignment operator. Fortunately, at first sight it seems that you don't need them here. Of couse, if you'd use c++ string you wouldn't have to worry about such details.
c-string conversion issues?
ANother issue in your code is the use of string literals with constructors. For example:
new Student("Meera").... // c-string literals (constant)
Student(char*...) // constructor using a c-string pointer (non constant)
You can easily get rid of this complaint, by making the constructor's pointer argument as constant:
Student(const char *sName)...
The same applies to function arguments, such as in find.
Other problems
The static member findStudent() works well, but only if a result is found. If nothing is found, it's UB, since there is no return statement (put a return nullptr; at the end of this function?)
Moreover, the wya you use this function, directly printing its result is dangerous, because dereferencing an invalid pointer will lead to UB.
Here the corrected code. It compiles and seem to run. I didn't analyse for more issues.

How to create an iterator function

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.

Can I call the function like that?

If I have a struct.
struct studentRec
{
string name;
int sid;
string major;
int cohort;
};
Then, I have a function.
int compare_MajorName(const studentRec& s1, const studentRec& s2)
Can I call the function like that?
String major = ECE;
list = new studentRec[n];
compare_MajorName(list[mid], major)
No you can't.
Your function parameters require studentRecs. A String cannot be converted to a studentRec automagically. It wouldn't make sense.
You have two possibilities:
make an overrided function which accepts a String as a second parameter
simply compare the name inside the struct with your String:
list[mid].name == major for exemple

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.

referenced memory conditionally modified in recursive loop

I have two structs and a function
struct nodeT {
bool last;
string attribute1;
string attribute2;
string attribute3;
vector<charT> leafs;
};
struct charT {
char character;
nodeT *next;
};
void addNode(nodeT *n, string stringy, string &attribute1, string &attribute2, string &attribute3)
{
if (stringy=="") {
w->last=true;
return;
} else {
if (n->last==true) {
attribute1=n->attribute1; //these attribute fields were given values earlier
attribute2=n->attribute2;
attribute3=n->attribute3;
}
addNode(n, stringy.substr(1), attribute);
}
}
And addNode is called with
string test="";
addNode(root, "wordy", test, test, test);
The problem is the attribute reference string &attribute is not changed to 5, it continues the next call with the "" value.
I tried making it a pointer reference *attribute->n->attribute
And tied a reference &attribute = n->attribute
These were shots in the dark and did not work.
EDIT: addNode should have been called with individual memory references.
string test1="";
string test2="";
string test3="";
addNode(root, "wordy", test1, test2, test3);
Have you tried initializing attribute in a constructor?
struct nodeT {
bool last;
string attribute;
vector<charT> leafs;
nodeT() : attribute("5") {}
};
Your code looks somewhat, but not entirely, unlike Java... :-)
No of args for function declaration and function call don't match and function dosnt have variable arg. It should not clear compilation hurdels also.
The answers made by the contributors helped lead me to the answer but they have been hitting answers slightly off from the issue.
For setup, function uses structs nodeT and charT
and is was called with the equivalent of
root is defined globally in the class
string wordy = "hello";
string test="";
addNode(root, "wordy", test, test, test);
addNode should have been called with individual memory references.
string test1="";
string test2="";
string test3="";
addNode(root, "wordy", test1, test2, test3);
So when later when attributes 1, 2 and 3 are changed with unique values, there is a corresponding unique memory for each.