How to fix Segmentation Fault in linked list - c++

I'm getting a segmentation fault error that I don't know how to fix. List.cpp and List.hpp are bigger, but I added just what I'm using in main.cpp. Here is the code:
List.hpp
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <cstdlib>
struct Node{
int _value;
Node *_next;
};
struct List{
Node *_head;
int _size;
List();
void insert(int value);
void print();
};
#endif
List.cpp
#include "List.hpp"
List::List(){
_size = 0;
_head = nullptr;
}
void List::insert(int value){
Node* node;
node->_value = value;
node->_next = _head;
_head = node;
}
void List::print(){
Node* head = _head;
if (_size > 0){
while(head){
std::cout << head->_value << " ";
head = head->_next;
}
std::cout<<std::endl;
}
else{
std::cout<<std::endl;
return;
}
}
main.cpp
#include <iostream>
#include "List.hpp"
int main(){
List *L = new List();
int N=0;
std::cout << "type the N value"<< std::endl;
std::cin >> N;
for(int i=0; i<=N; i++){
L->insert(i);
}
L->print();
delete L;
return 0;
}
console
▶ g++ -std=c++14 -Wall main.cpp List.cpp -o main && ./main out
List.cpp: In member function ‘void List::insert(int)’:
List.cpp:10:15: warning: ‘node’ is used uninitialized in this function [-Wuninitialized]
10 | node->_value = value;
| ~~~~~~~~~~~~~^~~~~~~
type the N value
3
[1] 13247 segmentation fault (core dumped) ./main out
I actually don't know how to debug it either (I'm using VS Code), so I have no idea about what is happening with the variables that are being created on the stack and on the heap.

As the error(warning) message says, in the insert function you are doing:
Node* node;
But this simply declares a pointer that is not yet pointing to valid memory. Accessing members of the object such as _value pointed at by node will invoke undefined behavior. This can cause a segmentation fault. If you're unlucky, there won't be a segfault, and the program will break at some later point.
You need to allocate memory for a Node like this:
Node* node = new Node{};
In fact, the entire insert function could simply be:
void List::insert(int value) {
_head = new Node{value, _head}; // allocate Node, initialize to
// appropriate values, and link _head
}
Also, you should default initialize the members of Node like this:
struct Node{
int _value{};
Node *_next = nullptr;
};
Also, there seems to be no need to allocate memory for a List in main:
List *L = new List();
Instead, you can simply have a List object like this:
List L{};

Inside the member function insert you are using an uninitialized pointer node
void List::insert(int value){
Node* node;
^^^^^^^^^^^
node->_value = value;
node->_next = _head;
_head = node;
}
that has an indeterminate value and trying to access memory using this pointer that results in undefined behavior.
You have to allocate a node that will be pointed to by the pointer and inserted in the list.
Also you forgot to increase the size of the list.
But I would like to point to some drawbacks of the implementation.
For starters do not use identifiers that start from underscore because according to the C++ Standard
(3.2) — Each identifier that begins with an underscore is reserved to
the implementation for use as a name in the global namespace.
So such names will confuse readers of your code.
The structure Node should be a private or protected data member of the structure List. The user shall not have a direct access to the structure Node. It is an implementation detail.
There is no sense to allocate an object of the type List dynamically.
Here is a demonstrative program that shows how the list can be implemented.
#include <iostream>
#include <functional>
class List
{
protected:
struct Node
{
int value;
Node *next;
} *head = nullptr;
size_t n = 0;
public:
List() = default;
~List() { clear(); }
// These special member functions you can define yourself if you will want
List( const List & ) = delete;
List & operator =( const List & ) = delete;
void insert( int value );
size_t size() const { return n; }
void clear()
{
while ( head ) delete std::exchange( head, head->next );
n = 0;
}
friend std::ostream & operator <<( std::ostream &os, const List &list )
{
for ( Node *current = list.head; current != nullptr; current = current->next )
{
os << current->value << " -> ";
}
return os << "null";
}
};
void List::insert( int value )
{
head = new Node { value, head };
++n;
}
int main()
{
const int N = 10;
List list;
for ( int i = N; i != 0; i-- )
{
list.insert( i );
}
std::cout << list << '\n';
return 0;
}
The program output is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> null

Related

Multiple constructors in a C++ LinkedList class: non-class type "ClassName"

I have a LinkedList constructor where I can pass in an array and it builds. Then I can add additional nodes to it by passing in integers.
However, I also want the option to construct the LinkedList, without any arguments. In my LinkedList.h file I've tried to create a constructor that sets the first and last pointers. My add method should construct a Node.
But in my main() function, when I try to use this constructor, I get an error:
request for member ‘add’ in ‘l’, which is of non-class type ‘LinkedList()’
Same error for the other methods called in the main.cpp.
Where am I going wrong in how I structure my two constructors?
main.cpp
#include <iostream>
#include <string>
#include "LinkedList.h"
using namespace std;
int main()
{
//int A[] {1, 2, 3, 4, 5};
//LinkedList l(A, 5);
LinkedList l();
l.add(8);
l.add(3);
cout << l.getCurrentSize()<<endl;
l.display();
return 0;
}
LinkedList.h
#ifndef LINKED_LIST_
#define LINKED_LIST_
#include "IList.h"
class LinkedList: public IList
{
protected:
struct Node
{
int data;
struct Node *next;
};
struct Node *first, *last;
public:
//constructor
LinkedList(){first=nullptr; last=nullptr;}
LinkedList(int A[], int n);
//destructor
virtual ~LinkedList();
//accessors
void display();
virtual int getCurrentSize() const;
virtual bool add(int newEntry);
};
#endif
LinkedList.cpp
#include <iostream>
#include <string>
#include "LinkedList.h"
using namespace std;
//constructor
LinkedList::LinkedList(int A[], int n)
{
Node *t;
int i = 0;
first = new Node;
first -> data = A[0];
first -> next = nullptr;
last = first;
for(i = 1; i < n; i++) {
t = new Node;
t -> data = A[i];
t -> next = nullptr;
last -> next = t;
last = t;
}
};
//destructor
LinkedList::~LinkedList()
{
Node *p = first;
while (first) {
first = first -> next;
delete p;
p = first;
}
}
void LinkedList::display()
{
Node *p = first;
while(p) {
cout << p -> data << " ";
p = p -> next;
}
cout <<endl;
}
int LinkedList::getCurrentSize() const
{
Node *p = first;
int len = 0;
while(p) {
len++;
p = p -> next;
}
return len;
}
bool LinkedList::add(int newEntry)
{
Node *temporary;
temporary = new Node;
temporary -> data = newEntry;
temporary -> next = nullptr;
if (first==nullptr) {
first = last = temporary;
}
else {
last -> next = temporary;
last = temporary;
}
return true;
}
The problem has nothing to do with your constructors themselves.
LinkedList l(); is a declaration of a function named l that takes no arguments, and returns a LinkedList. That is why the compiler is complaining about l being a non-class type.
To default-construct a variable named l of type LinkedList, drop the parenthesis:
LinkedList l;
Or, in C++11 and later, you can use curly-braces instead:
LinkedList l{};

What does this strange number mean in the output? Is this some memory Location? [duplicate]

This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 1 year ago.
The node Class is as follow:
class node
{
public:
int data; //the datum
node *next; //a pointer pointing to node data type
};
The PrintList Function is as follow:
void PrintList(node *n)
{ while (n != NULL)
{
cout << n->data << endl;
n = n->next;
}
}
If I try running it I get all three values (1,2,3) but I get an additional number as well which I'm unable to figure out what it represents, Can someone throw light on the same?
int main()
{
node first, second, third;
node *head = &first;
node *tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
PrintList(head);
}
I Know it can be fixed with
third.next = NULL;
But I am just curious what does this number represents in output, If I omit the above line
1
2
3
1963060099
As described in the comment by prapin, third.next is not initialized.
C++ has a zero-overhead rule.
Automatically initializing a variable would violate this rule as the value might be initialized (a second time) later on or never even be used.
The value of third.next is just the data that happened to live in the same memory location as third.next does now.
For this reason, it's recommended to always initialize your variables yourself.
It is better to initialize variables & it is better to use nullptr. Like that (See 1-3):
#include <iostream>
class node
{
public:
int data = 0; // 1
node* next = nullptr; // 2
};
void PrintList(node* n)
{
while (n != nullptr) // 3
{
std::cout << n->data << std::endl;
n = n->next;
}
}
int main()
{
node first, second, third;
node* head = &first;
node* tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
// third.next points to where?
PrintList(head);
}
Additional note:
I would prefer to use the STL container std::list:
#include <list>
#include <iostream>
std::list<int> int_list;
void PrintList()
{
for (auto i : int_list)
std::cout << i << std::endl;
}
int main()
{
int_list.push_back(1);
int_list.push_back(2);
int_list.push_back(3);
PrintList();
}
Or in case of list of node objects:
#include <list>
#include <iostream>
class node
{
public:
node(int data) : m_data{ data } {};
int m_data = 0;
// and maybe extra data-members
};
std::list<node> node_list;
void PrintList()
{
for (auto i : node_list)
std::cout << i.m_data << std::endl;
}
int main()
{
node_list.push_back(node(1));
node_list.push_back(node(2));
node_list.push_back(node(3));
PrintList();
}

Undefined reference to 'Inventory::insertEnd(Node*, int)'

I’m getting an “undefined reference to” error when trying to build/compile my program:
obj\Debug\main.o||In function main':|
C:\Users\user1\Desktop\Project5Example\main.cpp|13|undefined reference toInventory::insertEnd(Node*, int)'|
...
||error: ld returned 1 exit status|
||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|
I’m quite new to c++. What am I doing wrong? and how can I fix it?
I feel is has to do with my head node? But can’t really figure out how what it is.
The error happens on main.cpp line head = inventory1.insertEnd(head, 8);
Here is my code:
Inventory.h
#ifndef INVENTORY_H
#define INVENTORY_H
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
struct Node
{
int data;
Node* next;
};
class Inventory
{
public:
// Default Constructor
Inventory();
// MODIFICATION MEMBER FUNCTIONS
Node *newNode(int data);
Node* insertEnd(Node* head, int data);
private:
// Data members
Node *head;
Node *trailer;
};
#endif // INVENTORY_H
Inventory.cpp
#include "Inventory.h"
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <bits/stdc++.h>
using namespace std;
Inventory::Inventory()
{
// Set the header and trailer to NULL
head = NULL;
trailer = NULL;
}
// Allocates a new node with given data
Node *newNode(int data)
{
Node *new_node = new Node;
new_node->data = data;
new_node->next = NULL;
return new_node;
}
// Function to insert a new node at the
// end of linked list using recursion.
Node* insertEnd(Node* head, int data)
{
// If linked list is empty, create a
// new node (Assuming newNode() allocates
// a new node with given data)
if (head == NULL)
return newNode(data);
// If we have not reached end, keep traversing
// recursively.
else
head->next = insertEnd(head->next, data);
return head;
}
main.cpp
#include <iostream>
#include "Inventory.h"
using namespace std;
int main()
{
// Create an inventory list
Inventory inventory1;
Node* head = NULL;
head = inventory1.insertEnd(head, 8);
head = inventory1.insertEnd(head, 11);
head = inventory1.insertEnd(head, 20);
return 0;
}
For starters the structure Node should be a private member of the class Inventory. Correspondingly the class Inventory should not contain public member functions that have the return type Node *. So for example this member function
Node *newNode(int data);
should be removed. In turn this public member function
Node* insertEnd(Node* head, int data);
should be declared like
void insertEnd( int data );
If it is required (but it is not required) the function could call a private static member function declared like
static Node* insertEnd(Node* head, int data);
As you declared a two-sided singly-linked list then it does not make sense to define the function insertEnd as a recursive function because there is no recursion. A new node ia appended to the node that you named like trailer though it would be better to name it like tail.
Moreover in the definitions of the functions newNode and insertEnd you forgot to specify name of the class Inventory like
Node * Inventory::newNode(int data)
{
//...
}
Node * Inventory::insertEnd(Node* head, int data)
{
//...
}
And this part in main
Inventory inventory1;
Node* head = NULL;
head = inventory1.insertEnd(head, 8);
head = inventory1.insertEnd(head, 11);
head = inventory1.insertEnd(head, 20);
does not make sense. The object inventory1 already contains the data member head (and trailer) that should be updated for the object.
The class can be defined for example the following way as it is shown in the demonstrative program below.
#include <iostream>
class Inventory
{
public:
Inventory() = default;
Inventory( const Inventory & ) = delete;
Inventory & operator =( const Inventory & ) = delete;
~Inventory();
void insertEnd( int data );
void clear();
friend std::ostream & operator <<( std::ostream &, const Inventory & );
private:
struct Node
{
int data;
Node *next;
} *head = nullptr, *tail = nullptr;
};
Inventory::~Inventory()
{
clear();
}
void Inventory::insertEnd( int data )
{
Node *node = new Node { data, nullptr };
if ( tail == nullptr )
{
head = tail = node;
}
else
{
tail = tail->next = node;
}
}
void Inventory::clear()
{
while ( head != nullptr )
{
Node *node = head;
head = head->next;
delete node;
}
tail = head;
}
std::ostream & operator <<( std::ostream &os, const Inventory &inventory )
{
for ( Inventory::Node *node = inventory.head; node != nullptr; node = node->next )
{
os << node->data << " -> ";
}
return os << "null";
}
int main()
{
Inventory inventory;
for ( const auto &data : { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } )
{
inventory.insertEnd( data );
}
std::cout << inventory << '\n';
return 0;
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null

Why there's no error when I delete twice the same memory?

MySinglyLinkedList.h:
#include <iostream>
template<class T> class LinkedList;
template<class T>
class LinkedNode {
public:
LinkedNode(T new_data):data(new_data) {; }
private:
friend class LinkedList<T>;
LinkedNode<T> *next;
T data;
};
template<class T>
class LinkedList {
public:
LinkedList();
~LinkedList();
void PushNode(T new_data);
void Delete(LinkedNode<T> *pnode);
void Show();
private:
LinkedNode<T> *head; //Head pointer
LinkedNode<T> *tail; //Tail pointer
int length; //Length of the list
};
//Initialize an empty list when creating it
template<class T>
LinkedList<T>::LinkedList()
{
head = tail = NULL;
length = 0;
}
//delete all the nodes when deconstructing the object
template<class T>
LinkedList<T>::~LinkedList()
{
LinkedNode<T> *ptr = head;
while (ptr)
{
LinkedNode<T> *ptr_del = ptr;
ptr = ptr->next;
Delete(ptr_del);
}
}
//Add one node to the tail of the list
template<class T>
void LinkedList<T>::PushNode(T new_data)
{
LinkedNode<T> *pnew_node = new LinkedNode<T>(new_data);
pnew_node->next = NULL;
if (!length) {
head = tail = pnew_node;
length++;
} else {
tail->next = pnew_node;
tail = pnew_node;
length++;
}
}
//Delete the node pointed by pnode
template<class T>
void LinkedList<T>::Delete(LinkedNode<T> *pnode)
{
LinkedNode<T> *ptr = head;
if (pnode==head) {
head = pnode->next;
} else {
while(ptr->next != pnode)
{
ptr = ptr->next;
}
ptr->next = pnode->next;
}
if(pnode == tail)
tail = ptr;
delete pnode;
length--;
}
template<class T>
void LinkedList<T>::Show() //Print all the contents in the list
{
LinkedNode<T> *pnode = head;
while(pnode)
{
std::cout << pnode->data << std::endl;
pnode = pnode->next;
}
std::cout << "In total: " << length << std::endl;
}
The main function is as follows:
#include "MySinglyLinkedList.h"
#include <cstdlib>
#include <ctime>
using namespace std;
int main(int argc, char *argv[])
{
//list_len is the length of the list
int list_len = 5;
srand(time(0));
if (argc > 1)
list_len = atoi(argv[1]);
LinkedList<int> test_list; //Create the first list: test_list
for (int i = 0; i < list_len; i++)
{
//The elements in the list are random integers
int cur_data = rand()%list_len;
test_list.PushNode(cur_data);
}
test_list.Show();
LinkedList<int> test2 = test_list; //Create the second list: test2
test2.Show();
return 0;
}
Since I didn't define any copy constructor here, the default copy constructor will be called and do the bit copy when creating the second list, and as a result test_list and test2 will point to the same linked list. Therefore the first node of the list will be deleted twice when the two object are deconstructed. But the fact is nothing wrong happened when I compiled the program using GCC, and it ran successfully in Linux. I don't understand why no error occurred.
Deleting a pointer that has already been deleted causes undefined behavior, so anything can happen. If you want to make sure nothing happens, set the pointer to null after deletion. Deleting null does nothing, and it won't cause an error.
See: c++ delete (wikipedia)
As per Diego's answer, the C++ standard permits deleting NULL pointers. The compiler has no way to know what value your pointer will contain when you delete it the second time (i.e. it might be NULL), therefore it has no choice but to allow it in order to comply with the standard.

C++ Linked List assignment: trouble with insertion and deletion

I am working on a linked list implementation in C++. I am making progress but am having trouble getting the insertion functionality and deletion functionality to work correctly. Below is list object in the C++ header file:
#ifndef linkList_H
#define linkList_h
//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
Node() : sentinel(0) {}
int number;
Node* next;
Node* prev;
Node* sentinel;
};
//
// Create an object to keep track of all parts in the list
//
class List
{
public:
//
// Contstructor intializes all member data
//
List() : m_listSize(0), m_listHead(0) {}
//
// methods to return size of list and list head
//
Node* getListHead() const { return m_listHead; }
unsigned getListSize() const { return m_listSize; }
//
// method for adding and inserting a new node to the linked list,
// retrieving and deleting a specified node in the list
//
void addNode(int num);
void insertNode(Node* current);
void deleteNode(Node* current);
Node* retrieveNode(unsigned position);
private:
//
// member data consists of an unsigned integer representing
// the list size and a pointer to a Node object representing head
//
Node* m_listHead;
unsigned m_listSize;
};
#endif
And here is the implementation (.cpp) file:
#include "linkList.h"
#include <iostream>
using namespace std;
//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
++m_listSize;
}
//
// NOTWORKING: Inserts a node which has already been set to front
// of the list
//
void List::insertNode(Node* current)
{
// check to see if current node already at
// head of list
if(current == m_listHead)
return;
current->next = m_listHead;
if(m_listHead != 0)
m_listHead->prev = current;
m_listHead = current;
current->prev = 0;
}
//
// NOTWORKING: Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
current->prev->next = current->next;
current->next->prev = current->prev;
}
//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
if(position > (m_listSize-1) || position < 0)
{
cout << "Can't access node; out of list bounds";
cout << endl;
cout << endl;
exit(EXIT_FAILURE);
}
Node* current = m_listHead;
unsigned pos = 0;
while(current != 0 && pos != position)
{
current = current->next;
++pos;
}
return current;
}
After running a brief test program in the client C++ code, here is the resulting output:
Number of nodes: 10
Elements in each node:
9 8 7 6 5 4 3 2 1 0
Insertion of node 5 at the list head:
4 9 8 7 6 5 4 9 8 7
Deletion of node 5 from the linked list
As you can see, the insertion is not simply moving node 5 to head of list, but is overwriting other nodes beginning at the third position. The pseudo code I tried to implement came from the MIT algorithms book:
LIST-INSERT(L, x)
next[x] <- head[L]
if head[L] != NIL
then prev[head[L]] <- x
head[L] <- x
prev[x] <- NIL
Also the deletion implementation is just crashing when the method is called. Not sure why; but here is the corresponding pseudo-code:
LIST-DELET'
next[prev[x]] <- next[x]
prev[next[x]] <- prev[x]
To be honest, I am not sure how the previous, next and sentinel pointers are actually working in memory. I know what they should be doing in a practical sense, but looking at the debugger it appears these pointers are not pointing to anything in the case of deletion:
(*current).prev 0xcdcdcdcd {number=??? next=??? prev=??? ...} Node *
number CXX0030: Error: expression cannot be evaluated
next CXX0030: Error: expression cannot be evaluated
prev CXX0030: Error: expression cannot be evaluated
sentinel CXX0030: Error: expression cannot be evaluated
Any help would be greatly appreciated!!
You have got an error in addNode(). Until you fix that, you can't expect insertNode to work.
Also, I think your design is quite silly. For example a method named "insertNode" should insert a new item at arbitrary position, but your method insertNode does a pretty different thing, so you should rename it. Also addNode should be renamed. Also as glowcoder wrote, why are there so many sentinels? I am affraid your class design is bad as a whole.
The actual error is that you forgot to set prev attribute of the old head. It should point to the new head.
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
if(m_listHead) m_listHead->prev = newNode;
m_listHead = newNode;
++m_listSize;
}
Similarly, you have got another error in deleteNode(). It doesn't work when deleting last item from list.
void List::deleteNode(Node* current)
{
m_listSize--;
if(current == m_listHead) m_listHead = current->next;
if(current->prev) current->prev->next = current->next;
if(current->next) current->next->prev = current->prev;
}
Now you can fix your so-called insertNode:
void List::insertNode(Node* current)
{
int value = current->number;
deleteNode(current);
addNode(value);
}
Please note that I wrote everything here without compiling and testing in C++ compiler. Maybe there are some bugs, but still I hope it helps you at least a little bit.
In deleteNode, you are not handling the cases where current->next and/or current->prev is null. Also, you are not updating the list head if current happens to be the head.
You should do something like this:
node* next=current->next;
node* prev=current->prev;
if (next!=null) next->prev=prev;
if (prev!=null) prev->next=next;
if (m_listhead==current) m_list_head=next;
(Warning: I have not actually tested the code above - but I think it illustrates my idea well enough)
I am not sure what exactly your InsertNode method does, so I can't offer any help there.
OK.
As #Al Kepp points out, your "add node" is buggy. Look at Al's code and fix that.
The "insert" that you are doing does not appear to be a normal list insert. Rather it seems to be a "move to the front" operation.
Notwithstanding that, you need to delete the node from its current place in the list before you add it to the beginning of the list.
Update
I think you have misunderstood how insert should work. It should insert a new node, not one that is already in the list.
See below for a bare-bones example.
#include <iostream>
// List Node Object
//
struct Node
{
Node(int n=0);
int nData;
Node* pPrev;
Node* pNext;
};
Node::Node(int n)
: nData(n)
, pPrev(NULL)
, pNext(NULL)
{
}
//
// List object
//
class CList
{
public:
//
// Contstructor
//
CList();
//
// methods to inspect list
//
Node* Head() const;
unsigned Size() const;
Node* Get(unsigned nPos) const;
void Print(std::ostream &os=std::cout) const;
//
// methods to modify list
//
void Insert(int nData);
void Insert(Node *pNew);
void Delete(unsigned nPos);
void Delete(Node *pDel);
private:
//
// Internal data
//
Node* m_pHead;
unsigned m_nSize;
};
/////////////////////////////////////////////////////////////////////////////////
CList::CList()
: m_pHead(NULL)
, m_nSize(0)
{
}
Node *CList::Head() const
{
return m_pHead;
}
unsigned CList::Size() const
{
return m_nSize;
}
void CList::Insert(int nData)
{
Insert(new Node(nData));
}
void CList::Insert(Node *pNew)
{
pNew->pNext = m_pHead;
if (m_pHead)
m_pHead->pPrev = pNew;
pNew->pPrev = NULL;
m_pHead = pNew;
++m_nSize;
}
void CList::Delete(unsigned nPos)
{
Delete(Get(nPos));
}
void CList::Delete(Node *pDel)
{
if (pDel == m_pHead)
{
// delete first
m_pHead = pDel->pNext;
if (m_pHead)
m_pHead->pPrev = NULL;
}
else
{
// delete subsequent
pDel->pPrev->pNext = pDel->pNext;
if (pDel->pNext)
pDel->pNext->pPrev = pDel->pPrev;
}
delete pDel;
--m_nSize;
}
Node* CList::Get(unsigned nPos) const
{
unsigned nCount(0);
for (Node *p=m_pHead; p; p = p->pNext)
if (nCount++ == nPos)
return p;
throw std::out_of_range("No such node");
}
void CList::Print(std::ostream &os) const
{
const char szArrow[] = " --> ";
os << szArrow;
for (Node *p=m_pHead; p; p = p->pNext)
os << p->nData << szArrow;
os << "NIL\n";
}
int main()
{
CList l;
l.Print();
for (int i=0; i<10; i++)
l.Insert((i+1)*10);
l.Print();
l.Delete(3);
l.Delete(7);
l.Print();
try
{
l.Delete(33);
}
catch(std::exception &e)
{
std::cerr << "Failed to delete 33: " << e.what() << '\n';
}
l.Print();
return 0;
}