Been working on this program for a couple of days in class and I keep getting seg faults. I can comment out the part of code that I think is causing it and I stop getting the fault but then my print function doesn't work. I am picking up the c++ book tomorrow to help.
//linkedList.cpp
//Declaration of main and menu functions
//Programmer: Ronnie Warden
//Date: 2.15.15
#include<iostream>
#include "link.h"
using namespace std;
int main()
{
Node *list = new Node;
int delNode;
int findNode;
int choice = 1;
list->next = NULL;
while (choice != 5)
{
choice = menu();
if (choice == 1)
*list = insertNode(list);
if (choice == 2)
{
cout << "Enter the ID you wish to delete: ";
cin >> delNode;
*list = deleteNode(list, delNode);
}
if (choice == 3)
printNode(list);
if (choice == 4)
{
cout << "Enter the ID you are searching for: ";
cin >> findNode;
*list = searchNode(list, findNode);
}
if (choice < 1 || choice > 5)
cout << "Invalid choice! Please try again." << endl;
}
return 0;
}
int menu()
{
int choice = 1;
cout << "1. Insert Node" << endl;
cout << "2. Delete Node" << endl;
cout << "3. Print List" << endl;
cout << "4. Search List" << endl;
cout << "5. Quit" << endl;
cin >> choice;
return choice;
}
This following part is the one throwing the seg fault.
//linkFun.cpp
//Declaration of functions used to manage the linked list
//Programmer: Ronnie Warden
//Date: 2.10.15
#include<iostream>
#include "link.h"
using namespace std;
/*************************************************************************************************************
Function: createNode
Parameters: No parameters
Return Type: Pointer to new node
Task: Create a node with "new" operator. Get a student data from keyboard and assign to members of the node.
*************************************************************************************************************/
Node createNode()
{
Node *newNode = new Node;
cout << "Last Name?" << endl;
cin >> newNode->lastName;
cout << "First Name?" << endl;
cin >> newNode->firstName;
cout << "ID?" << endl;
cin >> newNode->idNumber;
return *newNode;
}
/**************************************************************************************************************
Function: insertNode
Parameters: Pointer to the linked list
Return Type: Pointer to the linked list
Task: insert a new node to the linked list sorted by student's ID number. If ID is already in list notify user
***************************************************************************************************************/
Node insertNode(Node *list)
{
Node *newNode = new Node;
Node *tmp = new Node;
*newNode = createNode();
int id = newNode->idNumber;
if (list == NULL) //Insert in empty list
list->next = newNode;
else
{
*tmp = searchNode(list, id);
if (tmp->idNumber == newNode->idNumber)
{
cout << "ID number already in list! Please try again with a different ID number." << endl;
insertNode(list);
}
if (list != NULL)
{
Node *tmp = list;
if (tmp->idNumber > newNode->idNumber) //Insert as first
{
newNode->next = tmp;
list = newNode;
}
while (tmp->idNumber < newNode->idNumber) //Search for insertion point
{
if (tmp->next == NULL) //Insert at end
tmp->next == newNode;
tmp = tmp->next;
if (tmp->idNumber < newNode->idNumber && tmp->next->idNumber > newNode->idNumber && tmp->next != NULL) //Insert in-between
{
newNode->next = tmp->next->next;
tmp->next = newNode;
}
}
}
}
return *list;
}
/***************************************************************************************************************
Function: searchNode
Parameters: Pointer to the linked list, student ID number
Return Type: Pointer to the node with matched ID number
Task: Search the linked list by student Id number. Notify user if ID is not found
***************************************************************************************************************/
Node searchNode(Node *list, int id)
{
Node *missing = new Node;
if (list->idNumber == id) //Checks if first node matches id number
return *list;
else
{
Node *tmp = new Node; //creates temporary pointer to scroll through list
while (tmp->idNumber != id)
{
if (tmp->next == NULL) //checks if number is missing returns sentinel if not found
{
missing->idNumber = 9999;
return *missing;
}
tmp = tmp->next;
}
return *tmp;
}
}
/***************************************************************************************************************
Function: deleteNode
Parameters: Pointer to the linked list, student ID number
Return Type: Pointer to the list
Task: Delete a node from the list. Notify user if no node matches
***************************************************************************************************************/
Node deleteNode(Node *list, int id)
{
Node *tmp = new Node;
*tmp = searchNode(list, id);
return *list;
}
/***************************************************************************************************************
Function: printNode
Parameters: Pointer to the linked list
Return Type: None
Task: Display the linked list
***************************************************************************************************************/
void printNode(Node *list)
{
Node *tmp = new Node;
tmp = list;
while (tmp != NULL)
{
cout << tmp->lastName << endl;
cout << tmp->firstName << endl;
cout << tmp->idNumber << endl;
tmp = tmp->next;
}
}
If I comment out the entire else statement in the insertNode function I stop getting the seg fault but then when I call to print it prints 3 blank lines and then 0. Any help would be appreciated, and if it comes up, the reason I didnt use classes was because I am not allowed to, it has to be done in structured data type.
#ifndef LINK_H
#define LINK_H
struct Node {
char lastName[20];
char firstName[20];
int idNumber;
Node *next;
};
int menu();
Node createNode();
Node insertNode(Node*);
Node searchNode(Node*, int);
Node deleteNode(Node*, int);
void printNode(Node*);
#endif
Your main problem is that you're not using pointers right - you're kind of half way between pointers and objects. (I'm not going to address the fact that this is a C style program in C++)
For example: Your createNode() method returns a Node object. It does this by creating a new Node on the heap and then returning that node's contents. This means that you've actually got a memory leak. No one has remembered the pointer to the node you put in the heap and so it leaks.
My first step would be to make createNode() return a Node*
Node* createNode()
{
Node *newNode = new Node;
// All your cout/cin stuff
return newNode;
}
I'd follow the same pattern with the other methods - use pointers rather than objects. Take searchNode() as an example. Because you're using objects, you need a special "Not Found" node. If you use pointers, you can return NULL (preferable 0 in C++) for the "not found case". You also don't need to new and temporary variables.
Node* searchNode(Node* list, int id)
{
while(list != 0) {
if (list->id == id) {
return list;
}
// This only impacts the local list. It doesn't
// permanently change the value of the list
// passed in.
list = list->next;
}
return 0;
}
For bonus points on searchNode(): Since it is a sorted list, you can stop searching as soon as you find an id that is greater than the one you are looking for.
Now that you've done that, your insert method is a bit simpler:
Get a new node from the user
Check if it exists - if so delete the node you just created and give error
If not, search the list and find where to insert your new node.
Related
I'm currently working on some of my code. I'm trying to learn how the "List Class" from the STL library works under the hood. I can't seem to quite understand the process of removing a node from a list made by the user. Is there any information that is accessible that would better help me wrap my head around this problem.
#include <iostream>
#include <string>
using namespace std;
class Node {
public:
string todos;
Node* next;
Node(string todos) {
this->todos = todos;
next = NULL;
}
};
void print_list(Node* head) {
Node* temp = head;
while (temp != NULL) {
cout << temp->todos << " ";
temp = temp->next;
}
}
Node* takeinput() {
string var;
int num;
Node* head = NULL;
Node* tail = NULL;
cout << "Please enter 5 Todo tasks. " << endl;
cout << endl;
cout << "If you would like to exit this prompt please enter 'End' " << endl;
cout << "If you would like to enter an item onto the list please press 1 " << endl;
cout << endl;
cin >> num;
while (var != "End") {
if (num == 1) {
Node* newNode = new Node(var);
if (head == NULL) {
head = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = tail->next;
}
}
cin >> var;
if (num == 2) {
}
}
return head;
}
int main()
{
string hello;
Node* head = takeinput();
print_list(head);
}
I'm trying to learn how the "List Class" from the STL library works under the hood.
std::list is a doubly linked list with user specified type for node data.
For Visual Studio, it is a circular linked list with a dummy node, where dummy.next is a pointer to the first node and dummy.prev is a pointer to the last node, and where first_node.prev and last_node.next point to the dummy node. There is a list size and optional user defined allocator (for nodes). There is support for iterators with operator overloading. std::list::end() returns an iterator to the dummy node (note that iterators can't be null). std::list::splice() allows nodes to be moved within a list or from one list to another.
std::list::sort() should be a bottom up merge sort for linked lists, but starting with Visual Studio 2015, it was changed to a less efficient top down merge sort for linked list when it was switched to be iterator based. If interested, link to example bottom up version:
`std::list<>::sort()` - why the sudden switch to top-down strategy?
The source code for std::list is ~2000 lines. I recommend starting off with just basic double linked list code.
I'm working on an assignment for my college class, and I'm struggling to figure out why code for my push_front() function works without fail, but my push_back() always gives:
"Exception thrown: read access violation. st was nullptr."
struct NodeDate
{
int day, month, year; //Structure's data
struct NodeDate* nextNode; //Pointer to point to next node
}*start; //Not sure why we do this, but all examples contain it
class LinkedListDate
{
public:
//Prototype of member functions
NodeDate* create_node(NodeDate);
void push_front();
void pop_front();
void remove_front();
void search();
void display();
LinkedListDate();
void push_back();
void remove_back();
void pop_back();
};
LinkedListDate::LinkedListDate()
{
start = NULL; //Our first created pointer will be set to NULL
}
NodeDate* LinkedListDate::create_node(struct NodeDate newDate) //Function that creates a new node and returns said node
{
struct NodeDate* tempNode, *s;
tempNode = new(struct NodeDate); //Reserving memory for our temp node
if (tempNode == NULL) //If the node is empty
{
std::cout << "Memory not allocated " << std::endl;
return 0;
}
else //Otherwise assign parameter node value to temporary node
{
tempNode->day = newDate.day;
tempNode->month = newDate.month;
tempNode->year = newDate.year;
tempNode->nextNode = NULL; //Remember these are all values contained within the date struct
return tempNode; //Return the node
}
}
void LinkedListDate::push_front() //Function that will insert a node at the start of our linkedlist
{
struct NodeDate* tempNode, *st, newNode;
std::cout << "Enter the day: ";
std::cin >> newNode.day;
std::cout << "Enter the month: ";
std::cin >> newNode.month;
std::cout << "Enter the year: ";
std::cin >> newNode.year;
tempNode = create_node(newNode); //Creating a new node for date with the create_node function
if (start == NULL) //Checks if the starting (Head) node is NULL then first node to insert
{
start = tempNode; //Start node points to our temporary node
start->nextNode = NULL; //Assign null to start->next
}
else //Otherwise nodes are already available in the list
{
st = start; //Assign start to st
start = tempNode; //Start points to temporary node
start->nextNode = st; //Start next point to st
}
std::cout << "Element Inserted at beginning" << std::endl;
}
void LinkedListDate::push_back() //Function to insert a new node at the end of the linkedlist
{
struct NodeDate* tempNode, *st, newNode;
std::cout << "Enter the day: ";
std::cin >> newNode.day;
std::cout << "Enter the month: ";
std::cin >> newNode.month;
std::cout << "Enter the year: ";
std::cin >> newNode.year;
tempNode = create_node(newNode); //Creating a new node for date with the create_node function
st = start;
while (st->nextNode != NULL) //Move til we reach end of the list
{
st = st->nextNode; //Move to the next node
}
tempNode->nextNode = NULL; //Assign null to temporary node next
st->nextNode = tempNode; //st next points to temporary node
std::cout << "Element Inserted at last" << std::endl;
}
Again, push_front() works, but push_back() does not work (The program runs, but after inputting the date for the first node I get the exception.
I've been trying a lot of things, but I can't seem to figure out what exactly I'm doing wrong.
struct NodeDate
{
//...
}*start;
is the same is
struct NodeDate
{
//...
};
NodeDate *start;
push_back will fail when the list is empty (i.e. start is null).
void LinkedListDate::push_back()
{
//...
tempNode = create_node(newNode);
tempNode->nextNode = nullptr;
if(start == nullptr)
{
start = tempNode;
}
else
{
st = start;
while (st->nextNode != nullptr) //Move til we reach end of the list
{
st = st->nextNode; //Move to the next node
}
st->nextNode = tempNode;
}
std::cout << "Element Inserted at last" << std::endl;
}
I was working on a homework assignment with linked lists, and while it seems that the code itself is spitting out the "right" answer (what the teacher wants it to), it brings up an error message when running that states "the program has stopped working (it will be forced closed, reported to windows, etc)". The program doesn't force close after closing this dialogue, and besides this, seems to be exactly what my teacher is looking for in the assignment. Any suggestions?
#include <iostream> // Provides cout
#include <cstdlib> // Provides EXIT_SUCCESS
using namespace std; // Allows all standard library items to be used
struct node
{
int data;
node* link;
};
void insert_at_head(node*& head, int entry)
//Precondition: head is the head pointer of a linked list, entry is
// a non-negative integer
//Postcondition: Inserts a new node with data field set to entry at the
// beginning of the linked list head
{
node* n;
n = new node;
n->data = entry;
n->link = head;
head = n;
}
void print(const node* head)
//Precondistion: head is the head pointer of a linked list
//Postcondition: Prints that linked list
{
const node* cursor;
cout << "The linked list is:" << endl;
for (cursor=head; cursor != NULL; cursor=cursor->link)
cout << cursor-> data << " ";
cout << endl;
}
void delete_last(node* & head)
{
while (head->link != NULL)
{
int i;
for(i = 0; 10 >= i; i++)
{
struct node* secondlast = head;
struct node* last = head->link;
while(last->link != NULL)
{ struct node* t = last;
secondlast = t;
last = last->link;
}
delete last;
secondlast->link = NULL;
cout << "I have deleted the last element in the linked list" << endl;
print(head);
}
}
while (head == NULL)
{
return;
}
}
int main( )
{ int i;
node* head;
head = NULL;
for(i = 1; 10 >= i; i++)
{
insert_at_head(head, i);
}
print(head);
delete_last(head);
return EXIT_SUCCESS;
}
My linked lists program works, but it wont show all of the list
here is my code
When the user enters a name and contribution it stores it in the list. When i print out the list only the last name that the user entered showed. I think its in my AddToList function is the problem Thanks
#include <string>
using namespace std;
struct PersonRec
{
char aName[20];
//string aName;
int aBribe;
PersonRec* link;
};
class PersonList
{
private:
PersonRec *head;
bool IsEmpty();
public:
PersonList();
~PersonList();
void AddToList();
void ViewList();
};
#include <iostream>
#include <string>
using namespace std;
#include "personlist.h"
PersonList::PersonList()
{
head = NULL;
}
PersonList::~PersonList()
{
PersonRec *current, *temp;
current = head;
temp = head;
while(current != NULL)
{
current = current->link;
delete temp;
temp = current;
}
}
bool PersonList::IsEmpty()
{
//PersonRec *p;
if(head == NULL)//it has no nodes head will poin to NULL
{
return true;
}
else
{
//p = head;
return false;
}
}
void PersonList::AddToList()
{
PersonRec *p;
head = new PersonRec();
//if(head == NULL)
//{
if(!IsEmpty())
{
//head = new PersonRec();
cout<<"Enter the person's name: ";
cin.getline(head->aName, 20);
//cin>>head->aName;
cout<<"Enter the person's contribution: ";
cin>>head->aBribe;
//head->link = NULL;
//}
}
else
{
p = head;
while(p->link != NULL)
p = p->link;
p->link = new PersonRec();
}
}//end function
void PersonList::ViewList()
{
PersonRec *p;
p = head;
if(IsEmpty())
{
cout<<"List is Empty "<<endl;
}
while(p != NULL)
{
cout<<p->aName<<" "<<"$"<<p->aBribe<<endl;
p = p->link;
}
}
#include <iostream>
#include "personlist.h"
using namespace std;
int displayMenu (void);
void processChoice(int, PersonList&);
int main()
{
int num;
PersonList myList;
do
{
num = displayMenu();
if (num != 3)
processChoice(num, myList);
} while (num != 3);
return 0;
}
int displayMenu(void)
{
int choice;
cout << "\nMenu\n";
cout << "==============================\n\n";
cout << "1. Add student to waiting list\n";
cout << "2. View waiting list\n";
cout << "3. Exit program\n\n";
cout << "Please enter choice: ";
cin >> choice;
cin.ignore();
return choice;
}
void processChoice(int choice, PersonList& p)
{
switch(choice)
{
case 1: p.AddToList();
break;
case 2: p.ViewList();
break;
}
}
Think about it: head is a pointer to the first item in your list, and the first thing you do in AddToList() is:
head = new PersonRec();
What do you think is going to happen to the current list when you overwrite head in this manner?
Don't change head until you're ready. The basic pseudo-code would be:
newnode = new PersonRec; # Don't overwrite head yet.
# Populate newnode with payload.
newnode-> next = head # Put current list at end.
head = newnode # Now you can change it.
That's if you wanted the new node at the start of the list. If you want it at the end, it's a little more complicated since you either have to:
traverse the list looking for the last node so you can append the new node to it; or
keep a pointer to the last node as well, to avoid traversal.
But the detail remains the same: don't destroy your head pointer until such time as you have the current list accessible by some other means.
I should mention that, based on your commented out code in AddToList(), you appear to be very close. Setting head should be done in the case where isEmpty() is true. But you appear to have commented that out and moved the head = new ... bit to outside/before the if statement. Not sure exactly what happened there with your thought processes.
It looks like what you tries to do was along the lines of:
if isEmpty:
head = new PersonRec;
p = head
else:
p = head
while p->next != NULL:
p = p->next
p->next = new PersonRec;
p = p->next
# Here, p is a pointer to the new node (head or otherwise)
# and the list is stable
p-> payload/link = whatever/null
That last line is also important, and your code doesn't seem to do it in all cases (ie, other than when you're creating the initial node in the list).
Making that a little less language-agnostic would give you something like (untested):
void PersonList::AddToList() {
PersonRec *p;
if(!IsEmpty()) {
p = head = new PersonRec();
} else {
p = head;
while (p->link != NULL)
p = p->link;
p->link = new PersonRec();
p = p->link;
}
cout << "Enter the person's name: ";
cin.getline (p->aName, 20);
cout << "Enter the person's contribution: ";
cin >> p->aBribe;
p->link = NULL;
}
#include <iostream>
using namespace std;
struct Node
{
int item; // storage for the node's item
Node* next; // pointer to the next node
};
/**************
use reference
**************/
void addNode(Node*& head, int data , int& count)
{
Node * q; // new node
q = new Node; // allocate memory for the new mode
q->item = data; // inserting data for the new node
q->next = head; // point to previous node ?? how would i do that? ( am i doing it correctly?)
count++; // keep track of number of node
head = q;
}
int main()
{
int a, count = 0;
int data;
char callen;
Node *head = NULL;
do
{
cout << "please enter the data for the next node" << endl;
cin >> data;
addNode(head, data, count);
cout << "do you wish to enter another node? (enter true or false)" << endl;
cin >> callen;
}while( callen != 'n' );
// assuming this is the print function
while(head != NULL)
{
cout << "output" << head->item << endl;
head = head->next; //next element
}
system("pause");
return 0;
}
I tried adding a new element in the list how would i move the head around like a LIFO memory (stack) so the last element is on the very top..
Any help would be appreciated ! The pointers and the nodes are messing with my brain lately ....
In the do-while loop try this
addNode(data, count, head);
instead of
addNode( data, count );
Also, change the signature of addNode as follows:
void addNode( int data , int& count , Node*& head)
The code shouldn't compile because you are using the variable head in addNode but head is local to main.
You could use std::stack for LIFO.
int main()
{
int a, count=0;
int data;
bool repeat;
stl::stack<int> lifo;
// assuming it is an empty list at the beginning and crating a new node below
cout << "enter some data" << endl;
cin >> a ;
lifo.push(a);
do
{
cout << "please enter the data for the next node" <<endl;
cin >> data;
lifo.push(data);
cout << "do you wish to enter another node? (enter true or false)" << endl;
cin >> repeat;
}
while (repeat == true);
// assuming this is the print function
while(!lifo.empty()) {
cout << lifo.pop() << endl;
}
system("pause");
return 0;
}
Sounds like you're trying to learn a bit about link lists. Awesome!
Anyway, I'm not going to give you the exact answer, but I'll give you some pointers in pseudo code, in particular for your addNode member function:
Node* addNode(Node* head, int data, int& count)
{
create a new node
let it point to head
return the pointer to the new node for it to become the new head node
}
int main()
{
// code...
head = addNode(head, data, count);
// more code...
}
As a visual:
head
\/
node A->node B->node C
new node->?
new node
\/
node A->node B->node C
The way you're doing it, by implementing your addNode function as a push operation, already moves the head around, so the head will always point to the last element you added.
Therefore, to implement a function to delete the last element added, you just need to write a simple pop operation: copy the address of the head, make the second element the new head, and release the memory at the copied address:
Node* oldHead = head;
head = head->next;
delete oldHead;
return head;
You could try the following modified code.
#include <iostream>
using namespace std;
struct Node
{
int item; // storage for the node's item
Node* next; // pointer to the next node
};
/**************
use reference
**************/
void addNode(Node*& head, int data , int& count)
{
Node * q; // new node
q = new Node; // allocate memory for the new mode
q->item = data; // inserting data for the new node
q->next = head; // point to previous node ?? how would i do that? ( am i doing it correctly?)
count++; // keep track of number of node
head = q;
}
int main()
{
int a, count = 0;
int data;
bool repeat;
Node *head = NULL;
// assuming it is an empty list at the beginning and crating a new node below
Node *temp;
temp = new Node ;
cout << "enter some data" << endl;
cin >> a ;
temp->item = a;
temp->next = head;
head = temp;
//^^ assuming thats creating the first node ^^
do
{
cout << "please enter the data for the next node" << endl;
cin >> data;
addNode(head, data, count);
cout << "do you wish to enter another node? (enter true or false)" << endl;
cin >> repeat;
}
while (repeat == true);
// assuming this is the print function
temp = head;
while(temp != NULL)
{
cout << "output" << temp->item << endl;
temp = temp->next; //next element
}
return 0;
}