C++ Singly Linked List Insertion Sort - c++

So hey, I'm having a problem with this project I have. I'm supposed to read integers from a file and insert them into a list. There's a findSpot function that needs to be implemented that traverses the linked list and if the next node's value is larger than what is being checked, it returns the current "spot". And then we output the linked list to a separate file.
Here's the code.
#include <iostream>
#include <fstream>
using namespace std;
class listNode {
public:
int value;
listNode* next;
friend class linkedList;
listNode()
: value(0)
, next(NULL)
{
}
public:
~listNode(){
};
};
class linkedList {
listNode* listHead;
public:
linkedList()
: listHead(NULL)
{
}
bool isEmpty()
{
return (listHead == 0);
}
void listInsert(int data, listNode* spot)
{
listNode* newNode;
newNode->value = data;
newNode->next = NULL;
if (isEmpty()) {
listHead = newNode;
}
else {
newNode->next = spot->next;
spot->next = newNode;
cout << newNode;
}
}
/*void listDelete ()
{
}*/
listNode* findSpot(int data)
{
listNode* spot;
spot = listHead;
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
return spot;
}
void printList(listNode* spot)
{
listNode* newNode = spot;
while (newNode != NULL) {
cout << "Inserting " << newNode->value << ": "
<< "listHead-->(" << newNode->value << "," << newNode->next->value << ")-->(";
newNode = newNode->next;
}
cout << endl;
}
/*~linkedList()
{
listNode* temp = spot->next;
spot->next = spot->next->next;
delete temp;
}*/
};
int main(int argc, char* argv[])
{
int data;
listNode* spot;
ifstream infile;
infile.open(argv[1]);
ofstream outfile(argv[2]);
cout << "Reading Data from the file" << endl;
while (infile >> data) {
cout << data << endl;
}
infile.close();
linkedList myList;
infile.open(argv[1]);
while (infile >> data) {
myList.findSpot(data);
myList.listInsert(data, spot);
myList.printList(spot);
}
cout << "Printing your linked list to the output file.";
/*while (outfile.is_open())
{
myList.printList();
}*/
infile.close();
outfile.close();
return 0;
}
I don't know if the problem lies mainly in the insertList function or if it's the findSpot function. The findSpot function seems correct to me but I may just be missing something.
As I run the code, the actual reading of the file the first time is fine. Actually inserting anything into the linked list causes the program to hang.

Ok, lets try this again. I'll actually include some code, but please try to use this as a learning point, and not something to just copy paste. I know you said you were copying your teachers algorithm, but what they gave you is probably just that, an algorithm. It is your job to actually implement that in working code, checking for error conditions, etc. Anyway, here we go:
For the function findSpot:
listNode* linkedList::findSpot(int data) {
listNode* spot = listHead; // Initialize spot to start of list
if ( isEmpty() ) // if list is empty, return NULL
return NULL;
// now we know listHead isn't null, so look through the list and
// find the entry that has a value greater than the one provided
// return the list item BEFORE the one with the greater value
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
// return the one we found; This could be the same as listHead
// (start of list), something in the middle, or the last item on the
// list. If we return from here, it will not be NULL
return spot;
}
Now we can do the insert function:
void linkedList::listInsert(int data, listNode* spot) {
// We need a new item to put on the list, so create it
listNode* newNode = new listNode();
newNode->value = data;
newNode->next = NULL;
// If the list is empty, update the head to point at our new object
if ( isEmpty() ) {
listHead = newNode;
// otherwise point spot to new item, and new item to the one spot
// pointed to
} else {
newNode->next = spot->next;
spot->next = newNode;
}
}
Looking at your print function, that is going to have it's own issues. It looks like you want to print the whole list, but it seems that you are starting to print from "spot". It's all very confused. It also has an issue using newNode->next->value, without checking if newNode->next is NULL. Here's a short example of what I think you are trying to do... note that I don't even need to pass in spot, just the data point added:
void linkedList::printList(int data) {
// if some huckleberry called this before calling insert,
// list will be empty... always a good idea to check
if ( isEmpty())
return;
// first line of output... just print out the data point
// added and start of output text
cout << "Inserted " << data << ": " << "listHead-->(";
// start at start of list
listNode* newNode = listHead;
// loop through until we find the end
while (newNode != NULL) {
cout << newNode->value; // print the value
newNode = newNode->next; // move to the next item on the list
// We moved to the next node; It might be NULL and the loop will end
// if not, we want to print an open bracket since we know another one
// is going to be printed
if ( newNode != NULL )
cout << ")-->(";
}
// last item was just printed, so close off the last bracket
cout << ")" << endl;
}
Hope that is somewhat helpful

Since this looks like a homework assignment, I'm going to give you one fix:
change
myList.findSpot(data);
to
spot = myList.findSpot(data);
If you look closely, spot is used, but never assigned anything.

Well, there are several problems with your program (besides formatting). In the function findSpot(), you have:
listNode* spot;
spot = listHead;
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
return spot;
The problem here is that the first time you call this, listHead is NULL, so the
while (spot->next
is going to fail, since spot is NULL.
I also notice that nowhere in your code do you call new(). In listInsert, you need to use new() to initialize your newNode variable.
Lastly, find spot has 2 conditions where it can return NULL. If the list is empty, it should return NULL, and you would want to insert at the start of the list. If the new value you are adding is greater than all the others, you will also return NULL and you would have to add to the end of the list.
Since this is a homework assignment, I don't want to write the code for you, but hopefully that helps.

Related

Last node is not printed in Linked List

I was trying to learn the Linked list and perform insertion operations from beginning of the list. while printing the nodes, the first node is not printed. Here is the core functions which I have written. Can someone help me?
struct Node //basic structure for a node
{
ll data; //data which we want to store
Node* link; //address of the next node;
};
Node* head=NULL;
void Insert(ll x) //insertion at beginning
{
Node* temp=new Node();
temp->data=x;
temp->link=head; //we are linking new node with previously connected node
head=temp;
}
void Print()
{
Node* temp=head;
while(temp->link!=NULL) //traversing the list until last element(last element.link = NULL)
{
cout<<temp->data<<" ";
temp=temp->link;
}
cout<<endl;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
f(i,0,5)
{
ll x;cin>>x;
Insert(x);
}
Print();
return 0;
}
Your Print function requires that the last node is linked or it won't be printed. Since the last node is never linked, it will never be printed.
void Print()
{
Node* temp = head;
while(temp) // <- corrected condition
{
std::cout << temp->data << ' ';
temp = temp->link;
}
std::cout << '\n';
}
It's because of your check in the while. The node will have link set as NULL, and therefore it will exit the while without printing it. My recommendation is changing the while check to (temp != NULL), but you can also fix it by putting a cout << temp->data; after the loop
In general the function Print can invoke undefined behavior when it is called for an empty list due to the expression temp->link that uses a null pointer to access memory.
Another side effect is that the last node will be skipped due to the condition in the while loop (if the list has only one node then its value will not be outputted)
while(temp->link!=NULL)
The function can be declared and defined the following way
std::ostream & Print( std::ostream &os = std::cout )
{
for ( const Node *current = head; current != nullptr; current = current->next )
{
os << current->data << " -> ";
}
return os << "null";
}
And in main the function can be called like
Print() << '\n';
The function is flexible. You can use it to write data in a file providing a corresponding file stream.
The function Insert can be simplified the following way
void Insert( ll x ) //insertion at beginning
{
head = new Node { x, head };
}
Pay attention to that it is a bad idea to declare the pointer head in the global namespace. In this case all functions depend on the global variable and you can not for example to use two lists in your program.
So you should declare the pointer in main.
int main()
{
Node *head = nullptr;
//...
In this case for example the function Insert can look the following way
void Insert( Node * &head, ll x ) //insertion at beginning
{
head = new Node { x, head };
}
and called in main like
Insert( head, x );

How to delete nodes in the middle and end of a doubly linked list

I am trying to delete the odd numbers that are randomly generated (see oddsOnly), and then print the list in reverse order. I can delete odds that may pop up at the beginning of the list, but I cannot find a way to delete anything after that.
I have tried various forms of if and while loops. Too many different ways for me to remember or list them all.
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
struct Node
{
int element;
Node *next;
Node *previous;
};
// Function headers
int takeNumber(int);
int writeFile(int);
struct Node *readFile(Node *&, int);
void printBackward(Node *);
struct Node *oddsOnly(Node *&, int);
void deleteList(Node *);
// Main
int main(int argc, char *argv[])
{
// Check to see if the user passed us the size to make the list.
if (argc == 2)
{
// Check to see if what the user passed us is in fact a valid number.
// Here we attempt to assign what was passes in to us to an int variable
int Size = atoi(argv[1]);
// Now we check a few things. If the !Size tells us whether or not the
// assignment above was successful. If the size is less than 20 or
// greater than 100, the input did not follow the instructions. In
// either case we ask the user to enter another number with the printed
// instructions of it must be between 20 and 100.
if (!Size || Size < 20 || Size > 100)
{
Size = takeNumber(Size);
}
// Create the pointer for Head. This is used to keep track of the beginning
// of the list.
Node *Head = new Node;
if (Head == NULL)
{
cout << "fatal error: could not create Head node." << endl;
return(1);
}
Head = NULL;
// If we are here, the head node was created successfully. As this is
// currently also the last node in the list, set the pointer to NULL.
//Head->next = NULL;
writeFile(Size);
readFile(Head, Size);
// When you allocate memory with new or malloc, you should always clean
// free up the memory when you are through.
deleteList(Head);
}
else
{
int Size = 0;
Size = takeNumber(Size);
// Create the pointer for Head. This is used to keep track of the beginning
// of the list.
Node *Head = new Node;
if (Head == NULL)
{
cout << "fatal error: could not create Head node." << endl;
return(1);
}
Head = NULL;
// If we are here, the head node was created successfully. As this is
// currently also the last node in the list, set the pointer to NULL.
//Head->next = NULL;
writeFile(Size);
readFile(Head, Size);
oddsOnly(Head, Size);
// When you allocate memory with new or malloc, you should always clean
// free up the memory when you are through.
deleteList(Head);
}
system("pause");
return 0;
}
// Function to take input (size) from the user
int takeNumber(int Size)
{
while (Size < 20 || Size > 100)
{
// Output specific instructions to the user.
cout << endl << "Please inter a number between 20 and 100 (inclusive). " << endl;
// Take a given input from the user.
cin >> Size;
// Set a while loop so that if the incorrect input is given, the user will
// be asked to enter a different input untill it fits the given discription
// in the instructions.
if (cin.fail() || Size < 20 || Size > 100)
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
// Print error message and ask for another input.
cout << "Input is not between 20 and 100 (inclusive). " << endl;
cout << "Please try again. " << endl << endl;
}
}
// Return the input.
return Size;
}
// Function to write random numbers to a binary file
int writeFile(int size)
{
// Create and open the file you will write to.
ofstream WriteFile;
WriteFile.open("numbers.bin", ios::out | ios::binary);
// Make sure to print an error message if the file was not created.
if (!WriteFile)
{
cout << "Could not create/open binary file for writing. " << endl << endl;
return (1);
}
// Seed the random fuction with the time from the computer.
srand(int(time(NULL)));
// create a variable to store the random variable gernerated.
int number = 0;
// Create a loop to generate some random data and store it in
// the number variable. Then write the number to the to the binary
// file.
for (int i = 0; i < size; i++)
{
// Generate a random number between 0 and 99.
number = (rand() % 100);
// Write the number to the binary file.
WriteFile.write(reinterpret_cast<const char *>(&number), sizeof(int));
}
WriteFile << endl;
// Close the binary file.
WriteFile.close();
return(0);
}
// Function to read the binary file and create a linked list.
struct Node *readFile(Node *&Head, int Size)
{
// Create and open a read binary file
ifstream ReadFile;
ReadFile.open("numbers.bin", ios::in | ios::binary);
// Check to make sure file has been created and opened.
if (!ReadFile)
{
cout << "Could not open the binary file for reading. " << endl << endl;
}
int Data = 0;
int counter = 1;
while (ReadFile)
{
ReadFile.read((char*)&Data, sizeof(int));
if (ReadFile.eof())
{
break;
}
if (Head == NULL)
{
Node *tmp = new Node;
if (tmp == NULL)
{
cout << "fatal error: could not create tmp node" << endl;
}
tmp->element = Data;
tmp->next = NULL;
tmp->previous = NULL;
Head = tmp;
counter = counter + 1;
}
else if (Head != NULL)
{
Node *current = new Node;
if (current == NULL)
{
cout << "fatal error: could not create current node" << endl;
}
current = Head;
while (current->next != NULL)
{
current = current->next;
}
struct Node *temp = new Node;
if (temp == NULL)
{
cout << "fatal error: could not create temp node" << endl;
}
temp->element = Data;
temp->next = NULL;
temp->previous = current;
current->next = temp;
counter = counter + 1;
}
}
cout << endl;
// Close the file
ReadFile.close();
oddsOnly(Head, Size);
printBackward(Head);
cout << endl;
return Head;
}
// Function to read the numbers.bin file and put numbers in reverse order
void printBackward(Node *Head)
{
// We now have a list. We can traverse the list and print the elements.
// We have the head, we create a current or tmp node pointer to set it
// equal to head.
Node *temp;
temp = Head;
while (temp->next != NULL)
{
temp = temp->next;
}
// We can use a counter to format the output on the console
int counter = 1;
// This is our loop to traverse the list. We start at head, and go until
// we reach the null pointer of the last node.
while (temp != NULL)
{
// This prints the number in the node, then a tab separator to the
// console.
cout << temp->element << "\t";
// This is used for formatting the output on the screen. In this case,
// after every five nodes have been printed, we insert a newline and
// reset the counter to 0.
if (counter % 5 == 0)
{
cout << endl;
counter = 0;
}
// We advance the tmp or current pointer to the next value and increment the counter.
temp = temp->previous;
counter = counter + 1;
}
}
// Function to weed out the odd numbers in the list
struct Node *oddsOnly(Node *&Head, int size)
{
int counter = 1;
while (Head->element % 2 == 0)
{
struct Node *temp = Head;
Head = Head->next;
Head->previous = NULL;
delete(temp);
return Head;
counter = counter + 1;
}
Node *tmp = Head;
while (tmp != NULL)
{
Node *current = Head;
while (current->element % 2 != 0 && current->next->next != NULL)
{
current = current->next;
tmp = current->next;
}
current->previous->next = current->next;
current->next->previous = current->previous;
delete(current);
struct Node *current1 = Head;
while (current1->next != NULL)
{
current1 = current1->next;
}
if (current1->element % 2 == 0)
{
current1->previous->next = NULL;
delete(current1);
}
tmp = tmp->next;
}
cout << endl;
return Head;
}
// Function to delete the link list.
void deleteList(Node *Head)
{
Node *tmp;
// Loop through the list, deleting one node at a time. We set tmp equal
// to the node after head, delete head and then set head equal to tmp.
while (Head != NULL)
{
tmp = Head->next;
delete(Head);
Head = tmp;
}
}
I am looking for a list that allows 5 integers before starting a new line, and that has only odd values from the linked list.
I have gotten a lot of error messages displaying 0xDDDDDDDD in the oddsOnly function. at this point though, I am only seeing that it is not deleting the evens after the first node in the list.
Refer to the following diagram:
To delete node B from the list, set A.Next to A.Next.Next, set C.Prev to C.Prev.Prev, and free node B.
To delete node D from the list, set C.Next to C.Next.Next (which is null), and free node D.
Make sure you write a function that does this. Your code suggests that you're not fully taking advantage of the encapsulation and "divide and conquer" strategy that functions provide.
Further Reading
Delete a node in a Doubly Linked List
Stealing Roberts great picture
I don't quite agree with his description (it is correct though just a bit complicated when written in English).
Node* x = findNodeToDelete();
if (x == nullptr) { // Check to make sure you have an actual node to delete.
return;
}
if (x->next != nullptr) {
x->next->prev = x->prev;
}
if (x->prev != nullptr) {
x->prev->next = x->next;
}
else {
Head = x->next;
}
// Now you have unlinked the node from the list.
x->next = nullptr; // Optional if node has a complex destructor may be worth it.
x->prev = nullptr; // Optional
// Now release the node you are deleting.
delete x;
As you know there are 3 situations in deleting being
1 - head
2 - middle
3- end
I think you covered the first one lest proceed to the second one
lets say you are in a traversing loop
while( cur != NULL ){
...
cur = cur -> next;
let's look at the middle of the node for second case
For deletion in the middle, you should know the previous node and the next node of to deleted node and you should bind them together. Luckily you both have previous and next in doubly linked list.
so lets add a statement to a code
if ( cur -> data == oddNumber ){
Node* prev = cur -> prev;
Node* next = cur -> next;
prev -> next = cur -> next;
delete cur;
cur = cur -> next;
}
that was for the middle, and for the end (3 rd case) you can simply check if the next node of the node is NULL and delete it peacefully.

trying to make a simpler insertion at end of linked list program.Help needed with minor issues

I have managed to create a simple insertion at beginnning of linked list program but now i am struggling with insertion at end of linked list.
The program seems to be able to take values from user but the output list is not coming correct.Could you help me out?
If possible keep along the lines of my program as i am beginner and won't be able to understand a completely different method.
Logic i used-
If list is empty then insert value at beginning else if list is not empty then travel along the list till the next value being pointed at is NULL and then enter the new value in place of NULL.
#include<iostream>
using namespace std;
struct node
{
int data;
node *next;
};
node *start=NULL;
void insertend(int x)
{
node* temp=new node;
if(start==NULL)
temp->data=x;
else
{
while(temp!=NULL)
{
temp=temp->next;
}
temp->next=x;
}
}
void display()
{
node* disp=new node;
while(disp!=NULL)
{
cout<<disp->data<<endl;
disp=disp->next;
}
}
int main()
{
int x;
char ch;
do
{
cout<<"Enter data";cin>>x;
cout<<endl;
insertend(x);
cout<<"Do you want to continue?(y/n)";cin>>ch;
cout<<endl;
}while(ch=='y');
cout<<"Your list:"<<endl;
display();
}
The entry point to your list is the variable start. But you never set it. Take for example the first item a user inputs. You will call insertend(), it will check that start == NULL, but then it never sets start. You must set start = temp or something similar. You have the same problem in the else section -- you loop through the nodes starting with temp, but you should be starting with start. And again in the function display(), you create a pointer to a node and start looping from it, but it will have no data -- you should use start as the starting point of your loop.
struct node{
int data;
node* next;
};
node *first = NULL, *last = NULL;
void insert(int x){
if(first == NULL){
first = new node;
first->data = x;
first->next = NULL;
}else if(last == NULL){
last = new node;
last->data = x;
first->next = last;
last->next = NULL;
}else{
node *n = new node;
n->data = x;
n->next = NULL;
last->next = n;
last = n;
}
}
As you can see I am keeping track of first and last node in the list. Insert function checks if there is anything in the list with if(first == NULL)part. If there isn't it creates the first node. Similar thing happens with the else if. Finally in the else block we create a new node with data x. Then point the node stored in variable last to our new node and set last to be that node.
Here is the display function:
void display()
{
node *disp =first;
while(disp->next != NULL){
cout << disp->data << " ";
disp = disp->next;
}
cout << disp->data;
}
I also recommend that you do a cleanup after your program is finished running since you are creating new nodes.
void cleanup(node* n)
{
if(n->next == NULL)return delete n;
cleanup(n->next);
delete n;
}
and then at the end of main call cleanup(first)
Hope this makes sense :) Have a nice day!

C++: While loop won't terminate as NULL, am I missing something?

It seems that I can't figure out why the while loop wont terminate.
It should be while(null) essentially.
I can't figure it out.
All help would be appreciated :D
I dont know what could possibly be stopping the while loop at all? It says that the first entry gets stored, and the entry for next is at 0x0000000000 and ??? name and ??? ??? coords so it is in fact NULL. I tried adding in the constructor next = 0; instead of next = NULL and it still did not work.
Thanks guys.
Anthony
EDIT: Value of nodePtr = 00000000 if next = 0 in the constructor
Value of nodePtr = 00899FE0 if next = NULL in the constructor
if adding a cout << nodePtr->next; before the while.
http://pastebin.com/7usYdfHB -- Full program for reference.
EDIT2:
Is the popup when I go to enter the 2nd entry.
void LinkedList::appendNode(string name, double x, double y)
{
ListNode* newNode; // To point to new node
ListNode* nodePtr; // To traverse List
// allocate new node
newNode = new ListNode(name, x, y);
// If no head, head is the newNode
// else traverse the list to find the end and append newNode
if (!head)
{
head = newNode;
cout << "Record inserted successfully.\n" << endl;
}
else
{
nodePtr = head;
//traverse the list loop
while (nodePtr->next) //VS 2012 locks up here <-----
{
//Checks for duplicate entry by name
if (nodePtr->cityName == name)
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
//traverse the list
nodePtr = nodePtr->next;
}
// checks 2nd entry, as while loop wont run for a 2nd entry.
if (nodePtr->cityName == name) {
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
}
// if next is NULL add newNode
else if (!nodePtr->next)
{
nodePtr->next = newNode;
cout << "Record inserted successfully.\n" << endl;
}
}
Aside from the obvious memory leak when an attempt to insert an already existing name is made, your code seems to work fine. It works fine when either 0 or NULL is used to initialize the pointers. It makes no difference.
(One wild guess I can make is that in your actual calling code (which you do not show), you somehow managed to pass your LinkedList around by value. Since your LinkedList does not satisfy the Rule of Three, the integrity of the list got violated, which lead to undefined consequences you observed.)
BTW, by using an extra level of indirection you can simplify your heavily branched appendNode function into a significantly more compact and almost branchless one
void LinkedList::appendNode(string name, double x, double y)
{
ListNode** pnodePtr;
for (pnodePtr = &head; *pnodePtr != NULL; pnodePtr = &(*pnodePtr)->next)
if ((*pnodePtr)->cityName == name)
break;
if (*pnodePtr == NULL)
{
*pnodePtr = new ListNode(name, x, y);
cout << "Record inserted successfully.\n" << endl;
}
else
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
}
(I also eliminated the leak.) Specifically, this technique allows one to avoid writing a dedicated branch for processing the head node.
Also (referring to the full version of the code), in your functions from "delete by coordinate" group you for some reason check both x and y coordinates of the head node, but only one coordinate of the other nodes down the list. Why? This is rather weird and does not seem to make much sense. Meanwhile, functions from "search by coordinate" group do not have this issue - they process all nodes consistently.
Also, your displayList function suffers from a stray return at the very beginning, which is why it never prints anything. You need to add a pair of {} to properly group your statements.
I tried to reproduce your problem but could not. I reverse engineered your ListNode and LinkedList classes. The code below works, maybe that will help you sort out your issue. I refactored it a little to simplify it (going further you should consider keeping track of the end of the list as this will help with other operations that your list will need). Be sure to implement a destructor for your LinkedList class to clean up the nodes.
#include <string>
#include <iostream>
using namespace std;
struct ListNode
{
string cityName;
double m_x, m_y;
ListNode* next;
ListNode(string name, double x, double y) : cityName(name), m_x(x), m_y(y), next(nullptr)
{}
};
class LinkedList
{
ListNode* head;
public:
LinkedList() : head(nullptr)
{
}
~LinkedList()
{
}
void LinkedList::appendNode(string name, double x, double y)
{
ListNode* newNode; // To point to new node
// allocate new node
newNode = new ListNode(name, x, y);
// If no head, head is the newNode
// else traverse the list to find the end and append newNode
if (!head)
{
head = newNode;
cout << "Record inserted successfully.\n" << endl;
}
else
{
ListNode *nodePtr = head;
ListNode *prevNode = nullptr;
//traverse the list loop
while (nodePtr)
{
//Checks for duplicate entry by name
if (nodePtr->cityName == name)
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
//traverse the list
prevNode = nodePtr;
nodePtr = nodePtr->next;
}
// if next is NULL add newNode
if (prevNode)
{
prevNode->next = newNode;
cout << "Record inserted successfully.\n" << endl;
}
}
}
};
int main()
{
LinkedList list;
list.appendNode("New York", 1.0, 2.0);
list.appendNode("Boston", 1.5, 2.5);
list.appendNode("Miami", 1.7, 2.7);
list.appendNode("Miami", 1.7, 2.7);
}

c++ node list - NULL test not working

I wanted to test the following code (which works fine for a non-null list) to see what would happen in the case of an empty list (in which case the head would be null).
hence the code which applies to filling the list is commented out..
But for some strange reason, the test for NULL in print_nodes() just doesnt seem to work. ive added some debug cout calls to see (and also checked using gdb) but whilst the value does indeed appear to be NULL, any if statements dont seem to test the equivalence properly..
any idea why?
many thanks!
#include <iostream>
using namespace std;
struct node {
char dat;
node *nextPtr;
};
//inserts new node and returns pointer
node* new_node(char data, node* prevNode);
//adds a new node at the head ofthe list
void new_head (node *head_, char dat_);
//inserts new node after *before
void insert_node (node *before, char dat_);
//runs through and prints the list - requires first node (head)
void print_nodes (node *head);
int main() {
cout <<endl << endl;
cout << endl << "*******************RUN******************" <<endl <<endl;
node* head = NULL;
if (head == NULL) {
cout << "head null"; //this works here
}
//head non-standard
// node* head = new node;
// head->dat ='a';
/*
node* b = new_node('b', head);
node* c = new_node('c', b);
node* d = new_node('d', c);
node* e = new_node('e', d);
node* f = new_node('f', e);
*/
print_nodes(head);
insert_node(head,'N');
print_nodes(head);
cout << endl << "*******************END RUN******************" <<endl;
return 0;
}
node* new_node(char data, node* prevNode) {
node* tempPtr = new node;
tempPtr->dat = data;
tempPtr->nextPtr = NULL; //standard
prevNode->nextPtr = tempPtr;
return tempPtr;
}
void new_head (node *head_, char dat_) {
}
void insert_node (node *before, char dat_) {
node* tempPtr = new node;
tempPtr->dat = dat_;
tempPtr->nextPtr = before->nextPtr;
before->nextPtr = tempPtr;
}
void print_nodes (node *head) {
node* tempPtr = head;
cout << "\nPrinting nodes..." <<endl;
if (tempPtr == NULL) { //this test is not working.. why?
cout << "tempPtr is NULL";
return;
} else { //only run in the non null case
for (tempPtr; tempPtr != NULL; tempPtr = tempPtr->nextPtr) {
cout << "Current node content: " << tempPtr->dat <<endl;
}
}
}
You have a problem: head was not allocated, but insert accesses its "next element":
before->nextPtr = tempPtr;
head is passed in as before, and you didn't allocate memory for head. Hence you dereference a NULL pointer here.
Could it be that your application crashes as a result, and the printout to cout isn't done because cout is buffered?
Try to:
Remove the call to insert
Change cout to cerr (unbuffered)
Report the results of these changes.
allocate head before insertion :
node * head = new node;
memset(head, 0, sizeof(node));
The code works for me using g++ 4.4.1 on windows. The message is displayed and then it crashes, because of other issues in the code. You are probably not seeing the message because the crash occurs before the output buffer containing the message is flushed.
In general, it is a good idea to write diagnostic messages to standard error (cerr) rather than standard output, as the error stream is not buffered.