/* Update on Oct 7th
Finally figured out the reason for the malfunction of str destructor.
It is really about pass-by-reference, which means when I call "a.inputName_by_Seq(n2, 10);"(just as an instance)
the str "n2" is actually partially passed by reference, and that part is "n2.element", which is a pointer itself.
although the function " inputName_by_Seq" generated another str "name" within its domain, the element of "name" is EXACTLY pointing to the SAME content which the element of "n2" is pointing to. So when the generated "name" is destructed as " inputName_by_Seq" ceases, the content of "n2.element" is freed as well. So when the main function ends, another freeing operation of "n2.element" leads to an error.
A way thereby to avoid this malfunction is to produce a switch(named "coin" here) to stop the freeing operation
at the end of "inputName_by_Seq". The other things of the parameter "name", such as its coin, and its len, will be released,
while the pointer "element" stays until the end of main function.
well, maybe not so elegant... but it works..
if you have any better solution, just reply please!
*/
/*Since school has begun, daily updating seems quite impratical, but I will try to keep it weekly..
This time the content is much more complex and it took me quite a while to figure out all the mistakes
the scope of destructor is determined by its initialization. here I initialized a in main func, BUT the destructor of a is called as soon as I
activate functions concerning str class, thus the free() in destructor will be repeatively called, causing bugs. No idea at all...
but apart from that everything of the first list I built worked fine. it is a singly linked list which contains nodes of students' sequence number ,name and score
*/
Finally figured out the reason for the malfunction of str destructor.
It is really about pass-by-reference, which means when I call "a.inputName_by_Seq(n2, 10);"(just as an instance)
the str "n2" is actually partially passed by reference, and that part is "n2.element", which is a pointer itself.
although the function " inputName_by_Seq" generated another str "name" within its domain, the element of "name" is EXACTLY pointing to the SAME content which the element of "n2" is pointing to. So when the generated "name" is destructed as " inputName_by_Seq" ceases, the content of "n2.element" is freed as well. So when the main function ends, another freeing operation of "n2.element" leads to an error.
A way thereby to avoid this malfunction is to produce a switch(named "coin" here) to stop the freeing operation
at the end of "inputName_by_Seq". The other things of the parameter "name", such as its coin, and its len, will be released,
while the pointer "element" stays until the end of main function.
well, maybe not so elegant... but it works..
if you have any better solution, just reply please!
*/
/*Since school has begun, daily updating seems quite impratical, but I will try to keep it weekly..
This time the content is much more complex and it took me quite a while to figure out all the mistakes
the scope of destructor is determined by its initialization. here I initialized a in main func, BUT the destructor of a is called as soon as I
activate functions concerning str class, thus the free() in destructor will be repeatively called, causing bugs. No idea at all...
but apart from that everything of the first list I built worked fine. it is a singly linked list which contains nodes of students' sequence number ,name and score
*/
#include<iostream>
#include<cstring> //for memcpy()
#include<cstddef> //for size_t
using namespace std;
class str { //str is a class of string which is enabled to automatically grow or decline in size
friend ostream& operator<<(ostream& out, const str& s); //so that "<<" is compatible with native classes from left or from right
public:
str();
~str() { if (coin) { free(element); } }
str(const char* ch);
str& operator=(const char ch[]); //overloading the heavily used operators to nativize the class
str& operator=(const str&);
bool operator==(const str&);
bool operator==(const char ch[]);
bool operator!=(const str&);
bool operator!=(const char ch[]);
void coinTurnFalse() { coin = false; }
void coinTurnTrue() { coin = true; }
bool getCoin() { return coin; }
private:
char *element;
bool coin;
size_t len;
str& Resize(size_t n); //Resize() is used when the string size needs to be remodified
};
str::str() //default constructor generates a void string
{
element = (char*)malloc(sizeof(char));
element[0] = 0;
len = 0;
}
str::str(const char ch[])
{
if (strlen(ch)>len)
len = strlen(ch);
*this = Resize(len + 1);
for (size_t i = 0; i<len; i++)
element[i] = ch[i];
element[len] = 0;
}
str& str::Resize(size_t n)
{
element = (char*)realloc(element, sizeof(char)*n);
return *this;
}
str& str::operator=(const char ch[])
{
len = strlen(ch);
/*if (len>strlen(element))
{
if (element)
*this = Resize(len + 1);
else
element = (char*)malloc(sizeof(char)*(len + 1));
}*/
if (len>strlen(element))
*this = Resize(len + 1);
for (size_t i = 0; i<len; i++)
element[i] = ch[i];
element[len] = 0;
return *this;
}
str& str::operator=(const str& s)
{
len = s.len;
element = (char*)malloc(sizeof(char)*(len + 1));
for (size_t i = 0; i<len; i++)
element[i] = s.element[i];
/*memcpy(element, s.element, sizeof(char)*len);*/
element[len] = 0;
return *this;
}
bool str::operator==(const str& s)
{
int i = 0;
while (element[i] == s.element[i] && element[i] != 0 && s.element[i] != 0)
i++;
if (i == len&&i == s.len)
return true;
else return false;
}
bool str::operator==(const char ch[])
{
int i = 0;
while (element[i] == ch[i] && element[i] != 0 && ch[i] != 0)
i++;
if (i == len&&i == strlen(ch))
return true;
else return false;
}
bool str::operator!=(const str& s)
{
int i = 0;
while (element[i] == s.element[i] && element[i] != 0 && s.element[i] != 0)
i++;
if (i == len&&i == s.len)
return false;
else return true;
}
bool str::operator!=(const char ch[])
{
int i = 0;
while (element[i] == ch[i] && element[i] != 0 && ch[i] != 0)
i++;
if (i == len&&i == strlen(ch))
return false;
else return true;
}
ostream& operator<<(ostream& out, const str& s)
{
out << s.element;
return out;
}
/*----------------------- Above is the str class for storing the name ------------------------------*/
/*--------------------Below is the singly linked list for storing student files---------------------*/
struct node { //set the node in the singly linked list
node *next;
int score;
str name;
int sequence;
};
class slinkedlist { //this is a list which contains the scores and names with sequence number in ascending order
public:
slinkedlist() { head = (node*)new(node); head->next = NULL; }
~slinkedlist() { delete head; cout << "finished." << endl; } //destructor used to avoid memory leak
node* getHead() { return head; }
int inputScore_by_Name(int Score, str Name);
int inputScore_by_Seq(int Score, int seq);
int insertNode(int seq);
int deleteNode(int seq);
int inputName_by_Seq(str Name, int seq);
void outputList();
void displayNode_Name(int seq);
void displayNode_Score(int seq);
private:
node *head;
};
int slinkedlist::inputScore_by_Name(int score, str name) // -1 for multiple names; 0 for search failure; 1 for success
{
name.coinTurnFalse();
node *prs;
int seq;
int dup = 0;
if (head->next == NULL || head == NULL)
return 0;
else
{
prs = head->next;
do {
if (prs->name == name)
{
dup++;
seq = prs->sequence;
}
if (prs->next != NULL)
prs = prs->next;
} while (prs->next != NULL);
}
if (dup == 0)
return 0;
else if (dup>1)
return -1; //strengthen the immunity to duplications
else
{
inputScore_by_Seq(score, seq);
return 1;
}
return 0;
}
int slinkedlist::inputScore_by_Seq(int score, int seq) // 0 for search failure; 1 for success
{
if (head->next == NULL || head == NULL)
return 0;
else
{
node *pro = head->next;
while (seq > pro->sequence&&pro->next != NULL)
pro = pro->next;
if (seq == pro->sequence)
{
pro->score = score;
return 1;
}
else
return 0;
}
return 0;
}
int slinkedlist::inputName_by_Seq(str name, int seq) //-1 for ungeneration; 0 for search failure; 1 for success
{
name.coinTurnFalse();
if (head == NULL)
return -1;
else if (head->next == NULL)
return 0;
else
{
node *prs = head->next;
while (seq > prs->sequence&&prs->next != NULL)
prs = prs->next;
if (seq == prs->sequence)
{
prs->name = name;
return 1;
}
else
return 0;
}
return 0;
}
int slinkedlist::deleteNode(int seq) //-1 for ungeneration; 0 for search failure; 1 for success
{
if (head == NULL)
return -1;
else if (head->next == NULL)
return 0;
else
{
node *prs = head->next;
node *temp = prs;
while (seq > prs->sequence&&prs->next != NULL)
{
temp = prs;
prs = prs->next;
}
if (seq == prs->sequence)
{
if (prs == head->next)
{
head->next = prs->next;
delete prs;
return 1;
}
else if (prs->next == NULL)
{
temp->next = NULL;
delete prs;
return 1;
}
else
{
temp->next = prs->next;
delete prs;
return 1;
}
}
else
return 0;
}
return 0;
}
int slinkedlist::insertNode(int seq) // -1 for ungeneration; 0 for multiple existence failure; 1 for success
{
node *ptr, *pro, *temp;
ptr = (node *)new(node);
if (head == NULL)
return -1;
else if (head->next == NULL) // an empty list
{
head->next = ptr;
ptr->sequence = seq;
ptr->next = NULL;
ptr->score = 0;
return 1;
}
else
{
pro = temp = head->next;
while (seq > pro->sequence && pro->next != NULL)
{
temp = pro;
pro = pro->next;
}
if (head->next == pro) // operating the first node
{
if (seq > pro->sequence)
{
pro->next = ptr;
ptr->sequence = seq;
ptr->next = NULL;
ptr->score = 0;
return 1;
}
else if (seq < pro->sequence)
{
ptr->next = pro;
head->next = ptr;
ptr->score = 0;
ptr->sequence = seq;
return 1;
}
else if (seq == pro->sequence)
return 0;
}
else if (pro->next == NULL) //operating the last node
{
if (seq != pro->sequence)
{
ptr->next = NULL;
ptr->sequence = seq;
ptr->score = 0;
pro->next = ptr;
return 1;
}
else if (seq == pro->sequence)
return 0;
}
else //common cases
{
if (seq == pro->sequence)
return 0;
else
{
temp->next = ptr;
ptr->next = pro;
ptr->sequence = seq;
ptr->score = 0;
return 1;
}
}
}
return 0;
}
void slinkedlist::displayNode_Name(int seq)
{
if (head == NULL)
cout << "List ungenerated. Please check." << endl;
else if (head->next == NULL)
cout << "No such sequence number found. Please check." << endl;
else
{
node *prs = head->next;
while (seq > prs->sequence && prs->next != NULL)
prs = prs->next;
if (seq == prs->sequence)
cout << "Name:" << prs->name << endl;
else
cout << "No such sequence number found. Please check." << endl;
}
}
void slinkedlist::displayNode_Score(int seq)
{
if (head == NULL)
cout << "List ungenerated. Please check." << endl;
else if (head->next == NULL)
cout << "No such sequence number found. Please check." << endl;
else
{
node *prs = head->next;
while (seq > prs->sequence && prs->next != NULL)
prs = prs->next;
if (seq == prs->sequence)
cout << "Score:" << prs->score << endl;
else
cout << "No such sequence number found. Please check." << endl;
}
}
void slinkedlist::outputList()
{
if (head == NULL)
cout << "List ungenerated. Please check." << endl;
else if (head->next == NULL)
cout << "List is empty. Please check." << endl;
else
{
node *prs = head->next;
int seq;
while (prs!=NULL)
{
cout << endl;
seq = prs->sequence;
displayNode_Name(seq);
cout << "Sequence number:" << seq << endl;
displayNode_Score(seq);
prs = prs->next;
}
}
}
int main()
{
slinkedlist a;
a.insertNode(1);
str n1, n2;
n1 = "Jason";
n2 = "Daisy";
a.inputName_by_Seq(n1, 1);
a.inputScore_by_Name(100, n1);
a.displayNode_Name(1);
a.displayNode_Score(1);
a.inputScore_by_Seq(98, 1);
a.displayNode_Score(1);
a.insertNode(10);
a.inputName_by_Seq(n2, 10);
a.displayNode_Name(10);
a.inputScore_by_Seq(98, 10);
a.outputList();
cout << a.deleteNode(1) << endl;
a.outputList();
system("pause");
return 0;
}