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

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

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{};

How would you write a function to create a linked list?

I was wondering if it would be possible to create a function that would create a linked list, here is my attempt, I would appreciate if anyone could tell me if this is correct or not.
The logic is as follows:
Take in a starting node, the created linked list will be connected to this node
Create all the nodes that need to be created and store their memory addresses in a vector
Loop through the vector linking together all of the nodes
#include <iostream>
#include <vector>
using namespace std;
class node{
public:;
int value;
node *next;
node():value(0),next(NULL){};
};
void CreateList(node& starting_node, int number_of_nodes_to_create){
// Keep track of all the nodes addresses that need to be created
vector <node*> nodes = {};
// Create the nodes
for (int i = 0; i < number_of_nodes_to_create;i++){
node *temp = new node;
nodes.push_back(temp);
}
// Attach the first created node to the starting node
starting_node.next = nodes[0];
// We now have all the new nodes, now we just need to link them all up with pointers
for (int i = 0; i < nodes.size()-1;i++){
nodes[i] ->next = nodes[i+1];
}
}
I am very much a beginner, all criticism is welcome!
You don't need the vector at all. Your function can be simplified to something like this:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
void CreateList(node* &starting_node, int number_of_nodes_to_create){
// if the list already exists, find the end of it...
node **n = &starting_node;
while (*n) {
n = &((*n)->next);
}
// Create the nodes
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
}
void DestroyList(node *starting_node) {
while (starting_node) {
node *n = starting_node->next;
delete starting_node;
starting_node = n;
}
}
int main() {
node* head = NULL;
CreateList(head, 5);
...
DestroyList(head);
}
Online Demo
Though, it is not usual for a list creation to take an existing node as input. Usually the creation should create the list and then return the 1st (head) node, eg:
#include <iostream>
#include <vector>
using namespace std;
class node{
public:
int value;
node *next;
node() : value(0), next(NULL) {}
};
node* CreateList(int number_of_nodes_to_create){
node *head = NULL, **n = &head;
while (number_of_nodes_to_create > 0) {
*n = new node;
n = &((*n)->next);
--number_of_nodes_to_create;
}
return head;
}
void DestroyList(node *head) {
while (head) {
node *n = head->next;
delete head;
head = n;
}
}
int main() {
node* head = CreateList(5);
...
DestroyList(head);
}
Online Demo

How to fix Segmentation Fault in linked list

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

C++ Linked list using Classes (OOP)

This is my first post on StackOverflow, as I am genuinely stuck.
My issue is that everytime I run the following code, at the first call for the function InsertNode(), the return temp node has the correct values for next node and data. However, when the function is called again, for some reasons the head gets reset to data NULL and next pointer recursively pointing to the same address. I'm having a hard time implementing this in OOP, I have done this using plain structs successfully. But with OOP I'm confused as how to declare the Node* Node::InsertNode(Node* head), method in main, as I get an error that InsertNode is undeclared. So as workaround I declared InsertNode outside of the Node class as an independent function. I have a feeling that is what may be causing the issue. would appreciate some help on what is going on or what I should change in my code. Thank you!
hashtable.cpp
#include "Hashtable.hpp"
using namespace std;
Node::Node(){
data = NULL;
Node* nextP = NULL;
};
Node::~Node(){
}
Node* InsertNode(Node* head, int data){
Node* temp = new Node();
if(head->nextP == NULL){
head->data = data;
temp->nextP = head;
head = temp;
} else if(head->nextP!=NULL){
temp->nextP = head;
temp->data = data;
head = temp;
}
return head;
};
void Node::printNode(Node* head){
Node* temp = new Node();
temp = head;
while(temp->nextP != NULL){
printf("%d\n", temp->data);
temp = temp->nextP;
}
}
Hashtable.hpp
#ifndef Hashtable_hpp
#define Hashtable_hpp
#include <stdio.h>
class Node
{
public:
Node* nextP;
Node();
~Node();
void printNode(Node* head);
int data = NULL;
private:
};
Node* InsertNode(Node* head, int data);
#endif /* Hashtable_hpp */
main.cpp
#include <iostream>
#include "stdio.h"
#include <string>
#include "Hashtable.hpp"
using namespace std;
Node head;
//Node* head = new Node();
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
head = *InsertNode (&head, 10);
// head = temp2;
head = *InsertNode (&head, 20);
// head = temp2;
head = *InsertNode (&head, 30);
// head = temp2;
//InsertNode(head, 20);
Node printNode(head);
return 0;
}
So I finally figured out the issue. Since initially I was referencing the class function InsertNode() directly, I was trying avoid the error that I was other getting with the undeclared identifier. So as a work around I moved the function outside of the class declaration, which then caused more problems as you saw above post. Now I realized that when the function exists inside the Class, I have reference it by first de-referencing (my terminology is probably wrong) the function using the following: head->InsertNode(head, data);
I was initially trying different iterations of InsertNode(&head, data) or Node* InsertNode(&head, data) ... etc. Basically trying to brute force my way through the compiler :).
I am attaching the code below, please let me know your comments on what I can improve.
Hashtable.cpp
#include "Hashtable.hpp"
#include <iostream>
using namespace std;
Node::Node(){
data = NULL;
Node* nextP = NULL;
};
Node::~Node(){
}
Node* Node::InsertNode(Node* head, int data){
Node* temp = new Node();
if(head->nextP == NULL){
head->data = data;
temp->nextP = head;
} else if(head->nextP!=NULL){
temp->nextP = head;
temp->data = data;
}
return temp;
};
void Node::printNode(Node* head){
Node* temp = new Node();
temp = head;
while(temp->nextP != NULL){
printf("%d\n", temp->data);
temp = temp->nextP;
}
}
Hashtable.hpp
#ifndef Hashtable_hpp
#define Hashtable_hpp
#include <stdio.h>
#include <iostream>
using namespace std;
class Node
{
int data = NULL;
Node* nextP;
public:
Node();
~Node();
Node* InsertNode(Node* head, int data);
void printNode(Node* head);
private:
};
#endif /* Hashtable_hpp */
main.cpp
#include <iostream>
#include "stdio.h"
#include <string>
#include "Hashtable.hpp"
using namespace std;
Node* head = new Node();
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
Node temp2;
head = head->InsertNode (head, 10);
head = head->InsertNode (head, 20);
head = head->InsertNode (head, 30);
head = head->InsertNode (head, 40);
head = head->InsertNode (head, 50);
head = head->InsertNode (head, 60);
head = head->InsertNode (head, 70);
head->printNode(head);
return 0;

I am getting the error "invalid null pointer"

I want to read in student names from a file and insert them into my linked-list, but I am having this problem with an error box. The error reads "Expression: Invalid Null Pointer."
I've googled with no such luck. I think I have an idea where I've went wrong, but I don't know how to fix it.
If you could help, that would be great!
Here is my code:
P.S I'm not nearly done so my code might be incomplete, I'm just trying to weed out all my errors now so I don't have triple my errors at the end.
LList.h
#include <iostream>
#include <iomanip>
#include <string>
#ifndef LLIST_H
#define LLIST_H
typedef int ElementType;
class LList
{
public:
LList();
~LList();
void insert(std::string new_data);
void display();
void remove(std::string delete_data);
private:
class Node
{
public:
std::string data;
Node *next;
Node(std::string data_value = NULL);
};
Node *head;
int mySize;
};
#endif LLIST_H
LList.cpp
#include <iomanip>
#include <iostream>
#include <string>
#include "LList.h"
using namespace std;
LList::Node::Node (string data_value)
{
this -> data = data_value;
this -> next = NULL;
}
LList::LList()
{
this -> head = new Node(0);
mySize = 0;
string data = "";
}
LList::~LList()
{
delete this -> head;
}
void LList::insert(string new_data)
{
Node *tempHolder;
tempHolder = this->head;
while (tempHolder->next != NULL)
tempHolder = tempHolder -> next;
Node *newNode = new Node(new_data);
tempHolder ->next = newNode;
this->mySize++;
}
void LList::display()
{
Node *temp;
temp = head->next;
while(temp -> next != NULL)
{
cout << temp -> data << endl;
temp = temp -> next ;
}
}
void LList::remove(string delete_data)
{
Node *tempHolder;
tempHolder = head;
while (tempHolder->next != NULL )
{
if (tempHolder->next->data == delete_data)
{
Node *delete_ptr = tempHolder->next;
tempHolder->next = tempHolder->next->next;
delete delete_ptr;
mySize-- ;
break;
} else
tempHolder = tempHolder->next;
}
}
Main.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include "LList.h"
#include <fstream>
using namespace std;
int main()
{
LList student;
ifstream infile;
char readLine[500];
infile.open ("names.txt");
if(infile.is_open())
{
while (!infile.eof())
{
infile.getline(readLine,sizeof(readLine)); // read a line from file
student.insert(readLine);
}
}
else
{
cout << "Can't open file!" << endl;
}
}
I found my problem.
In:
LList::LList()
{
this -> head = new Node(0);
mySize = 0;
string data = "";
}
Node(0);
is calling my
LList::Node::Node (string data_value)
{
this -> data = data_value;
this -> next = NULL;
}
which is initialized as a string.
I changed
Node(0);
to
Node("");
and it worked flawlessly.
I wonder could you give the reference where you read that you may to write?
Node(std::string data_value = NULL);
Class std::string has no constructor that converts NULL to an object of type std::string.
it would be much better to declare the constructor without a default argument
Node( std::string data_value );
There is no any sense to create a node without data.
In fact there is no any need to declare a constructor of Node. It could be used as an aggregate.
Also change the constructor of LList as
LList::LList() : head( 0 ), mySize( 0 ){}
Also the destructor is invalied
LList::~LList()
{
delete this -> head;
}
You have to delete not only head but all nodes in the LList.
Also nodes in a single linked list are inserted in the beginning of the list that is before the head.
I would write method insert the following way provided that the constructor of Node is removed bacause it is not needed.
void LList::insert( const std::string &new_data )
{
head = new Node { new_data, head };
}
If your compiler does not support the initializer list then you indeed need to define constructor in class Node.
Node( const std::string &data_value, next_node = NULL );
In this case method insert will look as
void LList::insert( const std::string &new_data )
{
head = new Node( new_data, head );
}