C++ - Struct addition via streams, what's wrong with this code? - c++

I am practicing streams in C++ because I've got a midterm coming up in school. I am trying to write a small program that adds items to a list of Nodes (structs). I've got the following code, and am getting a clear error, but don't know how to fix it.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
struct Node {
string name;
Node *next;
};
void foo(istream &in, ostream &out, Node *list) {
string nom;
in >> nom; //Assigns value to nom via cin
Node *temp = list;
while (temp->next != NULL) { //Loops through list to find null pointer
temp = temp->next; //to add new Node to
}
Node item; //Creates new Node with a NULL next
item.name = nom;
item.next = NULL;
temp->next = item; //Adds item to the list
out << nom; //Outputs that it's been added
cout << " added" << endl;
}
int main() {
Node one;
one.next = NULL;
foo(cin, cout, &one);
}
The error I'm getting is:
Cannot convert 'Node' to 'Node*' in assignment (Line 22)

Aside from the type mismatch (Node and Node* are not the same), you did not allocate item dynamically, and it's going to be destroyed when foo finishes. Assigning &item would leave you with invalid temp->next.
In code:
Node *item = new Node;
item->name = nom;
item->next = nullptr; // I can't write NULL
temp->next = item;
condensed into one statement:
temp->next = new Node{nom, nullptr};

Related

Cant display a linked list properly with char

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

C++ linked list crashed

I am new on data structure. I am trying to write a linked list for a string and display the list to screen. It crash at Node *p = create("I "); with the warning of access violation writing location. Here is my code, I don't know how to fix it. Please help. Thank you very much.
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
struct Node
{
string data;
Node *prev, *next;
};
Node* create (string value)
{
Node *temp = (Node*)malloc(sizeof(Node));
if (NULL==temp) return NULL;
temp->data=value;
temp->next=NULL;
temp->prev=NULL;
return temp;
}
void addHead (Node* head, string value)
{
Node *temp = new Node;
temp->data=value;
temp->next=head;
head->prev=temp;
head = temp;
temp->prev = NULL;
}
void addTail (Node* head, string value)
{
Node* s = new Node;
Node* temp = new Node;
s=head;
while (s->next!=NULL)
s = s->next;
s->next = temp;
temp->prev = s;
}
void display (Node* head)
{
if (head==NULL) return;
else
{
cout << head->data << " ";
display (head->next);
}
}
int main()
{
Node *p = create("I ");
addTail(p, "want ");
addTail(p, "cookies ");
display(p);
return 0;
}
You need to create a Node using new, not malloc, in your create function. Using malloc, the constructor for Node is not called, and the assignment to data will access an uninitialized string object.

How to dynamically create new nodes in linked lists C++

Could anyone tell me if this is the basic idea of linked lists? What are the pros and cons to this method and what are best practices when implementing linked lists in C++? Im new to data structures so this is my first approach. If there is a better way to do this same thing, please let me know. Additionally, how would you create the nodes dynamically without hard coding it? Thanks.
#include <iostream>
#include <string>
using namespace std;
struct node {
int x;
node *next;
};
int main()
{
node *head;
node *traverser;
node *n = new node; // Create first node
node *t = new node; // create second node
head =n; //set head node as the first node in out list.
traverser = head; //we will first begin at the head node.
n->x = 12; //set date of first node.
n->next = t; // Create a link to the next node
t->x = 35; //define date of second node.
t->next = 0; //set pointer to null if this is the last node in the list.
if ( traverser != 0 ) { //Makes sure there is a place to start
while ( traverser->next != 0 ) {
cout<< traverser->x; //print out first data member
traverser = traverser->next; //move to next node
cout<< traverser->x; //print out second data member
}
}
traverser->next = new node; // Creates a node at the end of the list
traverser = traverser->next; // Points to that node
traverser->next = 0; // Prevents it from going any further
traverser->x = 42;
}
for tutorial purpose, you can work out this example:
#include <iostream>
using namespace std;
struct myList
{
int info;
myList* next;
};
int main()
{
//Creation part
myList *start, *ptr;
char ch = 'y';
int number;
start = new myList;
ptr = start;
while (ptr != NULL)
{
cout << "Enter no. ";
cin >> ptr->info;
cout << "Continue (y/n)? ";
cin >> ch;
if (ch == 'y')
{
ptr->next = new myList;
ptr = ptr->next;
}
else
{
ptr->next = NULL;
ptr = NULL;
}
}
//Traversal part begins
cout << "Let's start the list traversal!\n\n";
ptr = start;
while (ptr!=NULL)
{
cout << ptr->info << '\n';
ptr = ptr->next;
}
}
It allocates memory dynamically for as many elements as you want to add.
I'd prefer to make a linked list class. This eliminates the need to call 'new' more than once. A nice implementation with examples can be found here.
You are in fact already doing dynamic allocation. So, not sure what you are asking for. But if you want to define functions to add new nodes to your linked list (or delete a node etc.), this can be a probable solution:
The location nodes get inserted/deleted is dependent on the type of data-structure. In a queue, new nodes will get added to the end; at the top in case of a stack. A function that adds a node to the top, simulating STACK push operation:
void pushNode(node **head, int Value) {
node *newNode = new node;
newNode->x = Value;
newNode->next = *head;
*head = newNode;
}
It would be called like pushNode(&head, 15) where 'head' would be defined as node *head = NULL. The root head should initially be set to NULL. After this operation head will point to the newly added node (top of stack).
The approach would be very similar for other data-structures (viz. queues) and works fine. But as you are using C++, I would suggest to define a class for your linked-list and define these functions as methods. That way, it will be more convenient and less error-prone.
Even better use std::list. It's the standard thing, so much portable and robust than a custom implementation.
You can also do it in this way
#include <iostream>
using namespace std;
struct Node{
int data;
Node* next;
};
void createList(Node** head ,Node* temp){
int n;
char ch;
temp = *head;
while(temp != NULL){
cout<<"Enter The Value ";
cin>>temp->data;
cout<<"DO you want to continue(y/n)";
cin>>ch;
if(ch=='Y' || ch == 'y'){
temp->next = new Node;
temp = temp->next;
}else{
temp->next = NULL;
temp = NULL;
}
}
}
void ShowList(Node* head){
cout<<"your list :"<<endl;
while(head != NULL){
cout<<head->data<<" ";
head = head->next;
}
}
int main()
{
//Creation part
Node *head, *temp;
createList(&head,temp);
ShowList(head);
}

Program crashes because of string?

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.

Attempting to create a pointer to previous object inside object

I'm attempting to create a vector of pointers to Nodes, where each node stores a pointer to the previous Node in the list.
I made a small test program to see if I could access a variable gscore in the previous object to the one I call.
#include <iostream>
#include <vector>
using namespace std;
struct Node
{
Node(int gscore1)
{
gscore = gscore1;
}
Node *previous;
int gscore;
};
int main()
{
std::vector<Node*> nodeVec;
Node *tempnode;
tempnode = new Node(10);
Node *tempnode2;
tempnode = new Node(11);
nodeVec.push_back(tempnode);
nodeVec.push_back(tempnode2);
nodeVec[1]->previous = tempnode;
cout << nodeVec[1]->previous->gscore << endl;
return 0;
}
However this results in a crash. What is the correct way to do this?
You never initialize tempnode2. You initialize tempnode twice.
int main()
{
std::vector<Node*> nodeVec;
Node *tempnode;
tempnode = new Node(10);
Node *tempnode2;
tempnode2 = new Node(11); // <<---- HERE
nodeVec.push_back(tempnode);
nodeVec.push_back(tempnode2);
nodeVec[1]->previous = tempnode;
cout << nodeVec[1]->previous->gscore << endl;
return 0;
}
Looks like a typing error. The third line in main() should be tempnode2 not tempnode.