I tried to implement by myself a single linked list. For now, I only wrote an addition of an element to the end of the list, and a function which prints lists content. But when I want to print out a list my program gives me a segmentation fault. Heres my code:
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
class Stuff;
class List
{
private :
Stuff *first, *last;
public :
List();
void addfront(Stuff *s);
void print();
~List();
};
class Stuff
{
private :
string name;
double price;
public :
Stuff();
Stuff(string, double);
void print();
Stuff *next;
};
Stuff::Stuff()
{
name = "";
price = 0;
next = NULL;
}
Stuff::Stuff(string n, double p)
{
name = n;
price = p;
}
void Stuff::print()
{
cout << name << " " << price << "\n";
}
List::~List()
{
}
void List::addfront(Stuff *s)
{
if(first == NULL )
first = s;
last->next = s;
s->next = NULL;
last = s;
}
void List::print()
{
Stuff *p;
if(last == first == NULL)
cout << "list is empty!\n";
else
for (p = first; p != NULL; p = p->next)
p->print();
}
List::List()
{
first = last = NULL;
}
int main(int argc, char **argv)
{
List l;
Stuff *s1 = new Stuff("Coffe", 4.50);
Stuff *s2 = new Stuff("Apple", 2.50);
l.addfront(s1);
l.addfront(s2);
l.print();
return 0;
}
It seems like you forgot to check if last != NULL before setting last->next to s.
Deferencing a NULL pointer results to an undefined behaviour.
Your addFront function should look like that:
void List::addfront(Stuff *s) {
if(!first)
first = s;
if (last)
last->next = s;
s->next = NULL;
last = s;
}
Btw: Use if(last == first && last == NULL) instead of if(last == first == NULL).
One issue is
if(last == first == NULL)
make it
if(last == NULL && first == NULL)
also you need to do,
void List::addfront(Stuff *s)
{
if(!first)
first = s;
if (last)
last->next = s;
s->next = NULL;
last = s;
}
It is because of this line in addfront method
last->next = s;
Here last is a NULL pointer.
(gdb) p last
$1 = (Stuff *) 0x0
Deferencing a NULL pointer will cause memory fault/segmentation violation.
Always check whether it is NULL and then deference.
if (last)
last->next = s;
If you are in Linux machine, then you can run the program in gdb. Once segmentation violation happens put use backtrace command to see the call stack to understand which statement is crashed.
Related
I have a little problem which occurs after trying to execute function delete_all(). Any idea why Visual Studio is throwing me an error:
Invalid address specified to RtlValidateHeap, instruction __debugbreak() or something similar
Everything works perfect until I want to execute this function.
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = NULL;
node* next = NULL;
};
node* add(node* first, string name) {
if (first == NULL) {
return NULL;
}
node* nowy = new node;
if (first->next == NULL) {
nowy->prev = first;
first->next = nowy;
}
else {
while (first->next != NULL) {
first = first->next;
}
nowy->prev = first;
first->next = nowy;
}
nowy->name = name;
return nowy;
}
void writeout(node* first) {
if (first == NULL) cout << "first = NULL";
while (first->next != NULL) {
cout << first->name;
cout << "\n";
first = first->next;
}
if (first->next == NULL) {
cout << first->name;
cout << "\n";
}
}
void delete_all(node* first) {
node* temp;
while (first != NULL) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node n1;
add(&n1, "n2");
add(&n1, "n3");
writeout(&n1);
delete_all(&n1);
}
You declared an object in main() with automatic storage duration as the first node of the list:
node n1;
You may not destroy it using the delete operator.
Using your approach of the list implementation, you could define the function delete_all() the following way:
void delete_all(node* first)
{
if ( first != nullptr )
{
while ( first->next != nullptr )
{
node *temp = first->next;
first->next = temp->next;
delete temp;
}
}
}
But, it will be much better if initially in main(), you declared a pointer to a node. In this case, you will need to update the functions.
Your implementation of delete_all() is fine, but you are passing it a pointer to a node instance that was not created with new, so delete'ing that node is undefined behavior. ALL of your node instances should be created dynamically, including the 1st node.
As such, your add() function should be updated to not blindly return without creating a new node instance if first is initially NULL. You should instead update the caller's node* pointer to point at the new node that was created.
Also, writout() has undefined behavior if first is NULL, because you are unconditionally accessing first->next whether first is NULL or not.
With that said, try something more like this instead:
#include <iostream>
using namespace std;
struct node {
string name = "n1";
node* prev = nullptr;
node* next = nullptr;
};
node* add(node* &first, string name) {
if (!first) {
first = new node{name};
return first;
}
else {
node *prev = first;
while (prev->next) {
prev = prev->next;
}
prev->next = new node{name, prev};
return prev->next;
}
}
/* alternatively:
node* add(node* &first, string name) {
node **nowy = &first, *prev = nullptr;
while (*nowy) {
prev = *nowy;
nowy = &(prev->next);
}
*nowy = new node{name, prev};
return *nowy;
}
*/
void writeout(node* first) {
if (!first) {
cout << "first = NULL";
}
else {
do {
cout << first->name;
first = first->next;
if (first) cout << '\n';
}
while (first);
}
}
void delete_all(node* first) {
node* temp;
while (first) {
temp = first->next;
delete first;
first = temp;
}
}
int main()
{
node* n1 = nullptr;
add(n1, "n2");
add(n1, "n3");
writeout(n1);
delete_all(n1);
}
Alternatively:
...
node* add(node* first, string name) {
if (!first) {
return new node{name};
}
else {
while (first->next) {
first = first->next;
}
first->next = new node{name, first};
return first->next;
}
}
/* alternatively
node* add(node* first, string name) {
// same as node** further above ...
}
*/
...
int main()
{
node* n1 = add(nullptr, "n2");
add(n1, "n3");
...
delete_all(n1);
}
For example, my text file reads:
A 1
A 3
B
A 2
The goal is for the output to be 123, but I have gotten everything but that.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class Node
{
public:
char letter;
Node* next;
Node* prev;
Node(char cc)
{
letter = cc;
next = prev = nullptr;
}
};
string command;
char parameter;
Node* p = nullptr;
Node* rows[10];
int currentRow = 0;
void main()
{
for (int i = 0; i < 10; i++)
{
rows[i] = new Node('.');
rows[i]->next = nullptr;
rows[i]->prev = nullptr;
}
ifstream input("c:\\temp\\input.txt");
while (input.peek() != -1)
{
Node* c = rows[currentRow];
c = rows[currentRow];
while (c->next != nullptr)
c = c->next;
input >> command;
if (command == "B") { // Back Curser
//Moves curser back
}
else if (command == "F") { // Forward Curser
//Moves curser forward
}
else if (command == "A") // Add char Done
{
input >> parameter;
Node* newnode = new Node(parameter);
c->next = newnode;
newnode->prev = c;
}
}
input.close();
// display linked list
cout << endl;
for (int i = 0; i < 10; i++)
{
Node* t = rows[i]->next;
if (t != nullptr)
{
while (t != nullptr)
{
cout << t->letter;
t = t->next;
}
cout << endl;
}
}
}
At first I had tried c = c->prev, but that did not work, as nothing was reorganized in my linked list.
I also attempted to create a brand new node that was hopefully then filled by the upcoming character, but my logic did not add up to that, and I ran into multiple issues.
For the lack of implementation details in 'B', I'll just help you fix 'A' instead.
You see, when moving the cursor back, you are now pointing to an element that already has a 'following node' (next is no longer nullptr)
else if (command == "A") // Add char Done
{
input >> parameter;
Node* newnode = new Node(parameter);
newnode->next = c->next; //Link the new node to the previously following node (may be nullptr)
c->next = newnode;
newnode->prev = c;
}
Without the line I inserted, the previous next of c becomes inaccessible, leading to a memory leak.
Greetings stack overflow. My program is supposed to take a user inputted line of characters and append them to a list. The program is also supposed to delete the most recent character appended if a hashtag is read in the input.
My program mostly works, but I run into errors when I try to break it by adding too many hashtags. Upon doing this the list stops accepting appends will display nothing if one too many hashtags are used.
I hope I only included what I thought was useful code, sorry if the main function was not necessary.
#include <iostream>
using namespace std;
class doubleList
{
public:
doubleList() { first = NULL; } // constructor
void append(char); // adds entry to the end of the list
void remove_last(); // removes the last item from a list
friend ostream& operator<<(ostream& out, const doubleList& l); // outputs in forward order
private:
struct Node
{
char data;
Node *next;
Node *prev;
};
Node *first;
Node *last;
};
void doubleList::append(char entry)
{
Node* temp = new Node();
temp -> data = entry;
temp -> next = NULL;
if (first == NULL)
{
first = temp;
last = temp;
}
else
{
last -> next = temp;
temp -> prev = last;
last = temp;
}
}
void doubleList::remove_last()
{
if (first -> next == NULL)
{
delete first;
}
else if (first != NULL)
{
last = last -> prev;
delete last -> next;
last -> next = NULL;
}
}
ostream& operator<<(ostream& out, const doubleList& l)
{
doubleList::Node* q;
q = l.first;
while (q != NULL)
{
out << q -> data;
q = q -> next;
}
return out;
}
int main()
{
doubleList list;
char ch[100];
cout << "Enter a line of characters; # will delete the most recent character." << endl;
for (int i = 0; i < 100; i++)
{
cin.get(ch[i]);
list.append(ch[i]);
if (ch[i] == '#')
{
list.remove_last();
list.remove_last(); // called twice becaue it removes the hashtag from the list
} // and i was too lazy to make it so it doesnt do that so this
// is simply an easier fix
if (ch[i] == '\n') // exits the loop when enter is clicked
break;
}
cout << list;
return 0;
}
A successful run of my program would look like:
Enter a line of characters; # will delete the most recent character.
abcd##fg
abfg
My program when too many hashtags are added:
Enter a line of characters; # will delete the most recent character.
ab#####efgh
Nothing is shown after user input is taken. Thanks in advance.
You should also set the pointer last to nullptr in the constructor
doubleList() { first = nullptr; last = nullptr; }
The function append is incorrect because it does not set the data member prev of the first node appended to the list. It should be written like
void doubleList::append(char entry)
{
Node* temp = new Node();
temp -> data = entry;
temp -> next = nullptr;
temp -> prev = last;
if (first == NULL)
{
first = temp;
}
else
{
last -> next = temp;
}
last = temp;
}
The function removeList can invoke undefined behavior because in the very beginning of the function it does not check whether the pointer first is equal to nullptr. And after deleting the node pointed to by the pointer first it does not set the pointers first and last to nullptr. The function can be defined the following way.
void doubleList::remove_last()
{
if ( last )
{
Node *tmp = last;
last = last->prev;
if ( last != nullptr )
{
last->next = nullptr;
}
else
{
first = nullptr;
}
delete temp;
}
}
You rely on first being NULL when deallocated in remove_last() but do not set it after the free. As your code is incomplete, I cannot tell what last is, and why you your logic doesn't rely on it in remove_last() instead of first.
Something along these lines (untested);
void doubleList::remove_last() {
if(!last) return;
if(last == first) {
free last;
first = nullptr;
last = nullptr;
return;
}
last = last->prev;
free last->next;
last->next = nullptr;
}
I've a homework task, where I've to sort linked list elements (strings) after first character in a string.
Example:
From: Pineapple->Apple->Ash->Abc->Pearl->Bonfire->Ball
To: Apple->Ash->Abc->Bonfire->Ball->Pineapple->Pearl (Only first char)
I made a function:
void insertionSort ()
{
first = current;
Node* insertionPointer = first;
current = current -> next;
for (start(); !end(); next()){ // Running through all list nodes
while (current != NULL) {
insertionPointer = first;
while(insertionPointer->next != current) {
if (insertionPointer->data.at(0) > current-> data.at(0)){ // Trying to sort strings alphabetically
// (after only first char)
string temp = current->data;
current->data = insertionPointer->data;
insertionPointer->data = temp;
}
else {
insertionPointer = insertionPointer->next;
}
}
}
}
}
But I get a segmentation fault - I guess that means I'm trying to get some information, that I can not access? Also, I'm not sure if:
if (insertionPointer->data.at(0) > current-> data.at(0))
Will compare strings first char? I'm just trying to experiment here. :(
Just to make sure, I'll post below also my whole code, so you can see how I structured lists and other functions. I'm new to this stuff - any information will be helpful.
Full program code:
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
using namespace std;
class Node
{
public:
string data;
Node *next;
Node (string city) { data = city; next = NULL; };
};
class List
{
protected:
Node *first, *last;
public:
Node *current;
public:
List () { first = last = current = NULL; };
void add_element (string city);
void delete_element ();
~List();
bool is_empty () { return (first == NULL); };
void start () { current = first; };
bool end () { return (current == NULL); };
void next(){if (!end())current = current -> next;};
void print();
void insertionSort ()
{
first = current;
Node* insertionPointer = first;
current = current -> next;
for (start(); !end(); next()){ // Running through all list nodes
while (current != NULL) {
insertionPointer = first;
while(insertionPointer->next != current) {
if (insertionPointer->data.at(0) > current->data.at(0)){ // Trying to sort strings alphabetically
// (after only first char)
string temp = current->data;
current->data = insertionPointer->data;
insertionPointer->data = temp;
}else{
insertionPointer = insertionPointer->next;
}
}
}
}
}
};
int main()
{
string s;
List l;
l.add_element("Pineapple");
l.add_element("Apple");
l.add_element("Ash");
l.add_element("Abc");
l.add_element("Pearl");
l.add_element("Bonfire");
l.add_element("Ball");
l.print();
cout << endl;
l.insertionSort();
l.print();
return 0;
}
void List::add_element (string city)
{
Node *p = new Node (city);
if (first == NULL) first = last = p;
else last = last -> next = p;
current = p;
};
void List::delete_element ()
{
Node *p = first;
if(!is_empty())
{ if (current == first) current = first-> next;
first = first -> next;
delete p;
if(is_empty())last = NULL;
}
};
void List::print()
{
for (start(); !end(); next())
{
cout << current->data << endl;
}
cout << endl;
};
List::~List()
{
while (!is_empty())
{
delete_element();
};
cout << "All memory of nodes deleted!"<< endl;
};
Your program is most likely crashing here:
while(insertionPointer->next != current) {
because insertionPointer has become null when you executed
insertionPointer = insertionPointer->next;
change the loop condition to
while(insertionPointer && insertionPointer->next != current) {
i want to make a linked list ..
but the first node with a data and null link
if i input a string (123)
linked list be like this:
1/null - 2/point to the last one(1) - 3/point to the last one(2)
#include <iostream>
#include <string>
using namespace std;
struct link
{
int data;
link* next;
};
class LinkedList
{
private:
link* first;
public:
LinkedList(){}
void Add(string s)
{
for (int i = 0; i > s.length(); i++)
{
if (i == 0)
{
first->data = s[i];
first->next = NULL;
}
else
{
link* NewOne = new link;
NewOne->data = s[i];
NewOne->next = first;
first = NewOne;
}
}
}
void display()
{
cout << first->data;
}
};
int main()
{
LinkedList l1;
l1.Add("2734");
l1.display();
return 0;
}
what's the wrong in the code
You forget to allocate memory for first.
Following may help (using std::unique_ptr for free/correct memory management):
struct link{
char data;
std::unique_ptr<link> next;
};
class LinkedList {
private:
std::unique_ptr<link> first;
public:
void Set(const std::string& s){
for (auto c : s) {
std::unique_ptr<link> node = std::move(first);
first = std::make_unique<link>();
first->data = c;
first->next = std::move(node);
}
}
Live example
It also looks like you're storing characters in an int. Your output will be the ASCII value of the character rather than the raw int values.
I would recommend using unique pointers as Jarod42 has done. Having said that, this quick example below does not use them so you will need to call delete appropriately or use unique_ptr.
I added a last pointer to help traversal of the list as we make new links.
private:
Link * first;
Link *last;
int numLinks;
public:
LinkedList()
{
first = NULL;
last = NULL;
numLinks = 0;
}
Now for Add
void Add(string s)
{
for (int i = 0; i < s.length(); i++)
{
if (numLinks == 0)
{
first = new Link;
first->data = (s[i] - '0');
first->next = NULL;
last = first;
numLinks++;
}
else
{
Link * newLink = new Link;
newLink->data = (s[i] - '0');
newLink->next = NULL;
last->next = newLink;
last = newLink;
numLinks++;
}
}
}
The constructor does not initialize the first member. Subsequently, in Add():
for (int i = 0; i > s.length();i++){
if (i == 0){
first->data = s[i];
first->next = NULL;
}
This ends up dereferencing an uninitialized pointer, leading to undefined behavior.
There's also a problem with your display() too, but this is the main problem.