I have a problem either adding to or traversing a linked list. The main item class is used by another class but I can add the correct number of these but it looks like when I add more data to the list the app no longer works.
I am not sure exactly where the error is. I know that when I try to traverse the list the application crashes. Any ideas or any improvements would be appreciated.
I can make the crash not happen by changing the AddOccurence method to not do the while loop.
Do
void Item::AddOccurence(int Item,int placeInLine){
ItemOccurence* ocr=myHead;
if(ocr)
{
}
instead of
void Item::AddOccurence(int Item,int placeInLine){
ItemOccurence* ocr=myHead;
while(ocr)
{
}
Basically hitting the first node but no more.
I have an object that contains a list.
Here is the .h file
#include
using namespace std;
class ItemOccurence{
public:
ItemOccurence(int line,int placeInLine,ItemOccurence* link=NULL) :myLine(line),myPlaceInLine(placeInLine),myLink(link){}
int myLine;
int myPlaceInLine;
ItemOccurence* myLink;
};
class Item {
public:
Item();
Item(string Item,int line,int placeInLine);
virtual ~Item();
void deallocate(ItemOccurence* p);
void AddOccurence(int Item,int placeInLine);
string myItem;
ItemOccurence* myHead;
private:
bool isEmpty();
};
And the .cpp file
#include "Item.h"
#include <string>
#include<iostream>
using namespace std;
Item::Item(string Item,int line,int placeInLine):myHead(NULL){
myItem=Item;
myHead= new ItemOccurence(line,placeInLine,NULL);
}
Item::Item():myHead(NULL){
myHead=0;
}
Item::~Item() {
deallocate(myHead);
myHead=0;
}
void Item::deallocate(ItemOccurence* p){
ItemOccurence* tmp;
while(p){
tmp=p;
p=p->myLink;
delete tmp;
}
}
void Item::AddOccurence(int Item,int placeInLine){
ItemOccurence* ocr=myHead;
while(ocr)
{
cout<<"orrucence head while adding " << myHead->myLine << " " << myHead->myPlaceInLine <<"\n";
ocr=ocr->myLink;
}
myHead = new ItemOccurence(Item,placeInLine,myHead);
return;
}
bool Item::isEmpty(){
if(myHead)
return false;
else
return true;
}
EDIT:
I updated AddOccurence to be.
void Item::AddOccurence(int line,int placeInLine){
ItemOccurence* prev = myHead;
ItemOccurence* curr = myHead->myLink;
while(curr){
prev=curr;
curr=curr->myLink;
}
// insert new ItemOccurence
cout<<"adding " <<line<< " and " << placeInLine <<"\n";
prev->myLink = new ItemOccurence(line,placeInLine);
return;
}
But I am still crashing. I am trying to debug but not sure what to look for.
It's very hard to tell what your code is trying to do. Unfortunately, the hard truth is, it's pretty far away from "working".
Here's a few hints:
Reconsider your classes. What is Item and ItemOccurrence? A linked list is a list. It has items. You should probably name it List and Item. If you want, you can do this in a single class representing Item (the List is only a special case of the front Item).
Each Item needs a string (the node data) and a next (the pointer to the next node).
If you use List, it will need to have a pointer to head (the first Item).
You don't need to store placeInLine. placeInLine should only be used when searching for the place to insert a new Item.
It's unclear what ItemOccurrence::myLine is supposed to represent.
When you initialize myHead(NULL), you don't need to set it to 0.
isEmpty() is not usually a private method.
The algorithm for adding a node is:
Loop until you find the place before it needs to be inserted.
It looks like you need to check for two things: "end of list" and "placeInLine"
Set new_node->next = current->next->next node.
Set current->next = new_node node.
Be aware of the special case where current->next is NULL.
Instead of if (x) return true; else return false;, it's common to return x;
There are several issues with the code, but most notably your addOccurrence method does not set the myLink pointer for myHead after it creates it. I think that's what you are trying to do in the loop above it, but in actuality that code only seems to loop through the existing list and print it out. You probably intend to loop through that placeInLine times and then update your myLink pointers at that level. It's not clear what the difference is between item and placeInLine or why you would need both. You definitely don't want to use class names (like Item) as integer variables. That adds to the confusion.
Related
I'm trying to create a linked list that has 2 data types and a function that inserts nodes. But in order to insert nodes, I have to create at least 1 empty node first.
linked list struct
struct receipt{
string name;
double price;
receipt* link;
};
function that inserts a node at the end of the list
void insert(receipt** head_name_ref, string new_name, double new_price)
{
receipt* new_name_node = new receipt();
receipt *last = *head_name_ref;
new_name_node->name = new_name;
new_name_node->price = new_price;
new_name_node->link = NULL;
if (*head_name_ref == NULL)
{
*head_name_ref = new_name_node;
return;
}
while (last->link != NULL)
{
last = last->link;
}
last->link = new_name_node;
return;
}
function that print the list
void printList(receipt* n){
while(n!=NULL){
cout<<"Name: "<<n->name<<'\t'<<" ";
cout<<"Price: "<<n->price<<'\t'<<" ";
cout<<endl;
n=n->link;
}
}
main function
int main(){
receipt* head = NULL;
head = new receipt;
insert(&head, "item", 23);
printList(head);
return 0;
}
here is a picture of the output https://i.stack.imgur.com/6Ss02.png
Consider that in a more complex program you would have much more than simply a main function. When creating a data structure you have to store a pointer or reference to an object in some way that other functions can receive or access the pointer. For something this simple a global variable or instance of a struct containing the attributes of the list would suffice. Simply initialize the head to 0 and create the functions needed to manage that global object. Upon the first instantiation of the node, simply assign the head to that pointer.
You've already created a struct that represents a node. Now create another one that represents the list which contains nodes. Within that struct you'd want attributes such as a head that pointers to the first node object or null if it is empty. You can give it a default constructor.
Since this looks like an assignment I'm only giving you some hints and not a complete example, purposefully.
struct SinglyLinkList {
receipt* head;
SinglyLinkList() : head(0) {}
~SinglyLinkList() { // code to iterate and destroy all node objects }
// now define copy constructor and assignment operators if you want or delete those
// possibly some methods to add, remove, print nodes
void print();
add(receipt* r); // could overload to insert at a position
remove(size_t n); // remove nth receipt or overload to remove by some other factor
void removeAll();
receipt
};
// somewhere above the main function you could just instantiate a global list
// Within the main function you may call methods that operate on the
// list and call its methods, or define other global functions if you
// prefer that the list be defined only with the attributes
SinglyLinkList list; // default constructed with head = 0 or head = nullptr if you prefer
First note that when struct receipt is constructed, price and link will be uninitialized (std::string name will be default constructed to an empty string, but double and pointers do not have such a default initialization). This problem will manifest with this line in main:
head = new receipt;
(the problem does not manifest when you create new_name_node because you manually initialized it after the allocation).
Therefore you should better handle struct receipt initialization. The minimum would be something like this:
struct receipt {
std::string name;
double price{ 0 };
receipt* link{ nullptr };
};
You can consider to add a custom constructor.
Now to answer you question:
The question title is how to avoid printing the first node.
To do this you just have to skip one node before starting the loop.
Add the following at the beginning of printList:
if (n != nullptr)
{
n = n->link;
}
However, "solving" the problem like this is not a good idea.
Having a "dummy" first node in a linked list is not the ideal design.
I suggest you redesign your code to avoid it. You can search the web for typical linked list implementations to get some ideas. Then the issue of printing (while skipping a node) will not arise at all.
On a side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
I am learning data structures in C++. This is a simple program for insertion
using links and nodes. The insertion takes place at the beginning of the node.
I do not understand some parts of the code.
In the function display() the pointer np points to the inserted info and then takes the value of the previous info using the next node. The next pointer is pointing to the previous info using the insert_beginning() function.
Displaying is done using the while loop. How does the next pointer change its value during each loop?
PS: The program runs fine.
#include<iostream>
#include<process.h>
#include<cstdlib>
using namespace std;
struct node
{
int info;
node *next;
}*start,*newptr,*save,*ptr;
node *create_new_node(int);
void insert_beg(node*);
void display(node*);
/*----------------------------------------------------------------------------------------------------------------------------
The pointer 'start' points to the beginning of the list.
Function 'create_new_node()' takes one integer argument , allocates memory to create new node and returns
the pointer to the new node.(return type: node*)
Function 'insert_beg()' takes node* type pointer as an argument and inserts this node in the beginning of the list.
Function display takes node* type pointer as an argument and displays the list from this pointer till the end of the list
------------------------------------------------------------------------------------------------------------------------------
*/
int main()
{
start=NULL;
int inf;
char ch='y';
while(ch=='y'||ch=='Y')
{
system("cls");
cout<<"enter information for the new node ";
cin>>inf;
cout<<"\ncreating new node. Press enter to continue ";
system("pause");
newptr = create_new_node(inf);
if(newptr!=NULL)
{
cout<<"\nnew node created successfully. Press enter to
continue. ";
system("pause");
}
else
{
cout<<"\nCannot create new node. ABORTING!! ";
exit(1);
}
cout<<"\nnow inserting this node in the beginning of the list.
Press enter to continue ";
system("pause");
insert_beg(newptr);
cout<<"\nNow the list is \n";
display(start);
cout<<"\nPress 'Y' to enter more nodes, 'N' to exit\n";
cin>>ch;
}
return 0;
}
node *create_new_node(int n)
{
ptr=new node;
ptr->info=n;
ptr->next=NULL;
}
void insert_beg(node *np)
{
if(start==NULL)
start=np;
else
{
save=start;
start=np;
np->next=save;
}
}
void display(node *np)
{
while(np!=NULL)
{
cout<<np->info<<" ->";
np=np->next;
}
cout<<"!!!\n";
}
To cut the long story short - per my understanding, your basic question is:-
display is done using the while loop. how does the next pointer change
its value during each loop??
This happens precisely in this line:-
np=np->next;
You are basically advancing the pointer to the node structure to another node structure whose address is in next member of the first node structure. This is text book stuff and any basic algo book should cover this thoroughly
HTH!
Your question is somewhat unclear. Especially because you state that:
PS:the program runs fine.
which it for sure does not. There is a bug that simply means this program will not work.
The problem is that create_new_node is not returning the pointer value
node *create_new_node(int n)
{
ptr=new node;
ptr->info=n;
ptr->next=NULL;
return ptr; // This line is missing
}
Besides that it is a really bad idea to use global pointer variables!
Here
struct node
{
int info;
node *next;
}*start,*newptr,*save,*ptr;
you define the struct node but you also define 4 variables, i.e. 4 pointers to node. These variables will be global, i.e. available in all your code. Something that you should never do.
Instead make local variables as needed - for instance:
node *create_new_node(int n)
{
node *ptr; // Local variable instead of global
ptr=new node;
ptr->info=n;
ptr->next=NULL;
return ptr;
}
Then for the insert_beg change it so that it returns a new start pointer - like:
node* insert_beg(node* start, node *np)
{
np->next=start;
return np;
}
and use it in main like:
node* start = NULL;
...
...
start = insert_beg(start, newptr);
BTW - In modern C++ you would never use raw pointers and you would never write your own list. Use smart pointers instead of raw pointer. Use the standard containers instead of writing your own.
This realization of linked list is broken. Address of nodes[0].next doesn't match the nodes[1] address. So nodes[1].next is NULL (as default value). I added some address printing to the search method. It looks like the nodes[1] wasn't initialized?
#include <iostream>
#include <vector>
using namespace std;
typedef struct Node_T {
int data;
Node_T *next;
} Node;
class LinkedList{
public:
vector<Node> nodes;
LinkedList(){
}
void insert(int data) {
Node temp_node;
temp_node.data = data;
temp_node.next = NULL;
size_t len = nodes.size();
nodes.push_back(temp_node);
if (len > 0) {
nodes[len - 1].next = &nodes[len];
}
}
int search(int val){
if (nodes.empty())
return -1;
Node *node_ptr = &nodes[0];
// Debug
cout << &nodes[1] << "\n";
cout << &nodes[0].next << "\n";
int i = 0;
do {
if (node_ptr->data == val) return i;
i++;
} while((node_ptr = node_ptr->next) != NULL);
return -1;
}
};
int main()
{
LinkedList llist;
llist.insert(1);
llist.insert(2);
llist.insert(3);
llist.insert(4);
llist.insert(5);
cout << llist.search(3) << "\n";
return 0;
}
It shows me: 0x8e6a060 0x8e6a05c -1
When you add elements to a vector, references to (and hence addresses of) vector elements are invalidated. You must therefore not use values such as &nodes[0] or &nodes[len], as they are meaningless.
The point with an exercise like this is to get the hang of the internal structure in a linked list. You have replaced that internal structure with a vector<Node>.
Instead of a vector, the idea is to have a
private:
Node* head;
As you data member.
In your insert function you are supposed to dynamically allocate memory for the Node with
Node* newNodePointer = new Node;
And manipulate the pointer with next and such.
It is worth to point out, that this is fine as an exercise, but your "real" code should use standard library facilities.
First, Your printout is incorrect: this line
cout << &nodes[0].next << "\n";
prints the address of next, rather than printing the next itself. Changing to
cout << nodes[0].next << "\n";
gives the correct printout (demo).
However, the main issue is that you keep pointers to elements of std::vector. These become invalid after the first write, because new storage gets allocated for the growing vector.
You can certainly work around this by reserving sufficient space upfront (call nodes.reserve(1000) from the constructor of your list; demo) but that is merely a hack: you should use new and delete to allocate elements of your linked list manually. That is the whole point of this exercise.
But I still need a container to ensure that nodes will be live as expected?
No, you do not. Your class is a container. By referencing the whole chain of nodes from the head pointer it can ensure that the entire chain is kept "live".
I am in process of learning c++. I am working on creating a linkedlist data structure. One of the functions that displays the values of nodes in the structure does not work. For some reason the while loop that traverses through nodes doesn't work in the display function, hence I can't see the values in those nodes. Does anyone see what the problem is? I've been staring at the code for a while and not sure what is wrong here.
Thanks for your help in advance.
Header:
// linklist.h
// class definitions
#ifndef LINKLIST_H
#define LINKLIST_H
class linklist
{
private:
// structure containing a data part and link part
struct node
{
int data;
node *link;
}*p;
public:
linklist();
void append(int num);
void addatbeg(int num);
void addafter(int loc, int num);
void display();
int count();
void del(int num);
~linklist();
};
#endif
.cpp file
// LinkedListLecture.cpp
// Class LinkedList implementation
#include"linklist.h"
#include<iostream>
using namespace std;
// initializes data member
linklist::linklist()
{
p =NULL;
}
// adds a node at the end of a linked list
void linklist::append(int num)
{
node *temp, *r;
// if the list is empty, create first node
if(p==NULL)
{
temp = new node;
temp->data = num;
temp->link = NULL;
}
else
{
// go to last node
temp = p;
while(temp->link!=NULL)
temp = temp->link;
// add node at the end
r = new node;
r->data=num;
r->link=NULL;
temp->link=r;
}
}
// displays the contents of the linked list
void linklist::display()
{
node *temp = p;
cout<< endl;
// traverse the entire linked list
while(temp!=NULL) // DEBUG: the loop doesn't work
{
cout<<temp->data<<" ";
temp = temp->link;
}
void main()
{
linklist l;
l.append(14);
l.append(30);
l.append(25);
l.append(42);
l.append(17);
cout<<"Elements in the linked list:";
l.display(); // this function doesn't work
system("PAUSE");
}
You never set p to a non NULL value.
if(p==NULL)
{
p = new node;
p->data = num;
p->link = NULL;
}
I think GWW has highlighted the issue, but part of learning to program it to learn how to identify the mistakes.
If you do something and don't get the expected result you could:
Use the visual c++ debugger to step through and see the values of your variables.
Put in log lines to report information you think is important
inspect the code - if you think something is right but it doesn't work, then go to an earlier step and check it does the right thing.
Add unit tests, or follow design by contract adding pre/post conditions and class invariants.
Learning to program C++ by writing a linked list is like learning math by adding 1 + 1. It is old fashioned thinking, slow and mostly boring without having any context.
Math isn't calculating, like C++ programming isn't pointer manipulation. At some stage you might need to know about it, but your better off learning other important things like stl and boost.
If it was understood that append() ment create something, find the end of the list, add it. you could then see that in you append function you have create something mixed uyp with move to the end of the list, but you never add it.
DEAR All;
Hi, I'm just beginner to C++;
Please help me to understand:
What functions should be in the Linked list class ?
I think there should be overloaded operators << and >>;
Please help me to improve the code (style, errors, etc,)
Thanks for advance. Igal.
Edit:
This is only first stage, the next one will be (hopefully) with templates.
Please review the small code for the integer List (enclosed MyNODE.h and ListDriver1.cpp);
MyNODE.h
// This is my first attempt to write linked list. Igal Spector, June 2010.
#include <iostream.h>
#include <assert.h>
//Forward Declaration of the classes:
class ListNode;
class TheLinkedlist;
// Definition of the node (WITH IMPLEMENTATION !!!, without test drive):
class ListNode{
friend class TheLinkedlist;
public:
// constructor:
ListNode(const int& value, ListNode *next= 0);
// note: no destructor, as this handled by TheLinkedList class.
// accessor: return data in the node.
// int Show() const {return theData;}
private:
int theData; //the Data
ListNode* theNext; //points to the next node in the list.
};
//Implementations:
//constructor:
inline ListNode::ListNode(const int &value,ListNode *next)
:theData(value),theNext(next){}
//end of ListNode class, now for the LL class:
class TheLinkedlist
{
public:
//constructors:
TheLinkedlist();
virtual ~TheLinkedlist();
// Accessors:
void InsertAtFront(const &);
void AppendAtBack(const &);
// void InOrderInsert(const &);
bool IsEmpty()const;//predicate function
void Print() const;
private:
ListNode * Head; //pointer to first node
ListNode * Tail; //pointer to last node.
};
//Implementation:
//Default constructor
inline TheLinkedlist::TheLinkedlist():Head(0),Tail(0) {}
//Destructor
inline TheLinkedlist::~TheLinkedlist(){
if(!IsEmpty()){ //list is not empty
cout<<"\n\tDestroying Nodes"<<endl;
ListNode *currentPointer=Head, *tempPtr;
while(currentPointer != 0){ //Delete remaining Nodes.
tempPtr=currentPointer;
cout<<"The node: "<<tempPtr->theData <<" is Destroyed."<<endl<<endl;
currentPointer=currentPointer->theNext;
delete tempPtr;
}
Head=Tail = 0; //don't forget this, as it may be checked one day.
}
}
//Insert the Node to the beginning of the list:
void TheLinkedlist::InsertAtFront(const int& value){
ListNode *newPtr = new ListNode(value,Head);
assert(newPtr!=0);
if(IsEmpty()) //list is empty
Head = Tail = newPtr;
else { //list is NOT empty
newPtr->theNext = Head;
Head = newPtr;
}
}
//Insert the Node to the beginning of the list:
void TheLinkedlist::AppendAtBack(const int& value){
ListNode *newPtr = new ListNode(value, NULL);
assert(newPtr!=0);
if(IsEmpty()) //list is empty
Head = Tail = newPtr;
else { //list is NOT empty
Tail->theNext = newPtr;
Tail = newPtr;
}
}
//is the list empty?
inline bool TheLinkedlist::IsEmpty() const
{ return (Head == 0); }
// Display the contents of the list
void TheLinkedlist::Print()const{
if ( IsEmpty() ){
cout << "\n\t The list is empty!!"<<endl;
return;
}
ListNode *tempPTR = Head;
cout<<"\n\t The List is: ";
while ( tempPTR != 0 ){
cout<< tempPTR->theData <<" ";
tempPTR = tempPTR->theNext;
}
cout<<endl<<endl;
}
//////////////////////////////////////
The test Driver:
//Driver test for integer Linked List.
#include <iostream.h>
#include "MyNODE.h"
// main Driver
int main(){
cout<< "\n\t This is the test for integer LinkedList."<<endl;
const int arraySize=11,
ARRAY[arraySize]={44,77,88,99,11,2,22,204,50,58,12};
cout << "\n\tThe array is: "; //print the numbers.
for (int i=0;i<arraySize; i++)
cout<<ARRAY[i]<<", ";
TheLinkedlist list; //declare the list
for(int index=0;index<arraySize;index++)
list.AppendAtBack( ARRAY[index] );//create the list
cout<<endl<<endl;
list.Print(); //print the list
return 0; //end of the program.
}
What functions should be in the Linked list class ?
That depends on what you need to do with it. At the very least, one should probably be able to add elements to it, and to look at the elements in the list.
(This is common sense. Because if you can't modify or read your list in any way, what could it ever be used for?)
I think there should be overloaded operators << and >>;
Why? What would they do? I suppose you mean operator << to do insertion, similar to how objects are inserted into C++ IO streams; but what exactly should operator >> do? Extraction/removal of elements of some sort? If you implement insertion and extraction (?) in this manner, probably noone will be able to understand your linked list class. A linked list is not an IO stream. (Those operators with IO streams were chosen for brevity.)
I would advise you against operator overloading if the meaning of the operation is not clear. I would suggest you name your operations more explicitly, e.g. by providing methods add and remove (I'm still guessing at the meaning of the latter operation >> btw.).
Please help me to improve the code (style, errors, etc,)
I don't want to make this the main point on my answer, so just very briefly off the top of my head, some issues:
You should #include <iostream> instead of #include <iostream.h>, and then either add a using namespace std; or write (e.g.) std::cout instead of cout.
Try to get rid of the friend. You should be able to design your classes in a way that doesn't require this. friend is easily misused to get around proper encapsulation. But encapsulation is something you should definitely think about in OOP.
Though that's not an advice to give to a C++ beginner, if you made your linked list class into a template class, it could store different values than just ints. Just take this as a hint for future improvements.
And finally:
Just use the STL ("Standard Template Library") containers which are included in the C++ standard library. I know that "rolling your own" helps understanding how these data structures work, but be aware that the C++ standard library already includes a solid and efficient set of data containers.
0 should be NULL
inline only in the case that you don't care that your code will be public, usually implementation puts in separate file Mylist.cpp file.
Why your destructor virtual, do you have inheritance ?
You can just define struct node instead separate class its better define your list for practice like in stl. http://www.sgi.com/tech/stl/List.html http://www.cplusplus.com/reference/stl/list/
In C++ common to use vector vs linked list in Java
http://www.yolinux.com/TUTORIALS/LinuxTutorialC++STL.html