Recordlabel.cpp
void recordLabel::addArtist(char* artistName)
{
Node* temp = new Node;
temp->artistName = artistName;
temp->next = head;
head = temp;
}
void recordLabel::displayArtists()
{
Node* tmp = head;
tmp = tmp->next;
while (tmp != NULL)
{
cout << tmp->artistName << " ";
tmp = tmp->next;
}
}
Main.cpp
int main()
{
recordLabel recordLabel;
char* artistName = new char[25];
char repeatLoop = 'y';
while (repeatLoop == 'y' || repeatLoop == 'Y')
{
cout << "Please Enter an Artist Name: ";
cin.getline(artistName,25);
recordLabel.addArtist(artistName);
cout << "Do you want to add a Name? (y/n): ";
cin >> repeatLoop;
cin.ignore();
}
recordLabel.displayArtists();
//delete[] artistName;
system("pause");
return 0;
}
So I'm trying to display my linked list but when I enter input like "john" "kyle" "david" the output from the display function justs ends up being david david david. Can someone help me with this? Also, I realize using string would solve most of my problems but I'm trying to just use Chars.
Thanks
Modify the method addArtist in this way:
void recordLabel::addArtist(char* artistName)
{
Node* temp = new Node;
temp->artistName = strdup(artistName);
temp->next = head;
head = temp;
}
You need to include also string.h
#include <cstring>
Do not forget to clean the memory with the destructor
All nodes of the list contain in their data members artistName the address of the allocated memory stored in the pointer artistName declared in main.
char* artistName = new char[25];
//...
recordLabel.addArtist(artistName);
and
void recordLabel::addArtist(char* artistName)
{
Node* temp = new Node;
temp->artistName = artistName;
//...
That is all the data members store the address of the same allocated memory.
As a result all the data members will point to the last string stored in this dynamically allocated memory.
You need to crate a copy of the stored string in the current moment.
For example
#include <cstring>
//...
void recordLabel::addArtist( const char *artistName )
{
Node* temp = new Node;
temp->artistName = new char[strlen( artistName ) + 1];
strcpy( temp->artistName, artistName );
temp->next = head;
head = temp;
}
When you should free all the allocated memory for strings and nodes in the destructor of the list.
Also it is unclear why the output of the list starts from the second node
void recordLabel::displayArtists()
{
Node* tmp = head;
tmp = tmp->next;
while (tmp != NULL)
//...
If initially the pointer head is equal to nullptr then the function can invoke undefined behavior when will be called for an empty list.
You could make your life easier if the data member artistName had the type std::string instead of char *.
For example if the class Node is defined something like
struct Node
{
std::string artistName;
Node *next;
}
then the member function addArtist could look very simply.
#include <string>
//...
void recordLabel::addArtist( const char *artistName )
{
head = new Node { artistName, head };
}
Related
I have to dynamically allocate a list of robots for a school project. In an actual program, there will be other member functions that will require the list of names in order to perform certain functions.
As of right now, I just learned about this concept, and have tried really hard to put together some things I have seen online. The issue at the moment is that I can not tell if my list is properly being stored -- I am also getting wonky output when I try to call my display of list function.
Please help if you can. Also, I am happy to hear any tips for literally anything, as I am fairly new to programming.
class Node{
public:
std::string name_;
Node* next;
};
class linkedBotList{
public:
linkedBotList() {head = nullptr;} //constructor
~linkedBotList(){}; // destructure
void addNode();
void display();
private:
Node* head;
};
int main(int argc, const char * argv[]) {
linkedBotList* list = new linkedBotList();
int siz;
std::cout << "How many Robots?" << std::endl;
std::cout << "What are the names?" << std::endl;
std::cin >> siz;
for(int i = 0; i < siz; i++){
list->addNode();
}
delete list;
return 0;
}
void linkedBotList::addNode(){
std::string botName;
Node* newNode = new Node();
newNode->name_ = botName;
newNode->next = nullptr;
std::cin >> botName;
if(head == nullptr){
head = newNode;
}
else {
Node* temp = head; // head is not null
while(temp->next != nullptr){ // go until at the end of the list
temp = temp->next;
}
temp->next = new Node; // linking to new node
}
}
void linkedBotList::display() {
if (head == NULL) {
std::cout << "List is empty!" << std::endl;
}
else {
Node* temp = head;
while (temp != NULL) {
std::cout << "Made it to display funct.\n";
std::cout << temp->name_ << " ";
temp = temp->next;
}
std::cout << std::endl;
}
}
I did try a few things, like switching around my temp variable, and a few other re-assignments. Maybe someone can quickly spot the issue and help?
Your display function is fine.
The problem is that you have 2 logic flaws in addNode():
you are not storing strings in your list correctly. You are assigning botName to newNode->name_ before botName has been assigned a value. So all of your nodes have empty strings. Assigning botName afterwards will not update newNode->name_. 1
if the list is not empty, you iterate to the end of the list correctly 2, but then you assign a new blank node to temp->next instead of assigning your newNode that you already populated. And your Node constructor is not initializing the next member to nullptr, so you are creating a corrupted list, which will cause subsequent loops through the list to invoke undefined behavior.
Try this instead:
void linkedBotList::addNode(){
std::string botName;
std::cin >> botName; // <-- move up here
Node* newNode = new Node{botName, nullptr};
if (!head){
head = newNode;
}
else {
Node* temp = head;
while (temp->next){
temp = temp->next;
}
temp->next = newNode; // <-- linking to new node
}
}
Alternatively, you can eliminate the if like this:
void linkedBotList::addNode(){
std::string botName;
std::cin >> botName;
Node** temp = &head;
while (*temp){
temp = &((*temp)->next);
}
*temp = new Node{botName, nullptr};
}
1: A better design would be to have addNode() take in a string as an input parameter, and then move the cin call into your loop in main().
2: consider adding a tail member to your list to avoid having to loop on each addition.
Try this alternate design:
class Node{
public:
std::string name;
Node* next = nullptr;
};
class linkedBotList{
public:
linkedBotList() = default;
~linkedBotList();
void addNode(std::string name);
void display() const;
private:
Node* head = nullptr;
Node* tail = nullptr;
};
int main() {
linkedBotList list;
int siz;
std::string botName;
std::cout << "How many Robots?" << std::endl;
std::cin >> siz;
std::cout << "What are the names?" << std::endl;
for(int i = 0; i < siz; i++){
std::cin >> botName;
list.addNode(botName);
}
list.display();
return 0;
}
linkedBotList::~linkedBotList(){
Node *temp = head, *next;
while (temp) {
next = temp->next;
delete temp;
temp = next;
}
}
void linkedBotList::addNode(std::string name){
Node* newNode = new Node{name};
if (tail)
tail->next = newNode;
else
head = newNode;
tail = newNode;
}
void linkedBotList::display() const {
if (!head) {
std::cout << "List is empty!" << std::endl;
}
else {
Node* temp = head;
do {
std::cout << temp->name << " ";
temp = temp->next;
}
while (temp);
std::cout << std::endl;
}
}
Hi i am frankly new to these forums so i tried looking up as much as i could but i couldn't find anything relate-able to my problem.
I am trying to read nodes that i stored into a file and insert them into a linked list that i created
THE insert functions works perfectly fine however while loading it when i attempt to insert the node ,
1.it inserts the node
2.reads the new node
3.since im using a pointer , the pointer now points to the new read node
4.inserts the newly read node from the file into the list overwriting the old data.
This causes my old data to be completely lost and the new node to act as the header of the file
load function :
void load_file_students(linked_student &students)
{
node_student *test = new node_student;
ifstream stu_list("students.dat",ios::binary);
stu_list.read((char*)test, sizeof(*test));
while (!stu_list.eof())
{
//students.insert_node_list(test);
students.insert_node_list(test);
stu_list.read((char*)test, sizeof(*test));
}
stu_list.close();
}
the insert_node function:
void linked_student::insert_node_list(node_student *student)
{
node_student* temp = new node_student;
temp = student;
if (head == NULL)
{
head = temp;
}
else
{
node_student *ptr = this->head;
while (ptr->next != 0)
{
ptr = ptr->next;
}
temp->previous = ptr;
ptr->next= temp;
}
}
the node :
#pragma once
#include <string>
using namespace std;
static int roll_number = 1; // used for the personal identification of the student
class node_student
{
public:
bool fees_paid = true;
string name;
float CGPA;
int ID; // same as the static roll_number provided
int semester;
string department;
string elective_subjects[5];
node_student *next;
node_student *previous;
node_student();
~node_student();
};
during debugging mode it is evident that when i re-read the data in the load function during
stu_list.read((char*)test, sizeof(*test));
it overwrites the old data in the insert function as well even though it is called before this line.
Once again the insertion into the file works perfectly fine , i can actually see the values being loaded via the debugging mode
here is the insert function for reference
INSERT :
void update_student_file(linked_student testing)
{
node_student *temp = testing.head;
ofstream stu_list("students.dat",ios::binary);
while (temp != NULL)
{
stu_list.write((char*)temp, sizeof(*temp));
temp = temp->next;
}
stu_list.close();
}
Here a fix to load_file_students:
void load_file_students(linked_student &students)
{
node_student test; //way use dynamic allocation?
ifstream stu_list("students.dat",ios::binary);
while (stu_list.read((char*)test, sizeof(*test)))
{
students.insert_node_list(&test);
}
//file will be closed at the destructor.
}
Another fix for insert_node_list
void linked_student::insert_node_list(node_student *student)
{
node_student* temp = new node_student;
*temp = *student; //call copy constructor, do not copy pointer value.
if (head == NULL)
{
head = temp;
}
else
{
node_student *ptr = this->head;
while (ptr->next != 0)
{
ptr = ptr->next;
}
temp->previous = ptr;
ptr->next= temp;
}
}
I have written a set of functions which together build a list of "Hubs" from a .csv file. I wish to generate a linked-list of these hubs in my main function I have a "head" pointer that I can pass to other functions in main.
The code in main:
HubNode *hh = NULL;
HubNode **head;
*head = hh;
Tools::loadHubs(head);
cout << hh->name; /* HubNodes have a string called "name" */
The code in Tools:
void Tools::loadHubs(HubNode **head)
{
string line, name, location;
// headFlights = currFlights = prevFlights = NULL;
ifstream myfile("Hub.csv");
if (myfile.is_open())
{
while (getline(myfile, line)) {// Omit the Caption Line.
while (getline(myfile, name, ','))//Get every value in order.
{
getline(myfile, location, '\n');
// cout << line << "\n";
// cout << name << "\n";
// cout << location << "\n";
HubNode::AddHub(name, location, head);
}
}
myfile.close();
}
else { cout << "\nUnable to open file\n"; }
}
The code in HubNode:
void HubNode::AddHub(string sname, string slocation, HubNode **head)
{
HubNode* newNode = new HubNode;
HubNode *point;
newNode->next = NULL;
newNode->name = sname;
newNode->location = slocation;
if (*head != NULL)
{
HubNode *curr = *head;
while (curr->next != NULL)
{
curr = curr->next;
}
curr->next = newNode;
}
else
{
point = newNode;
*head = point;
}
}
I thought that using a double pointer to the head of the list in this way would work, so that from "hh" in main, I would have access to the whole linked-list.
When I compile and start debugging, I can see that AddHubs is successfully creating the HubNodes in its scope, But when I try to access any of the elements from main (e.g. by cout << hh->name), I get a segmentation fault.
What have I done wrong? (Let me know if I need to post more code...)
You wouldn't do this:
int value = 10;
int *p;
*p = value;
So why would you think this would work:
HubNode *hh = NULL;
HubNode **head;
*head = hh;
The indirection is the same, only the type has changed. And both snippets invoke undefined behavior. This code should do this:
HubNode *hh = NULL;
Tools::loadHubs(&hh);
cout << hh->name;
Further, your add function should be:
void HubNode::AddHub(const string& sname, const string& slocation, HubNode **head)
{
HubNode* newNode = new HubNode;
newNode->next = NULL;
newNode->name = sname;
newNode->location = slocation;
while (*head)
head = &(*head)->next;
*head = newNode;
}
It gets even more straight forward if you provide a proper constructor for HubNode that takes the sname and slocation as construction parameters and initializes the node next member to NULL. if you code that, the add becomes simply:
void HubNode::AddHub(const string& sname, const string& slocation, HubNode **head)
{
while (*head)
head = &(*head)->next;
*head = new HubNode(sname, slocation);
}
I'm programming doubly linked list, everything was going fine but I faced with crash when reading a string value to the structure (code row is commented in the function "struct Node* GetNewNode()"):
#include <iostream>
#include <String>
#include <fstream>
#include <cstdlib>
using namespace std;
struct Node {
int sv;
double real;
bool log;
char simb;
string str;
struct Node* next;
struct Node* prev;
};
struct Node* head; // global variable - pointer to head node.
//----------------------------
struct Node* GetNewNode();
void Initialize(Node *stack);
void InsertAtTail(Node *stack);
void Print(Node *stack);
//----------------------------
//Creates a new Node and returns pointer to it.
ifstream fd("duom.txt");
struct Node* GetNewNode() {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
fd >> newNode->sv;
fd >> newNode->real;
string loginis;
fd >> loginis;
if (loginis == "TRUE")
newNode->log = true;
else
newNode->log = false;
fd >> newNode->simb;
//fd >> newNode->str; //uncommented code in this row crashes the program
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
//Inserts a Node at head of doubly linked list
void Initialize(Node *stack) {
stack = head;
}
//Inserts a Node at tail of Doubly linked list
void InsertAtTail(Node *stack) {
struct Node* temp = stack;
struct Node* newNode = GetNewNode();
if(head == NULL) {
head = newNode;
return;
}
while(temp->next != NULL)
temp = temp->next; // Go To last Node
temp->next = newNode;
newNode->prev = temp;
}
//Prints all elements in linked list in reverse traversal order.
void Print(Node *stack) {
struct Node* temp = stack;
if(temp == NULL)
return; // empty list, exit
// Going to last Node
while(temp->next != NULL)
temp = temp->next;
// Traversing backward using prev pointer
while(temp != NULL) {
cout << temp->sv << " ";
cout << temp->real << " ";
if (temp->log == true)
cout << "TRUE " << " ";
else
cout << "FALSE " << " ";
cout << temp->simb << " ";
//cout << temp->str << "\n";
temp = temp->prev;
}
printf("\n");
}
int main() {
/*Driver code to test the implementation*/
head = NULL; // empty list. set head as NULL.
// Calling an Insert and printing list both in forward as well as reverse direction.
Initialize(head);
InsertAtTail(head);
Print(head);
InsertAtTail(head);
Print(head);
fd.close();
}
Input data is:
4 5.27 TRUE $ asdf
6 7.3 TRUE # qwer
9 8.8 FALSE # zxvc
7 6.35 FALSE ! vbmn
1 0.89 TRUE % ghjk
Can somebody explain what is wrong here?
Instead of using C standard function malloc
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
you have to use operator new
In this case the compiler will call a constructor of class std::string that to create data member str
Othewise object str of type std::string will not be created and the program will chash.
Function malloc simply allocates a raw memory of a requested size. It knows nothing about constructors of classes.
malloc allocates a raw block of memory. This is sufficient for simple (POD) datatypes which only store data. A std::string however needs to have its constructor called to be initialized correctly. Therefore you must allocate the node using new:
Node* newNode = new Node();
In general, malloc is very rarely needed in C++ (it doesn't call any constructors). It is a C-function.
Note that you need to call delete instead of free to free memory allocated by new.
I am a beginner in C++ and need help in many things. Well, for the starters, I have been working on Linked List and not really getting why my header(the first pointer which points towards first node) keep on rotating. I am just pointing it towards first node plus my display node is just displaying last node, why is it so?. Please tell me where I am wrong. Thank you in advance
#include <iostream>
#include <conio.h>
using namespace std;
struct Node
{
int data;
Node *link;
};
Node* create_Node()
{
int no_of_nodes;
Node *header = new Node;
Node *ptr = new Node;
header = ptr;
cout << "Enter no of nodes:";
cin >> no_of_nodes;
cout << "Enter data:";
for(int n = 0; n < no_of_nodes; n++)
{
cin >> ptr->data;
Node *temp = new Node;
ptr->link = temp;
temp = ptr;
}
ptr->link = NULL;
return ptr;
}
void display_link_list(Node * list)
{
Node *temp = new Node;
temp = list;
while(temp != NULL)
{
if(temp->link != NULL)
{
cout << "List:" << list->data << endl;
temp = temp->link;
}
}
}
int main()
{
Node *n = new Node;
n = create_Node();
display_link_list(n);
getch();
return 0;
}
Welcome to C++. My advice here is to break the Linked list into two. First the Nodes and then a List struct.
struct Node
{
int data;
Node *next;
Node(int data) : data(data), next(NULL) {}
};
struct List {
Node* tail;
Node* head;
List() : head(NULL), tail(NULL) {}
void insert(int data) {
if(head==NULL) {
head = new Node(data);
tail = head;
} else {
tail->next = new Node(data);
tail = tail->next;
}
}
};
Now you can insert one element into the list at a time and use head to print the list from beginning to end.
Something basic that you need to understand:
When you do Node* p = new Node, you are setting variable p to point to the start address of a piece of memory, the size of which being equal to sizeof(Node).
Now, when you then do p = something else (which often appears in your code), you are essentially overriding the previous value of p with some other value. It is like doing:
int i = 5;
i = 6;
So your code does not do what you're expecting to begin with.
In addition to that, what's bad about overriding the first value with a second value in this case, is the fact that the first value is the address of a dynamically-allocated piece of memory, that you will need to delete at a later point in your program. And once you've used p to store a different value, you no longer "remember" that address, hence you cannot delete that piece of memory.
So you should start by fixing this problem in each of the following places:
Node *header = new Node; // Variable 'header' is assigned
header = ptr; // Variable 'header' is reassigned
Node *temp = new Node; // Variable 'temp' is assigned
temp = list; // Variable 'temp' is reassigned
Node *n = new Node; // Variable 'n' is assigned
n = create_Node(); // Variable 'n' is reassigned