I am working on unsorted linked list check full currently, below is my specification and implementation.
Specification:
#ifndef UNSORTEDLIST_H
#define UNSORTEDLIST_H
#include <iostream>
using namespace std;
struct Node {
float element;
Node* next;
};
class UnsortedList
{
public:
UnsortedList();
bool IsEmpty();
bool IsFull();
void ResetList();
void MakeEmpty();
int LengthIs();
bool IsInTheList(float item);
void InsertItem(float item);
void DeleteItem(float item);
float GetNextItem();
private:
Node* data;
Node* currentPos;
int length;
};
#endif
And implemetation:
UnsortedList::UnsortedList()
{
length = 0;
data = NULL;
currentPos = NULL;
}
bool UnsortedList:: IsEmpty(){
if(length == 0)
{
return true;
}
else
{
return false;
}
}
bool UnsortedList::IsFull(){
Node* ptr = new Node();
if(ptr == NULL)
return true;
else
{
delete ptr;
return false;
}
}
void UnsortedList::ResetList(){
currentPos = NULL;
}
void UnsortedList::MakeEmpty()
{
Node* tempPtr = new Node();
while(data != NULL)
{
tempPtr = data;
data = data->next;
delete tempPtr;
}
length = 0;
}
int UnsortedList::LengthIs(){
return length;
}
bool UnsortedList:: IsInTheList(float item){
Node* location = new Node();
location = data;
bool found = false;
while(location != NULL && !found)
{
if(item == location->element)
found = true;
else
location = location->next;
}
return found;
}
void UnsortedList:: InsertItem(float item){
Node* location = new Node();
location->element = item;
location->next=data;
data = location;
length++;
}
void UnsortedList:: DeleteItem(float item){
Node* location = data;
Node* tempPtr;
if(item == data->element){
tempPtr = location;
data = data->next;
}
else{
while(!(item == (location->next) ->element) )
location = location->next;
tempPtr = location->next;
location->next = (location->next)->next;
}
delete tempPtr;
length--;
}
float UnsortedList::GetNextItem(){
if(currentPos == NULL)
currentPos = data;
else
currentPos = currentPos->next;
return currentPos->element;
}
1.In the constructor, why don't assign currentPos as null?
2.In the IsInTheList function, Why points to pointer "next" ? Isn't next is a null pointer since it has been declared in struct as Node* next?
The pointer value is not set to NULL value by default, you should set to to null explicitly. Also instead of using NULL, choose using nullptr.
This code is rather incomplete, so it is difficult to answer your questions.
This does not contain the code to insert an item in the list, which is where I would expect both the next and currentPos pointers to be set. However, that's based on a number of assumptions.
However, I don't see where next is used in the "check full function" at all, so that question is a bit confusing.
I'll also point out that this code has a glaring memory leak. The first line in IsInTheList allocates memory for a new Node, which is immediately lost with location = data.
Pointers (like any other basic type) need to be initialized before use. A value of NULL is still a value.
The code you provided seems to be very incomplete. Is data supposed to be the head of your list? I am not sure how you define "fullness". If you want to test if the list is empty, you can see if your "head" of the list is null:
bool UnsortedList::IsEmpty() {
if (data == NULL) {return true;} // if there is no first element, empty
else {return false;} // if there is ANY element, not empty
}
Or more compactly:
bool UnsortedList::Empty() {
return (data == NULL);
}
When a node is added to a linked list, we usually add the node as a whole and modify the element that came before it. For example, we might create a new node and add it using code like the following:
// implementation file
void UnsortedList::InsertItem(const float& item) {
if (data == NULL) { // no elements in list, so new node becomes the head
data = new Node; // allocate memory for new node
data->element = item; // fill with requested data
data->next = NULL; // there is no element after the tail
}
else {
new_node = new Node; // allocate memory
new_node->element = item // set data
new_node->next = NULL; // new end of the list, so it points to nothing
tail->next = new_node; // have the OLD end node point to the NEW end
tail = new_node; // have the tail member variable move up
}
}
// driver file
int main() {
UnsortedList my_list;
float pie = 3.14159;
my_list.AddNode(pie);
return 0;
}
Please note that I made use of a Node* member variable called tail. It is a good idea to keep track of both where the list begins and ends.
In your IsFull function, it will always return false since it can always create a new Node*. Except perhaps if you run out of memory, which is probably more problematic.
Your functions are rather confusing and your pointer work leaves many memory leaks. You might want to review the STL list object design here.
Related
This is in the main function. Using visual studio 2017.
list a;
a.insertAtEnd("i", 1);
a.insertAtEnd("love", 1);
Here in the main when second insert at end is called. The program crashes and says the getnext() is NULL. Even though at the creation of every new node the next pointer is declared NULL.
class node {
public:
node(string value) {
next = NULL;
data = value;
}
void setNext(node *temp) {
next = temp;
}
void setdata(string value) {
data = value;
}
node* getNext() {
return next;
}
Debugger shows this function to be at fault^
string getData() {
return data;
}
void createDetail() {
detail *tmp = new detail();
d = tmp;
}
void setDetail(int lin) {
d->insertAtEnd(lin);
}
void getDetails() {
d->print();
}
private:
node *next;
string data;
detail *d;
};
class list {
public:
list() {
head = NULL;
}
void insertAtEnd(string, int);
void insertAfter(string, string);
void display();
private:
node *head;
};
void list::insertAtEnd(string value, int lin) { //main func being used
if (head == NULL) {
node *temp = new node(value);
temp->createDetail();
temp->setDetail(lin);
head = temp;
}
else {
node *temp2 = head;
while (temp2->getNext() != NULL || temp2->getData()!=value)
{
temp2 = temp2->getNext();
}
if (temp2->getData() == value)
{
temp2->setDetail(lin); //if same line then increment frequency, dont create new detail as word exists
}
else
{
node *temp = new node(value);
temp->createDetail();
temp->setDetail(lin);
temp2->setNext(temp);
}
}
}
In
while (temp2->getNext() != NULL || temp2->getData() != value)
{
temp2 = temp2->getNext();
}
temp2->getNext() != NULL will be be NULL for the last item in the list, and the data in the last item in the list may not match value. In this case,
while (NULL != NULL || "I" != "love") // false or true = true. Enter loop
{
temp2 = NULL;
}
Next iteration fails because
while (NULL->getNext() != NULL || temp2->getData() != value)
{
temp2 = temp2->getNext();
}
Ka-blam.
My solution changes a lot of code. You might not like it. Also note I've removed everything that will not compile because it was left out of the question.
class node
{
friend class list; // list has access to node's private members
public:
node(string value)
{
next = NULL;
data = value;
}
// removed setNext. Only list should ever be allowed to set the next member
void setdata(string value) {
data = value;
}
// same deal for get. Some shmuck could delete link->getNext();, so why let them?
string getData()
{
return data;
}
private:
node *next;
string data;
};
This is a much safer list node. All a user can interact with is the data. The rest is safely locked up and only exposed to list.
class list
{
public:
list()
{
head = NULL;
}
void insertAtEnd(string);
private:
node *head;
};
Unchanged, other than the stuff removed because it supported code not included in the question.
void list::insertAtEnd(string value)
{ //main func being used
node **cur = &head; // double pointer abstracts away need to test for head.
// Now all nodes are equal and we're always pointed at a next.
while (*cur != NULL && (*cur)->getData() != value) // note && not ||
//we loop until out of nodes unless we find a match
{
cur = &(*cur)->next; // get pointer to next next
}
if (*cur != NULL) // pointing at a node. Must have exited because of match
{
// did stuff I ommtted because no MCVE
}
else // not pointing at node. Need a new node.
{
*cur = new node(value);
}
}
Bloodbath. Rather than drop a big ball of explanation here, I commented inline what I was doing and why.
I am writing a simple app that gets a list and saves the objects as nodes in a singly linked list and we can add(), remove(), copy(), etc. each node depending on the given data set. each node has a char value which is our data and an int count which counts the occurrence of the related char.
e.g. for a list like
a, a, b, b, c, a
there would be three nodes (since there are three different characters) which are:
[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr
bool isAvailable() checks if the data is already in the list or not.
Q: When inserting a data there are two options:
The data has not been entered: so we have to create a newNodewith the given data, count=1and *next=NULL.
The data is already entered: so we have to count++ the node that has the same data.
I know if the given data is available or not, but how can I point to the node with same data?
Here's the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Snode
{
public:
char data;
int count;
Snode *next;
Snode(char d, int c)
{
data = d;
count = c;
next = NULL;
}
};
class set
{
private:
Snode *head;
public:
set()
{
head = NULL;
tail = NULL;
}
~set();
void insert(char value);
bool isAvailable(char value);
};
set::~set()
{
Snode *t = head;
while (t != NULL)
{
head = head->next;
delete t;
}
}
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
void set::insert(char value)
{
Snode *newNode = new Snode(char d, int c);
data = value;
if (head == NULL)
{
newNode->next = NULL;
head = newNode;
newNode->count++;
}
else
{
if(isAvailable)
{
//IDK what should i do here +_+
}
else
{
tail->next= newNode;
newNode->next = NULL;
tail = newNode;
}
}
}
I know if the given data is available or not, but how can I point to the node with same data?
You'll need to start at the head of the list and iterate along the list by following the next pointers until you find the node with the same data value. Once you've done that, you have your pointer to the node with the same data.
Some other notes for you:
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
Why is this function allocating a new Snode? There's no reason for it to do that, just initialize the floatingNode pointer to point to head instead.
This function always returns after looking at only the first node in the linked list -- which is not the behavior you want. Instead, it should return true only if (value == floatingNode); otherwise it should stay inside the while-loop so that it can go on to look at the subsequent nodes as well. Only after it drops out of the while-loop (because floatingNode finally becomes NULL) should it return false.
If you were to modify isAvailable() slightly so that instead of returning true or false, it returned either floatingPointer or NULL, you'd have your mechanism for finding a pointer to the node with the matching data.
e.g.:
// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
[...]
}
void set::insert(char value)
{
Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
if (theNode != NULL)
{
theNode->count++;
}
else
{
[create a new Snode and insert it]
}
}
You had a lot of problems in your code, lets see what are they:
First of all, Snode doesn't need to be a class, rather you can go with a simple strcut; since we need everything public.(not a mistake, but good practice)
You could simple initialize count = 1 and next = nullptr, so that no need of initializing them throw constructor. The only element that need to be initialized through constructor is Snod's data.
Since c++11 you can use keyword nullptr instead of NULL, which denotes the pointer literal.
Member function bool set::isAvailable(char value) will not work as you think. Here you have unnecessarily created a new Snode and cheacking whether it points to nullptr which doesn't allow you to even enter the loop. BTW what you have written in the loop also wrong. What do you mean by return (value == floatingNode); ? floatingNode is a Snode by type; not a char.
Hear is the correct implementation. Since we don't wanna overwrite the head, will create a Node* pointer and assign head to it. Then iterate through list until you find a match. If not found, we will reach the end of the isAvailable() and return false.
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
In void set::insert(char value), your logic is correct, but implementation is wrong. Following is the correct implementation.(Hope the comments will help you to understand.
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value); // create a node and assign there
}
}
Your destructor will not delete all what you created. It will be UB, since your are deleting newly created Snode t ( i.e, Snode *t = head;). The correct implementation is as bellow.(un-comment the debugging msg to understand.)
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
Last but not least, the naming (set) what you have here and what the code exactly doing are both different. This looks more like a simple linked list with no duplicates. This is however okay, in order to play around with pointers and list.
To make the code or iteration more efficient, you could do something like follows. In the isAvailable(), in case of value match/ if you found a node, you could simply increment its count as well. Then in insert(), you can think of, if node is not available part.
Hope this was helpful. See a DEMO
#include <iostream>
// since you wanna have all of Node in public, declare as struct
struct Node
{
char data;
int count = 1;
Node* next_node = nullptr;
Node(const char& a) // create a constrcor which will initilize data
: data(a) {} // at the time of Node creation
};
class set
{
private:
Node *head; // need only head, if it's a simple list
public:
set() :head(nullptr) {} // constructor set it to nullptr
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value);
}
}
void print() const // just to print
{
Node *temp = head;
while(temp != nullptr)
{
std::cout << temp->data << " " << temp->count << "\n";
temp = temp->next_node;
}
}
};
int main()
{
::set mySet;
mySet.insert('a');
mySet.insert('a');
mySet.insert('b');
mySet.insert('b');
mySet.insert('c');
mySet.insert('a');
mySet.print();
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I am inserting a string at the end of a linked list. When I compile my file I get 2 errors:
error: ‘setData’ was not declared in this scope
setData(*string_p);
error: ‘getNext’ was not declared in this scope
newNode = getNext();
However they are defined before I use them (defined in above methods) so I do not understand the error.
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
#define SUCCESS 0
#define FAIL 1
// Represents an entry object in the linked-list
class ListEntry
{
public:
explicit ListEntry();
explicit ListEntry(const char *string_p);
~ListEntry();
string getData();
void setData(const char* string_p);
void setData(string string);
ListEntry *getNext();
ListEntry *getPrevious();
ListEntry *prev_p; // pointer to previous entry in the linked-list
ListEntry *next_p; // pointer to next entry in the linked-list
private:
string data; // entry's string
};
// Represents the linked-list object
class List
{
public:
List();
~List();
bool printForward();
bool printReverse();
bool insert(const char *string_p);
private:
int entryCount; // number of entries present in the linked-list
ListEntry *head_p; // pointer to the first entry in the list
ListEntry *tail_p; // pointer to the last entry in the list
};
// ListEntry constructor
ListEntry::ListEntry()
{
this->prev_p = NULL;
this->next_p = NULL;
return;
}
// ListEntry constructor
ListEntry::ListEntry(const char *string_p)
{
this->data = string_p;
this->prev_p = NULL;
this->next_p = NULL;
return;
}
// List entry destructor
ListEntry::~ListEntry()
{
return;
}
// Return the stored string object
string ListEntry::getData()
{
return this->data;
}
// Set the internal string data from a char*
void ListEntry::setData(const char* string_p)
{
this->data = string_p;
}
// Set the internal string data from a string
void ListEntry::setData(string string)
{
this->data = string;
}
// Returns reference to the next entry in the list
ListEntry *ListEntry::getNext()
{
return this->next_p;
}
// Returns reference to the previous entry in the list
ListEntry *ListEntry::getPrevious()
{
return this->prev_p;
}
And my Insert function (which is below the above methods in my program):
bool List::insert(const char *string_p)
{
// Please write the list insert function
//new node to be inserted
ListEntry* newNode = new ListEntry();
//List *newList = new List();
if(newNode == NULL)
{
cout << "FAILED";
}
else
{
setData(*string_p); //////ERROR HERE
if(this->head_p = NULL)
{
newNode = getNext(); //////ERROR HERE
newNode = this->head_p;
this->head_p = newNode; // newNode now points to the head node
this->entryCount++;
return SUCCESS;
}
else
{
ListEntry* temp = this->head_p;
while(temp -> next_p != NULL)
{
temp = temp -> next_p;
}
temp -> next_p = newNode;
this->entryCount++;
return SUCCESS;
}
}
}
You have defined the functions but you are not using them the way you have defined:
setData(*string_p); // Takes a const char*, but you have provided a char.
// *string_p dereferences the string pointer, giving the
// first char.
newNode = getNext(); // getNext is a ListEntry function, but you are trying
// to use it in the context of List. This is also true of the
// above function.
Your insert() method is implemented all wrong. It should look more like this instead:
int List::insert(const char *string_p)
{
//new node to be inserted
ListEntry* newNode = new ListEntry(string_p);
if (newNode == NULL)
{
cout << "FAILED";
return FAIL;
}
if (this->head_p == NULL) {
this->head_p = newNode;
}
if (this->tail_p != NULL)
{
this->tail_p->next_p = newNode;
newNode->prev_p = this->tail_p;
}
this->tail_p = newNode;
this->entryCount++;
return SUCCESS;
}
The functions setData and getNext are non-static member functions of the class ListEntry. So they have to be called using a member access expression.
Moreover the supplied argument of this call
setData(*string_p);
has different type than the the function expects.
You have to write at least like
newNode->setFata( string_p );
and
newNode->getNext();
though this code snippet even if the call of the function will be correct from the syntax point of view does not make sense
if(this->head_p = NULL)
{
newNode = newNode->getNext();
newNode = this->head_p;
because there is at least a memory leak.
Also this if statement
if(newNode == NULL)
will make sense if you use the following call of the new operator
ListEntry* newNode = new ( std::nothrow ) ListEntry();
The function can look the following way
bool List::insert( const char *string_p )
{
//new node to be inserted
ListEntry *newNode = new ( std::nothrow ) ListEntry( string_p );
bool success = newNode != nullptr;
if ( success )
{
if ( tail_p )
{
tail_p->next_p = newNode;
newNode->prev_p = tail_p;
}
else
{
head_p = newNode;
}
tail_p = newNode;
entryCount++;
}
return success;
}
i've use this function to erase element with a particular value:
void eraseFromTable(ipTable * head,int sock)
{
while(head)
{
if(head->sockNumber == sock)
{
delete head;
break;
}
head = head->next;
}
}
This is the struct:
struct ipTable
{
char iPv4[INET_ADDRSTRLEN];
char iPv6[INET6_ADDRSTRLEN];
int sockNumber;
int ipv4;
int ipv6;
ipTable * next;
};
The problem is that when i use the erase function and then display again all the list
in the place of the node that've erased there's still sockNumber showed.
I've tried also free() function but it's the same.
How can i erase everything,pratically sconnecting that particular node?
You aren't doing two things:
Fixing the broken link from the node previous to the to-be-deleted node leading into it.
Reassigning the head pointer (which must be passed by reference / through a double pointer etc.) in case the node to be deleted is the head of the list.
Here's a fix (untested; also note I'm not really a C++ programmer so this may not be idiomatic - treat it as a general idea):
bool eraseFromTable(ipTable** headPtrPtr, int sock)
{
ipTable* headPtr = *headPtrPtr;
if(headPtr && headPtr->sockNumber == sock)
{
*headPtrPtr = headPtr->next;
delete headPtr;
// I'm assuming there can only be 1 matching entry;
// will need change otherwise.
return true;
}
ipTable* nodePtr = headPtr;
while(nodePtr)
{
ipTable* nextPtr = nodePtr->next;
if(nextPtr && nextPtr->sockNumber == sock)
{
nodePtr->next = nextPtr->next;
delete nextPtr;
// I'm assuming there can only be 1 matching entry;
// will need change otherwise.
return true;
}
nodePtr = nextPtr;
}
return false;
}
i've got an own implemented list:
struct NodeComposition {
Int32 index;
Int8 address;
char* label;
NodeComposition* next;
};
and I am creating new structs with the following method, whereas the label of the root element is initialized with NULL and is changed later on.
NodeComposition ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition;
newNode->address = address;
newNode->label = label;
newNode->next = 0;
newNode->index = -1;
return *newNode;
}
In order to check if a specific "label" exists I have implemented following method:
NodeComposition* ListManager::labelExists(char* label)
{
UInt32 i = 0;
NodeComposition* conductor = &rootNode;
// Traverse through list
while(i < elements)
{
// Label has been found
if (strcmp(conductor->label, label) == 0)
{
return conductor;
}
/* Advancing in list */
else
{
if(conductor->next != 0)
{
conductor = conductor->next;
}
else
{
/* Error: Null reference found in conductor->next */
return NULL;
//return Errors::NULL_REFERENCE;
}
}
i++;
}
/* label not found */
return NULL;
}
And here comes my problem:
I called the labelExists(char* label) method (With a linked list of two elements)
After it compares the two strings it changes the value of the member label of the second element inside of the first iteration
This data is some random trash out of my main memory and I do not have any idea why it behaves like that. Additionally, exactly this code worked just an hour before. At least I think that it did because I can not remember changing any code.
Does anybody has an idea?
Thank you!
Edit:
here is some additional code
NodeComposition newNode = getNewNode(label, address);
ListManager::addNode(newNode);
Int32 ListManager::addNode(NodeComposition node)
{
node.index = elements;
lastNode->next = &node;
lastNode = &node;
elements++;
return lastNode->index;
}
It is definitely not strmcp, so let's not focus on that. You should clean up this code first. There are memory leak and corruption going on.
To start with:
NodeComposition ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition; // $#!^!memory allocated
newNode->address = address;
newNode->label = label; // $#!^! is label allocated on stack or heap? possible leak & corruption
newNode->next = 0;
newNode->index = -1;
return *newNode; // $#!^!return by value. newNode is now lost! memory leak
}
Then in your additional code:
NodeComposition newNode = getNewNode(label, address); // $#!^! getting a copy of the "newNode" only. This copy is allocated in stack.
ListManager::addNode(newNode); //$#!^! adding a stack object onto linked list
Int32 ListManager::addNode(NodeComposition node)
{
node.index = elements;
lastNode->next = &node;
lastNode = &node; //node is actually allocated from stack, not heap! likely memory corruption here!
elements++;
return lastNode->index;
}
I got the answer .. I modified my code like this:
Int32 ListManager::addNode(NodeComposition* node)
{
node->index = ++elements;
lastNode->next = node;
lastNode = node;
return lastNode->index;
}
NodeComposition* ListManager::getNewNode(char* label, Int8 address)
{
NodeComposition* newNode = new NodeComposition;
newNode->address = address;
newNode->label = label;
newNode->next = 0;
newNode->index = -1;
return newNode;
}
NodeComposition* ListManager::labelExists(char* label)
The use of pointers helped me out - Thank you guys.