Implementing a queue structure from scratch (C++) - c++

I have to implement a queue from the scratch for an assignment without using any premade lib. It's working fine when I Enqueue e Dequeue, but when I Dequeue a unary queue (with just one element) and I print it, doesn't show that it is empty, the Print function actually print blank spaces, and when try to Enqueue new elements after Dequeuing the whole list it simply does not push new elements. Looks like that the reference to the first element got lost. If someone could help, here is the code:
structs:
typedef struct{
int number;
}TItem;
typedef struct cell{
struct cell *pNext;
TItem item;
}TCell;
typedef struct{
TCell *pFirst;
TCell *pLast;
}TQueue;
And the imlementations:
void Init(TQueue* pQueue){
pQueue->pFirst = new TCell;
pQueue->pLast = pQueue->pFirst;
pQueue->pFirst->pNext = NULL;
}
int Is_Empty(TQueue* pQueue){
return (pQueue->pFirst == pQueue->pLast);
}
int Enqueue(TQueue* pQueue, TItem x){
pQueue->pLast->pNext = new TCell;
pQueue->pLast = pQueue->pLast->pNext;
pQueue->pLast->item = x;
pQueue->pLast->pNext = NULL;
return 1;
}
int Dequeue(TQueue* pQueue, TItem* pX){
if(Is_Empty(pQueue))
return 0;
TCell* aux;
aux = pQueue->pFirst->pNext;
*pX = aux->item;
pQueue->pFirst->pNext = aux->pNext;
delete aux;
return 1;
}
void Print(TQueue* pQueue){
if(Is_Empty(pQueue) == 1)
cout << "EMPTY"<<endl;
TCell *temp;
temp = pQueue->pFirst->pNext;
cout << "Queue:"<<endl;
while( temp != NULL){
cout << temp->item.number << " ";
temp = temp->pNext;
}
}
PS: The memory allocation for the queue is made on the main block

Problem
Your Dequeue logic is invalid. All you need to do when dequeing is remove the first item in the queue.
Solution
int Dequeue(TQueue* pQueue, TItem* pX){
if(Is_Empty(pQueue))
return 0;
TCell* aux;
//aux = pQueue->pFirst->pNext;
aux = pQueue->pFirst;
//*pX = aux->item;
//pQueue->pFirst->pNext = aux->pNext;
pQueue->pFirst = aux->pNext;
delete aux;
return 1;
}
Also I don't know why you need to pass TItem* pX as you don't really use it.

Related

Inserting a basic singly linked list node seems to break my c++ code?

Singly Linked List and Node classes and the start of the main function, where I wrote a brief outline of the code functionality. The issue is toward the end of the main function. I wrote '...' in place of what I believe to be irrelevant code because it simply parses strings and assigns them to the string temp_hold[3] array.
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
string value;
string attr;
string tagname;
Node *next;
Node(string c_tagname, string c_attr, string c_value) {
this->attr = c_attr;
this->value = c_value;
this->tagname = c_tagname;
this->next = nullptr;
}
};
class SinglyLinkedList {
public:
Node *head;
Node *tail;
SinglyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void insert_node(string c_tagname, string c_attr,string c_value) {
Node *node = new Node(c_tagname,c_attr, c_value);
if (!this->head) {
this->head = node;
} else {
this->tail->next = node;
}
this->tail = node;
}
};
int main(int argc, char **argv) {
/* storage is a vector holding pointers to the linked lists
linked lists are created and the linked list iterator sll_itr is incremented when
previous line begins with '</' and the currentline begins with '<'
linked lists have nodes, which have strings corresponding to tagname, value, and attribute
*/
SinglyLinkedList *llist = new SinglyLinkedList();
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
string temp_hold[3];
// to determine new sll creation
bool prev = false;
bool now = false;
//input
int num1, num2;
cin >> num1; cin >> num2;
//read input in
for (int i = 0; i <= num1; ++i) {
string line1, test1;
getline(cin, line1);
test1 = line1.substr(line1.find("<") + 1);
//determine to create a new linked list or wait
if (test1[0] == '/') {
prev = now;
now = true;
} else {
//make a node for the data and add to current linked list
if (i > 0) {
prev = now;
now = false;
//if last statement starts with '</' and current statment starts with '<'
// then start a new sll and increment pointer to vector<SinglyLinkedList*>
if (prev && !now) {
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp);
sll_itr++;
}
}
//parse strings from line
int j = 0;
vector<string> datastr;
vector<char> data;
char test = test1[j];
while (test) {
if (isspace(test) || test == '>') {
string temp_for_vect(data.begin(),data.end());
if (!temp_for_vect.empty()) {
datastr.push_back(temp_for_vect);
}
data.clear();
} else
if (!isalnum(test)) {
} else {
data.push_back(test);
}
j++;
test = test1[j];
}
//each node has 3 strings to fill
int count = 0;
for (auto itrs = datastr.begin(); itrs!=datastr.end(); ++itrs) {
switch (count) {
case 0:
temp_hold[count]=(*itrs);
break;
case 1:
temp_hold[count]=(*itrs);
break;
case 2:
temp_hold[count]=(*itrs);
break;
default:
break;
}
count++;
}
}
cout << "before storing node" << endl;
(*sll_itr)->insert_node(temp_hold[0], temp_hold[1], temp_hold[2]);
cout << "after" << endl;
}
cout << "AFTER ELSE" << endl;
return 0;
}
And here is the line that breaks the code. The auto sll_itr is dereferenced which means *sll_itr is now a SinglyLinkedList* and we can call the insert_node(string, string, string) to add a node to the current linked list. However when I keep the line, anything after the else statement brace does not run, which means the cout<<"AFTER ELSE"<< endl; does not fire. If I remove the insert_node line, then the program runs the cout<<"AFTER ELSE"<< endl; I am unsure what the issue is.
(*sll_itr)->insert_node(temp_hold[0],temp_hold[1],temp_hold[2]);
cout << "after" << endl;
} //NOT HANGING. This closes an else statement.
cout << "AFTER ELSE" << endl;
return 0;
}
Compiled as g++ -o myll mylinkedlist.cpp and then myll.exe < input.txt And input.txt contains
8 3
<tag1 value = "HelloWorld">
<tag2 name = "Name2">
</tag2>
</tag1>
<tag5 name = "Name5">
</tag5>
<tag6 name = "Name6">
</tag6>
Your linked list isn't the problem, at least not the problem here.
A recipe for disaster in the making: retaining, referencing, and potentially manipulating, an iterator on a dynamic collection that potentially invalidates iterators on container-modification. Your code does just that. tossing out all the cruft between:
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
....
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp); // HERE: INVALIDATES sll_iter on internal resize
sll_itr++; // HERE: NO LONGER GUARANTEED VALID; operator++ CAN INVOKE UB
To address this, you have two choices:
Use a container that doesn't invalidate iterators on push_back. There are really only two sequence containers that fit that description: std::forward_list and std::list.
Alter your algorithm to reference by index`, not by iterator. I.e. man your loop to iterate until the indexed element reaches end-of-container, then break.
An excellent discussion about containers that do/do-not invalidate pointers and iterators can be found here. It's worth a read.

Program Terminates unexpectedly C++

The goal of the program is to simulate a medical complex with 6 "Doctor Queues". I tried keeping it close enough to the Java version I've completed (must do this in 3 languages). At this point when I run the DequeuePatients and ListPatients method, the program terminates unexpectedly with no errors. I've tried the debugger but eclipse is ignoring all my breakpoints.Why is it terminating?
The ListPatients method is all follows in Driver class:
void ListPatients() {
int x, QueueChoice = 0;
bool exit = false;``
while (!exit) {
for (x = 1; x <= MAX; x++) {
cout << x << ": " << Doctor[x - 1] << "\n";
} // end-for
cout << "Choose a Queue to List From";
cin >> QueueChoice;
if (OpenFlag[QueueChoice - 1] == true) { //open flag for each queue
int i = Complex[QueueChoice - 1]->GetSize();//Global array of queues
//cout <<i<<endl;
Terminates in this loop if function is called
for (x = 1; x <= i; x++) {
Patient This = Complex[QueueChoice-1]->GetInfo(x); //Program Terminates here
cout << x<< ": " << endl;//This.ID_Number;
//<<Complex[QueueChoice - 1]->GetInfo(x + 1).PrintMe()
} // end-for
} // end-if
cout << "Press 1 to List Another Queue, press 2 to exit";
cin >> x;
switch (x) {
case 1:
break;
case 2:
exit = true;
break;
}//switch
} // end-while
} // List Patients`
Queue Class GetInfo and toArray():
/*Return Patient info from each Node*/
Patient Queue::GetInfo(int Pos) {
Node* ComplexArray= new Node[Length];
ComplexArray = this->toArray();
return ComplexArray[Pos - 1].Info;
}
// The toArray method
Node* Queue::toArray() {
// Copy the information in each node to an array and return the array.
int x = Length;
Node ComplexArray[Length] ={} ;
Node* Current = new Node();
Current = Rear;`
for (x = 0; x<Length;x++) {
ComplexArray[x] = Node();
ComplexArray[x].Modify(Current);
Current = Current->Next;
}
return ComplexArray;
} // End of toArray method
Modify Method in Node:
void Node :: Modify(Node* ThisNode)
{
Info = ThisNode->Info;
Next = ThisNode->Next;
}
If this is base-zero why are you subtracting 1 from x
for (x = 0; x<Length;x++) {
ComplexArray[x-1] = Node();
ComplexArray[x - 1].Modify(Current);
Current = Current->Next;
}
Subscript errors are hard crashes in C/C++.
The problem was sort of basic, it was way I was declaring my pointers, as well as changing the toArray function to return a Patient pointer(That can be treated as an array?) as apposed to Node, and not just to the first element of the array.
this caused toArray to return one Node pointer, with that instances Next pointer continuously pointing to itself.
Queue Complex[6] = Queue(); //in driver class
Patient* ComplexArray[Length] = new Patient();//Queue Class GetInfo & toArray
I needed:
Queue* Complex = new Queue[MAX];
Patient* ComplexArray = new Patient[Length];
and changed these functions:
Patient Queue::GetInfo(int Pos) {
Patient* ComplexArray = new Patient[Length];
ComplexArray= toArray();
return ComplexArray[Pos - 1];
}
// Now returns Patient pointer of Node->Info to GetInfo
Patient* Queue::toArray() {
Node* Current;
int x;
Patient* ComplexArray = new Patient[Length];
Current = Rear;
for (x = 1; x <= Length; x++) {
ComplexArray[x-1] = Patient();
ComplexArray[x - 1].Modify(Current->Info);
Current = Current->Next;
}
return ComplexArray;
} // End of toArray method

Pouring via Depth First Search node linking to itself. C++

Working on a program to solve the pouring problem:
I believe I am down to one last issue. My data structure is as follows:
I have an vector of Node pointers and each node contains a int array, and an address to the next node. In testing everything functions properly. The goal of this data structure is to basically function as an adjacency list. Where each node is linked to the nodes that it would have an edge to.
Currently my problem is when I am attempting to link these nodes to one another:
the LinkState function that I have should accomplish this, however it is instead resulting in the program running...forever.
The function should simply iterate through the individual nodes linked list and find where to connect the new node. Instead it is causing a node to constantly be leak to itself..which is leading to the runtime issue.
Sorry if this is a bit confusing. Any help would be greatly appreciated.
p.s. I know there are better ways to solve this problem like BFS, I'd like to stick to DFS.
#ifndef _POURINGLIST_H_
#define _POURINGLIST_H_
#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
struct Node{
int state[3];
Node* next = NULL;
};
class PouringList{
Node* init;
vector<Node*> Head;
int max[3];
int steps;
public:
PouringList(){
//max values for comaprison
max[0] = 10;
max[1] = 7;
max[2] = 4;
//init values to begin DFS
init = new Node;
init->state[0] = 0;
init->state[1] = 7;
init->state[2] = 4;
};
//private methods not to be called by user
private:
//pours some good old h2o
Node pour(Node* curr_state, int A, int B){
int a = curr_state->state[A];
int b = curr_state->state[B];
int change = min(a, max[B]-b);
Node newState = *curr_state;
newState.state[A] = (a-=change);
newState.state[B] = (b+=change);
return newState;
}
//O(n) complexity used to check if a node is already in head
bool isIn(Node* find_me){
for(vector<Node*>::iterator i = Head.begin(); i != Head.end(); i++) {
if (equal(begin(find_me->state), end(find_me->state), begin((*i)->state)))
return true;
}
return false;
}
void printNode(Node* print){
for(int i = 0; i < 3; i++){
cout << print->state[i] << " ";
}
cout << endl;
}
int locate(Node* find_me){
for(vector<Node*>::iterator i = Head.begin(); i != Head.end(); i++) {
if (equal(begin(find_me->state), end(find_me->state), begin((*i)->state)))
return distance(Head.begin(), i);
}
return -1;
}
void LinkState(Node* head, Node * nxt){
Node* vert = Head[locate(head)];
while(vert->next != NULL){
vert = vert->next;
}
vert->next = nxt;
}
public:
void DFS(){
steps = 0;
//start exploring at initial value
explore(init);
}
void explore(Node* vertex){
//base case to end
if(!isIn(vertex)){
Head.push_back(vertex);
if(vertex->state[1] == 2 || vertex->state[2] == 2){
cout << steps << endl;
printNode(vertex);
return;
}
//generate all possible states and connects them to Head vertex
else{
for(int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++){
Node conn1 = pour(vertex,i,j);
Node *conn = &conn1;
if(i!=j && !isIn(conn)){
cout << i << " adds water to " << j << endl;
LinkState(vertex, conn);
}
}
}
}
Node* Nextex = vertex;
//printNode(vertex);
while(Nextex != NULL){
//new neighbor
if(!isIn(Nextex)){
//printNode(Nextex);
explore(Nextex);
}
Nextex = Nextex->next;
}
}
//printNode(Nextex);
else{
cout <<"Dead end" << endl;
}
}
//start from init node and show path to solution
void display(){
Node *output;
for(int i = 0; i < Head.size(); i++){
output = Head[i];
while ( output != NULL){
printNode(output);
output = output->next;
}
cout << '#' <<endl;
}
}
};
#endif // _POURINGLIST_
basic driver:
#include "PouringList.h"
int main(){
PouringList s1;
s1.DFS();
}
Edit
I've attempted the suggested fix before (This is what I'm assuming you mean). It still lead to the programming running forever. Also I do not know enough about smartpointers to go and overhaul the application!
Node conn1 = pour(vertex,i,
Node *conn = new Node;
conn = &conn1;
You are storing the address of a local variable in your list.
In explore, you have
Node conn1 = pour(vertex,i,j);
Node *conn = &conn1;
then later pass conn to LinkState, which stores that pointer in your PouringList. All your added nodes will point at the same memory address.
What you should be doing is allocating a new Node and using that (preferably using some sort of smart pointer rather than storing raw pointers so the clean up will happen automatically).

C++ memory leak, where?

I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.

trouble with linked list values C++

I'm trying to teach myself c++. to do so I made a challenge for myself to write a prime finder app. I've succeeded once in python (to learn python) with a less efficient algorithm. I'm using a doubly linked list to store the primes. currently I'm just trying to run this in a single thread but I made it doubly linked so I could multithread it later on.
anyway, TL;DR the debugger is showing the program getting stuck trying to assign a value to the start link's prm int in the Prime constructor I've done a bunch of searching but I can't figure out what I'm doing wrong. (also note the bings are debug messages)
#include <iostream>
#include <math.h>
#include <cmath>
using namespace std;
using std::cout;
struct PLink{
int prm;
PLink *next;
PLink *prev;
};
class Prime{
public:
PLink *start, *end;
Prime(){
start -> prm = 2;
end -> prm = 3;
start->next = end;
end->next = NULL;
start->prev = NULL;
end->prev = start;
addToEnd(5);
cout <<"cbing" << endl;
}
void insert(int val){
}
void addToEnd(int val){//adds a new prime to the end of the list
PLink *tmp = new PLink;
tmp->prm = val;
tmp->prev = end;
end->next = tmp;
tmp->next = NULL;
tmp = end;
cout << tmp->prm << endl;
cout << "addbing" << endl;
}
bool comp(int pot){ //compares the potential prime against known primes via modulo
int lim = sqrt(pot);
PLink * current = start;
bool check = false;
cout<<"bing " << pot << endl;
while (current->prm < lim && check == false){
if (pot%current->prm == 0) {
check = true;}
current = current->next;
}
return check; //false means its prime true means its not
}
};
int main()
{
Prime primeList;
int cap = 10000;
int beg = 5;
int count = 3;
bool toggle = false;
bool check = false;
cout << "2 \n3 \n5" << endl;
while(count < cap){
beg += 2;
cout << "bing" << endl;
if (toggle){
beg += 2;}
toggle = !toggle;
check = primeList.comp(beg);
if (check == false){
primeList.addToEnd(beg);
count++;
cout << "bing2" << endl;
}
}
};
using namespace std;
using std::cout;
the second using std::cout; is redundant, you can read some documents about C++ name visibility, like this:
http://www.cplusplus.com/doc/tutorial/namespaces/
http://www.tutorialspoint.com/cplusplus/cpp_namespaces.htm
Prime(){
start -> prm = 2;
end -> prm = 3;
start->next = end;
end->next = NULL;
start->prev = NULL;
end->prev = start;
addToEnd(5);
cout <<"cbing" << endl;
}
Note: when you declare a pointer like PLink *start, *end; C++ complier(say 'gcc' or clang) only allocate memory to store that pointer, but not allocate memory to store what your pointer is pointed(here it means your PLink object).
So, you should allocate memory for your PLink object pointed by these two pointers: PLink *start, *end;, that is to say, you have to change the above code to:
Prime(){
start = new PLink(); // use the default constructor generated by C++ complier since you haven't declared one in struct PLink
end = new PLink()
start -> prm = 2;
end -> prm = 3;
start->next = end;
end->next = NULL;
start->prev = NULL;
end->prev = start;
addToEnd(5);
cout <<"cbing" << endl;
}
Well, in order not to cause memory leak and double free the same pointer, you should carefully manipulate the object you created.