I delete the pointer aStudent in the destroyStudent() function, then I set aStudent to nullptr. However, after running the function, aStudent is not set to nullptr anymore, so I have to set it to nullptr again.
#include <cstring>
using namespace std;
struct Student {
char * name;
float gpa;
};
Student * createStudent(const char name[], float gpa) {
struct Student * student = new Student;
student->name = (char*)malloc(strlen(name + 1)); //allocate only enough memory to fit the given name
strcpy(student->name, name);
student->gpa = gpa;
return student;
}
bool destroyStudent(Student * aStudent) {
if(aStudent) { //check whether this pointer is already null.
free(aStudent->name);
delete aStudent; // ******This is where the issue is******
aStudent = nullptr;
return true;
}
return false; //aStudent is already null
}
int main() {
Student * student1 = createStudent("Charles", 2.5);
cout << student1->name << " and " << student1->gpa << endl;
destroyStudent(student1);
if(student1) {
cout << "Pointer is NOT null!!!" << endl;
student1 = nullptr;
}
if(!student1) {
cout << "The pointer is null now." << endl;
}
return 0;
}
The problem is that aStudent is a local copy of the pointer.
You need to pass the pointer in by reference like this:
bool destroyStudent(Student*& aStudent) {
if(aStudent) { //check whether this pointer is already null.
free(aStudent->name);
delete aStudent; // ******This is where the issue is******
aStudent = nullptr;
return true;
}
return false; //aStudent is already null
}
That way it is the outside pointer you change, not a local copy.
C++ uses pass-by-value.
You're setting the variable local to your destroyStudent() method to nullptr, not the variable in your main().
Related
If we have a vector of struct pointer MyInfo* (allocated on heap). Then we can check vec[i] == NULL to know whether there is a struct in the vec[i], like this, if (vec[i] != NULL) //then do some processing
However, if we allocate MyInfo on stack instead of on heap, then we have vector<MyInfo> as shown below. I guess each vec[i] is initialized by the struct default constructor. How do you check whether vec[i] contains a non-empty struct similar to above NULL pointer case, like if (vec[i] contains valid struct) //then do some processing
My code is below
#include <iostream> // std::cout
#include <string>
#include <vector>
using namespace std;
struct MyInfo {
string name;
int age;
};
int main () {
vector<MyInfo> vec(5);
cout << "vec.size(): " << vec.size() << endl;
auto x = vec[0];
cout << x.name << endl; //this print "" empty string
cout << x.age << endl; //this print 0
return 0;
}
There are some options you can use. The first and easiest one, is to define a value to each (or for one) of your struct's variables, that will point that the struct is not initialized yet. In this case, age should be large or equal to 0, to be logicly straight. So, you can initialize it to -1, like this:
struct MyInfo {
string name;
int age = -1;
};
// Or
struct MyInfo {
string name;
int age;
MyInfo() : name(""), age(-1) {} // Use constructor
};
Now, in your main function, it will print in the age the value -1. Also, you can see the empty of the name variable as a sign for it too.
Another way might be using flag and get/set operations to indicate when the variables are initialize:
struct MyInfo {
private:
std::string _name;
int _age;
bool age_initialize = false;
bool name_initialize = false;
public:
void name(const std::string &name_p) { _name = name_p; name_initialize = true; }
void age(int age_p) { _age = age_p; age_initialize = true; }
void init(int age_p, const std::string &name_p) { age(age_p); name(name_p); }
bool is_initialize() { return name_initialize && age_initialize; }
int age() { return _age; }
std::string name() { return _name; }
};
int main() {
std::vector<MyInfo> vec(5);
std::cout << "vec.size(): " << vec.size() << std::endl;
auto x = vec[0];
std::cout << x.is_initialize() << std::endl; //this print 0
std::cout << x.name() << std::endl; //this print "" empty string
std::cout << x.age() << std::endl; //this print 0
return 0;
}
You can also throw an exception when calling int age() of std::string name() function, if those values are not initialize yet:
struct MyInfo {
private:
/* ... */
public:
/* ... */
int age() {
if (!age_initialize) throw std::runtime_error("Please initialize age first.");
return _age;
}
std::string name() {
if (!name_initialize) throw std::runtime_error("Please initialize name first.");
return _name;
}
};
I have a class Employee with pointer variables tag and values of type char and a self reference pointer children. We also have another two integer variables "numAttributes" and "numChildren". "numChildren" specifies how may children can be added to the class. "numAttributes" is for future purpose. I have to allocate and deallocate memory. For this I'm trying to implement a copy constructor and a destructor. The problem I am facing is, I couldn't able to deep copy the whole class when it has the children var not NULL. I have tried using memcpy() and also the solution mentioned here. But I couldn't able to do it properly. When everything goes well it fails in destructor. What I have tried so far is:
#include<iostream>
#include<stdlib.h>
#include<string>
#include<map>
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
class Employee
{
public:
char* tag;
char* value;
int numAttributes;
int numChildren;
Employee* children;
Employee(const Employee &attr)
{
cout << "Copy constructor called" << endl;
numAttributes = attr.numAttributes;
numChildren = attr.numChildren;
tag = (char*)malloc(sizeof(char)*strlen(attr.tag) + 1);
value = (char*)malloc(sizeof(char)*strlen(attr.value) + 1);
strcpy(tag, attr.tag);
strcpy(value, attr.value);
if (attr.children == NULL)
children = NULL;
else
children = attr.children; // shallow copy happening. Have to do deep copy if it has children
}
Employee(){
cout << " constructor called" << endl;
tag = NULL;
value = NULL;
children = NULL;
numAttributes = 0;
numChildren = 0;
}
~Employee(){
cout << "Destructor called" << endl;
if (tag != NULL){
free(tag);
tag = NULL;
}
if (value != NULL){
free(value);
value = NULL;
}
if (children != NULL){
free(children);
children = NULL;
}
}
};
Employee createNode(const char* tag, const char* value, unsigned int numAttributes, unsigned int numChildren)
{
Employee retNode;
retNode.tag = (char*)malloc(sizeof(char)* (strlen(tag) + 1));
strcpy(retNode.tag, tag);
retNode.value = (char*)malloc(sizeof(char)* (strlen(value) + 1));
strcpy(retNode.value, value);
retNode.numAttributes = numAttributes;
retNode.numChildren = numChildren;
//use this block if we are not initializing the children in the createOffset() method
/*if (numChildren == 0){
retNode.children = NULL;
}
else{
retNode.children = (Employee*)malloc(sizeof(Employee)*numChildren);
}*/
return retNode;
}
Employee createOffset()
{
//Create and tag initial root node
Employee retNode = createNode("offset", "value", 0, 1);
retNode.children = (Employee*)malloc(sizeof(Employee)*retNode.numChildren);
retNode.children[0] = createNode("prnt", "0000", 0, 0);
return retNode; // Until here it is fine. This return calls the copy constructor first. As it has children the children must also be deep copied. Getting error here. Have to do deep copy the entire the class
}
Employee get(){
return createOffset();
}
int main(){
Employee node = get();
getchar();
return 0;
}
struct Employee {
std::string tag;
std::string value;
int numAttributes = 0;
std::vector<Employee> children;
};
no need to write a copy constructor or destructor, the C++ language makes one for you that does the right thing here.
This is known as the rule of 0.
Employee createNode(const char* tag, const char* value, unsigned int numAttributes, unsigned int numChildren)
{
return {tag, value, numAttributes, std::vector<Employee>(numChildren)};
}
also a lot shorter.
Employee createOffset()
{
//Create and tag initial root node
Employee retNode = createNode("offset", "value", 0, 1);
retNode.children[0] = createNode("prnt", "0000", 0, 0);
return retNode;
}
and done.
New to programming , but when I try to create this link list I receive an error 'no matching function for call to 'meetings::meetings()' Been through it a few times and I'm just not seeing what it causing the issue.
class meetings{
public:
void duplicatetest (string,memberlist *&head);
void menufn(memberlist *&head);
void meetinginfo( memberlist *&head,string);
string timestamp ( memberlist *&head,string);
memberlist *&head;
string UID;
string timestp;
meetings *timest;
meetings *link;
int meetnum;
string dt;
};
void meetings::meetinginfo(memberlist *&head, string dt ){
string meetingNum;
memberlist *currptr;
meetings *meetptr , *nnmeet ,*meetcurr, *meethead;
meethead= NULL;
if (currptr->meetnum == 0 ) {
meethead = new meetings; // <<< Error appears here!
meetingNum = currptr->UID;
meethead->UID = meetingNum;
meethead->timestp = dt;
meetcurr=meethead;
system ("pause");
}
else {
nnmeet = new meetings;
meetcurr->link= nnmeet;
nnmeet->UID=currptr->UID;
nnmeet->timestp = dt;
}
cout << "Meeting number : ";
menufn(head);
}
using namespace std;
#include "memberlist.h"
#include "meeting.h"
int main(){
system("color f0");
memberlist *member,entermember;
meetings menu, *meet;
entermember.createlinklist(member);
menu.menufn(member);
system("pause");
return 0;
}//End of main
This is the other class I refer to from the meetings class
class memberlist {
public:
void createlinklist (memberlist *&head);
void displaylist (memberlist *&head);
memberlist *link;
string name[2];
string UID;
int meetnum;
};
void memberlist::createlinklist (memberlist *&head)
{
ifstream fin;
memberlist *currptr , *nnptr;
head = NULL;
fin.open ("members.txt");
while (fin)
{
if(head==NULL)
{
head = new memberlist;
fin>>head->UID >> head->name[0] >> head->name[1];
head->meetnum = 0;
currptr = head;
}
nnptr = new memberlist;
currptr->link = nnptr;
fin>>nnptr->UID >> nnptr->name[0] >> nnptr->name[1];
nnptr->meetnum = 0;
currptr = nnptr;
}
currptr->link = NULL;
currptr = NULL;
displaylist(head);
}
void memberlist::displaylist (memberlist *&head)
{
//memberlist *meetptr;
cout << " Student information " << endl;
memberlist *currptr;
currptr = head;
//meetptr = meethead;
while (currptr->link!= NULL)
{
cout << setw(10) << left << currptr->UID << " " << currptr->name[0] <<" " <<
currptr->name[1] <<endl;
currptr= currptr->link;
}
}
The problem is that data member head is defined as a reference.
memberlist *&head;
The compiler is unbale to generate the default constructor becuase it does not know how to initialize the reference. You have to define the constructor yourself.
According to the C++ Standard
A defaulted default constructor for class X is defined as deleted if:
— any non-static data member with no brace-or-equal-initializer is of
reference type,
Also take into account that referebces can be initialized only in the ctor initializer. For example
meetings::meetings( memberlist * &ptr ) : head( ptr )
{
// possible some additional code
}
Or as it is said in the quote I cited in the class definition using brace-or-equal-initializer.
I'm currently writing a class for a program and this is what I'm attempting to accomplish...
Setup: Sets m_ptrEmployee to NULL and m_beginHour to hour.
AssignEmployee: Sets m_ptrEmployee to employee.
GetEmployeeName: Uses m_ptrEmployee and Employee.GetName to return the employees
name. Returns “UNALLOCATED”, if m_ptrEmployee is NULL.
Output: Uses m_ptrEmployee and Employee.GetName to display m_beginHour and the
employee’s name something like this, “8:00 - David Johnson” or like this, “8:00 -
UNALLOCATED”, if m_ptrEmployee is NULL.
Reset: Resets m_ptrEmployee to NULL.
GetIsSet: Returns true, if m_ptrEmployee is not NULL and false otherwise.
Here is my code...
#include <string>
using namespace std;
#include "Employee.h"
class Schedule
{
public:
void Setup( int hour )
{
m_ptrEmployee = NULL;
m_beginHour = hour;
};
void AssignEmployee( Employee* employee )
{
m_ptrEmployee = employee;
};
string GetEmployeeName()
{
if (m_ptrEmployee = NULL)
return "UNALLOCATED"
else
return Employee.GetName()
};
void Output()
{
if (m_ptrEmployee = NULL)
cout>> m_beginHour>>"--">>"UNALLOCATED">>endl;
else
cout>>m_beginHour>>"--">>GetName()>>endl;
}
void Reset()
{
m_ptrEmployee = NULL;
}
bool GetIsSet()
{
if (m_ptrEmployee != NULL)
return true;
else
return false;
}
private:
Employee* m_ptrEmployee;
int m_beginHour;
};
GetName() is included in a previous class and it is...
public:
void Setup( const string& first, const string& last, float pay );
{
m_firstName = first;
m_lastName = last;
m_payPerHour = pay;
m_activeEmployee = true;
}
string GetName()
{
return m_firstName+""+m_lastName
};
I'm receiving multiple errors and I'm not sure what I'm doing wrong? This is my first time attempting to write classes with pointers, so I apologize if my code is absolutely awful.
Here are some corrections:
In general, be careful with comparisons in C++. You can't use the intuitive = when comparing two things. You have to use ==. If you use =, it results in an assignment and not a test. Also, do not forget your semicolon ; at the end of a statement.
Bad comparison:
if (m_ptrEmployee = NULL) //Assigns NULL to m_ptrEmployee and then tests m_ptrEmployee
//Always false because m_ptrEmployee was just assigned NULL
Good comparison:
if (m_ptrEmployee == NULL) //Better. This is false only when m_ptrEmployee equals NULL
When you want to access a member of a class through a pointer (such as m_ptrEmployee), you have to use the -> operator like so: m_ptrEmployee->GetName()
Operator cout is used with the << operator, and not the >> operator.
I have annotated the places in your code where you made mistakes.
#include <string>
using namespace std;
#include "Employee.h"
class Schedule
{
public:
void Setup( int hour )
{
m_ptrEmployee = NULL;
m_beginHour = hour;
};
void AssignEmployee( Employee* employee )
{
m_ptrEmployee = employee;
};
string GetEmployeeName()
{
if (m_ptrEmployee == NULL) //Comparison always takes double ==
return "UNALLOCATED";
else
return m_ptrEmployee->GetName(); //Use employee pointer with -> operator
};
void Output()
{
if (m_ptrEmployee == NULL) //Careful with comparisons. Always use ==, not =
cout << m_beginHour << "--" << "UNALLOCATED" << endl; //Operator << was the other way around. It's not >>, but << for cout
else
cout << m_beginHour << "--" << m_ptrEmployee->GetName() << endl;
}
void Reset()
{
m_ptrEmployee = NULL;
}
bool GetIsSet()
{
if (m_ptrEmployee != NULL)
return true;
else
return false;
}
private:
Employee* m_ptrEmployee;
int m_beginHour;
};
I'm am fairly new to C++.
I have this code from an assignment, i don't quite understand all of it, but i have to make the program give an option at the end for the user to recall any partnumber and model year/engine no. that was entered.
I have no idea on how to go about doing this task... maybe have some kind of id for each node so i can recall it?
Or is it my only option to rewrite the program using an array or vector data structure?
#include <iostream>
using namespace std;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
// **************** Part ************
// Abstract base class of parts
class Part
{
friend void showPart();
public:
Part():itsPartNumber(1) {}
Part(ULONG PartNumber):itsPartNumber(PartNumber){}
virtual ~Part(){};
ULONG GetPartNumber() const { return itsPartNumber; }
virtual void Display() const =0; // must be overridden
private:
ULONG itsPartNumber;
};
// implementation of pure virtual function so that
// derived classes can chain up
void Part::Display() const
{
cout << "\nPart Number: " << itsPartNumber << endl;
}
// **************** Car Part ************
class CarPart : public Part
{
friend void showPart();
public:
CarPart():itsModelYear(94){}
CarPart(USHORT year, ULONG partNumber);
virtual void Display() const
{
Part::Display(); cout << "Model Year: ";
cout << itsModelYear << endl;
}
private:
USHORT itsModelYear;
};
CarPart::CarPart(USHORT year, ULONG partNumber):
itsModelYear(year),
Part(partNumber)
{}
// **************** AirPlane Part ************
class AirPlanePart : public Part
{
friend void showPart();
public:
AirPlanePart():itsEngineNumber(1){};
AirPlanePart(USHORT EngineNumber, ULONG PartNumber);
virtual void Display() const
{
Part::Display(); cout << "Engine No.: ";
cout << itsEngineNumber << endl;
}
private:
USHORT itsEngineNumber;
};
AirPlanePart::AirPlanePart(USHORT EngineNumber, ULONG PartNumber):
itsEngineNumber(EngineNumber),
Part(PartNumber)
{}
// **************** Part Node ************
class PartNode
{
public:
PartNode (Part*);
~PartNode();
void SetNext(PartNode * node) { itsNext = node; }
PartNode * GetNext() const;
Part * GetPart() const;
private:
Part *itsPart;
PartNode * itsNext;
};
// PartNode Implementations...
PartNode::PartNode(Part* pPart):
itsPart(pPart),
itsNext(0)
{}
PartNode::~PartNode()
{
delete itsPart;
itsPart = 0;
delete itsNext;
itsNext = 0;
}
// Returns NULL if no next PartNode
PartNode * PartNode::GetNext() const
{
return itsNext;
}
Part * PartNode::GetPart() const
{
if (itsPart)
return itsPart;
else
return NULL; //error
}
// **************** Part List ************
class PartsList
{
public:
PartsList();
~PartsList();
// needs copy constructor and operator equals!
Part* Find(ULONG & position, ULONG PartNumber) const;
ULONG GetCount() const { return itsCount; }
Part* GetFirst() const;
static PartsList& GetGlobalPartsList()
{
return GlobalPartsList;
}
void Insert(Part *);
void Iterate(void (Part::*f)()const) const;
Part* operator[](ULONG) const;
private:
PartNode * pHead;
ULONG itsCount;
static PartsList GlobalPartsList;
};
PartsList PartsList::GlobalPartsList;
// Implementations for Lists...
PartsList::PartsList():
pHead(0),
itsCount(0)
{}
PartsList::~PartsList()
{
delete pHead;
}
Part* PartsList::GetFirst() const
{
if (pHead)
return pHead->GetPart();
else
return NULL; // error catch here
}
Part * PartsList::operator[](ULONG offSet) const
{
PartNode* pNode = pHead;
if (!pHead)
return NULL; // error catch here
if (offSet > itsCount)
return NULL; // error
for (ULONG i=0;i<offSet; i++)
pNode = pNode->GetNext();
return pNode->GetPart();
}
Part* PartsList::Find(ULONG & position, ULONG PartNumber) const
{
PartNode * pNode = 0;
for (pNode = pHead, position = 0;
pNode!=NULL;
pNode = pNode->GetNext(), position++)
{
if (pNode->GetPart()->GetPartNumber() == PartNumber)
break;
}
if (pNode == NULL)
return NULL;
else
return pNode->GetPart();
}
void PartsList::Iterate(void (Part::*func)()const) const
{
if (!pHead)
return;
PartNode* pNode = pHead;
do
(pNode->GetPart()->*func)();
while (pNode = pNode->GetNext());
}
void PartsList::Insert(Part* pPart)
{
PartNode * pNode = new PartNode(pPart);
PartNode * pCurrent = pHead;
PartNode * pNext = 0;
ULONG New = pPart->GetPartNumber();
ULONG Next = 0;
itsCount++;
if (!pHead)
{
pHead = pNode;
return;
}
// if this one is smaller than head
// this one is the new head
if (pHead->GetPart()->GetPartNumber() > New)
{
pNode->SetNext(pHead);
pHead = pNode;
return;
}
for (;;)
{
// if there is no next, append this new one
if (!pCurrent->GetNext())
{
pCurrent->SetNext(pNode);
return;
}
// if this goes after this one and before the next
// then insert it here, otherwise get the next
pNext = pCurrent->GetNext();
Next = pNext->GetPart()->GetPartNumber();
if (Next > New)
{
pCurrent->SetNext(pNode);
pNode->SetNext(pNext);
return;
}
pCurrent = pNext;
}
}
int main()
{
PartsList pl = PartsList::GetGlobalPartsList();
Part * pPart = 0;
ULONG PartNumber;
USHORT value;
ULONG choice;
while (1)
{
cout << "(0)Quit (1)Car (2)Plane: ";
cin >> choice;
if (!choice)
break;
cout << "New PartNumber?: ";
cin >> PartNumber;
if (choice == 1)
{
cout << "Model Year?: ";
cin >> value;
pPart = new CarPart(value,PartNumber);
}
else
{
cout << "Engine Number?: ";
cin >> value;
pPart = new AirPlanePart(value,PartNumber);
}
pl.Insert(pPart);
}
void (Part::*pFunc)()const = &Part::Display;
pl.Iterate(pFunc);
cout << "\n\n\nThere are " << pl.GetCount() << " items in the list" << endl;
return 0;
}
I tried using The Find() in the PartsList class. Does Find() take the partnumber and return the address of the part?
I wrote this to dereference the retrieved address, but it gives me the error no match for 'operator<<' in 'std::cout << * show':
int findnumber;
ULONG position;
cout << "Enter Partnumber" << endl;
cin >> findnumber;
Part* show = pl.Find(position, findnumber);
cout << *show;
Am i doing this all wrong? D: Show me please...
The function Find does take a part number, but returns a pointer to a part, which is not the same as the address of the part (that would be a reference, denoted by an &). In addition, Find takes a reference to a variable called 'position', so after calling the Find function, the variable that was passed in for 'position' will contain the value of where the part is in the linked list.
The reason you can't use the << operator, is that it hasn't been provided for the Part class. However, from the source code provided, it looks like the objective is for you to understand Polymorphism and rather than trying to use <<, call the Display function on the part that you have found. e.g: -
Part* part = pl.Find(position, findnumber);
part->Display();
This will display the text for the relevant type of part, so if the part returned was a CarPart, the CarPart's Display function will be called, whereas if the part is an AirPlane part, its Display function is called.
If you wanted to use the stream operator (<<) you'd need to overload the io operators, which you can read more about here.
The class PartsList already has a Find() method that could be used to retrieve any part based on its partnumber. You can then call the Display() method of that part.