I am attempting to implement a linked list in C++, when I create an object pointer without the keyword new, the code does not display anything. I have done some research and found that by using the new keyword this fixed this issue, but I am not entirely sure as to why this fixes it, I read that the pointer object may go out of scope and this "new" prevents that, but I do not understand how it goes out of scope.
Here is the code:
#include <iostream>
using namespace std;
struct Node{
int val;
};
int main(){
Node *head;
//Node *head = new Node; fixed the issue
head->val = 200;
cout << head->val;
return 0;
}
Related
This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 3 days ago.
I have a method called deleteList that takes a head of a single linked list as an input and it removes all the nodes.
In the method deleteList I can verify that all the nodes are deleted, but when the execution returns back to the main, myList is not empty. So in the subsequent call to LengthOfList, the code fails with an exception.
[Please note that I am unable to change the signature of deleteList]
Here is the code:
#include <iostream>
using namespace std;
typedef struct CodeNode* List;
struct CodeNode
{
char data;
List next;
CodeNode(char new_data, List new_next)
: data(new_data), next(new_next) {
}
};
int LengthOfList(List head)
{
int len = 0;
for (List ptr = head; ptr != nullptr; ptr = ptr->next) {
len++;
}
return len;
}
void deleteList(List head)
{
List prev = head;
while (head)
{
head = head->next;
delete(prev);
prev = head;
}
// I can verify that head is null and all the nodes have been deleted
}
int main(void)
{
List temp1 = new CodeNode('3', nullptr);
List temp2 = new CodeNode('2', temp1);
List myList = new CodeNode('1', temp2);
cout << "Before " << LengthOfList(myList);
deleteList(myList);
cout << "After " << LengthOfList(myList); // CODE FAILS HERE because myList is pointing to a bad memory address (it SHOULD be NULL)
}
Pass by reference
void deleteList(List& head)
The & makes all the difference. If you want a function to alter a variable in the calling function then you pass by reference.
All your code is doing is modifying the variable head in the function deleteList which is not the same variable as head in main. By using a reference you make head in deleteList an alias for the variable used in the calling function, and therefore changes to it effect that variable.
Another option is to return the changed variable, so in main
myList = deleteList(myList);
and in deleteList
List deleteList(List head)
{
...
return head; // return modified head
}
Both approaches work, it's a style choice which you choose.
I just noticed your comment, 'please note I'm unable to change the signature of deleteList'. Then I'm afraid your code is guaranteed to fail. There is no solution given the peculiar constraints you have been given.
It's amazing how often we see this here, newbie struggling with some problem, but unable to use any of the solutions that any normal programmer would use because of artificial constraints placed on the task by their teacher. In some cases, like yours, these constraints are so severe that there is literally no solution to the task that they've been given. I suggest you ask your teacher for some advice.
In short, your solution is doing exactly this.
#include <iostream>
typedef struct CodeNode* List;
struct CodeNode {
char data;
List next;
CodeNode(char new_data, List new_next): data(new_data), next(new_next) {}
};
int main() {
List myList = new CodeNode('1', nullptr);
cout<<myList->data<<endl;
delete(myList);
cout<<myList->data<<endl;
return 0;
}
// given error
// AddressSanitizer: heap-use-after-free on address
// 0x602000000010 at pc 0x000000342fd6 bp 0x7fffcb6b5110 sp 0x7fffcb6b5108
And, accessing myList after deletion is supposed to be undefined as this is an example of heap use after free which occurs when a program continues to use a pointer after it has been freed.
Useful Links
ASAN heap use after free
Use after free error?
Solution
john's answer has already given the answer on how passing by reference can actually update the underlying variable and produce the desired effect.
I just wanted to supplement the reason for your understanding.
Currently I'm trying to use multiple classes (each with their own .cpp and header .h file) and link them using a main .cpp. I want to make a temporary new video object pointer, pass in the arguments, insert it into the linked list, and delete the temporary pointer. Afterwards, I need to print each individual node of the list.
Currently there are 4 files: main.cpp, vlist.cpp, vlist.h, video.cpp, and video.h
I am using vlist as a way to construct a linked list which gets passed in a video object pointer with the insert function defined in the vlist.cpp file.
The first problem being that I'm not sure I am doing that correctly. At the moment, all I'm doing to be able to pass a video object in another class is by including video.h in the vlist.h file.
The second problem is that I cannot figure out how to properly access the individual video object attributes in each node because my getter functions (defined in video.h) won't work. They seem to return an address rather than a value. However, whenever I try to fix that, it tells me that I cannot use the getter function like this.
My third and final problem is that in vlist.cpp I cannot pass in m_vid when creating a new node but I can pass in m_head just fine. It won't compile if I don't use myVid (a publicly declared video object pointer in vlist.h).
Files below:
main.cpp
#include <iostream>
using namespace std;
#include "vlist.h"
#include "video.h"
int main()
{
//Create temporary video object pointer using Video * temp = new Video(arguments);
//Pass in the temp video pointer to the list and insert it with VList function
string firstLine, secondLine, thirdLine = "";
float fourthLine = 1.1;
int fifthLine = 2;
VList list;
Video * tempVid = new Video(firstLine, secondLine, thirdLine, fourthLine, fifthLine);
list.insert(tempVid);
delete tempVid;
list.print();
return 0;
}
video.cpp
#include "video.h"
#include <iostream>
using namespace std;
Video::Video(string title, string URL, string comment, float length, int rating) {
vidTitle = title;
vidURL = URL;
vidComment = comment;
vidLength = length;
vidRating = rating;
}
void Video::print(Video *myVid) {
cout << myVid->getTitle() << endl;
}
video.h
#ifndef VIDEO_H
#define VIDEO_H
#include <string>
#include <iostream>
using namespace std;
class Video
{
public:
Video(string title, string URL, string comment, float length, int rating);
int getRating() {
return vidRating;
}
float getLength() {
return vidLength;
}
string getTitle() {
return vidTitle;
}
string getURL() {
return vidURL;
}
string getComment() {
return vidComment;
}
void print(Video *myVid);
private:
string vidTitle, vidURL, vidComment, vidPreference;
float vidLength;
int vidRating;
};
#endif
vlist.cpp
#include <iostream>
using namespace std;
#include "vlist.h"
VList::VList() {
m_head = NULL;
}
VList::~VList() {
Node *ptr = m_head;
while (ptr != NULL) {
Node *temp;
temp = ptr;
ptr = ptr->m_next;
delete temp;
}
}
void VList::insert(Video *myVid) {
m_head = new Node(myVid, m_head);
}
void VList::print() {
Node *ptr = m_head;
while (ptr != NULL) {
cout << ptr->m_vid->getTitle();
ptr = ptr->m_next;
}
}
vlist.h
#ifndef VLIST_H
#define VLIST_H
#include "video.h"
class VList
{
public:
VList();
~VList();
void insert(Video *myVid);
void print();
Video *myVid;
private:
class Node
{
public:
Node(Video *myVid, Node *next) {
m_vid = myVid;
m_next = next;
}
Video *m_vid;
Node *m_next;
};
Node *m_head;
};
#endif
The first problem being that I'm not sure I am doing that correctly.
At the moment, all I'm doing to be able to pass a video object in
another class is by including video.h in the vlist.h file.
No, you are not doing it correctly, In the file main.cpp you are creating a pointer to Video(i.e, a Video*) and passing it to void VList::insert(Video *myVid) function and at the next line you are deleting the pointer before printing it. Remember that, when you create pointers and pass it to a method its lifecycle is not managed automatically like a magic, you yourself need to manage the pointers (which is the most common issue beginners face, I too). So there are two fixes to this problem
First Fix
Not deleting the pointer in the main, since it is deleted in the destructor of the VList.
#include <iostream>
using namespace std;
#include "vlist.h"
#include "video.h"
int main()
{
//Create temporary video object pointer using Video * temp = new Video(arguments);
//Pass in the temp video pointer to the list and insert it with VList function
string firstLine, secondLine, thirdLine = "";
float fourthLine = 1.1;
int fifthLine = 2;
VList list;
Video * tempVid = new Video(firstLine, secondLine, thirdLine, fourthLine, fifthLine);
list.insert(tempVid);
// delete tempVid; // don't delete this pointer right here, since I've found that you are deleting the pointer in the destructor of VList
list.print();
return 0;
}
Second Fix
You might like to use something called smart pointers as of C++11 these are standardized! See std::unique_ptr and std::shared_ptr. They will automatically delete the pointers and guarantees no memory leaks.
The second problem is that I cannot figure out how to properly access
the individual video object attributes in each node because my getter
functions (defined in video.h) won't work.
Your second problem is related to first one as your are deleting the pointer before using it which causes undefined behaviour and the output you might be getting is like a garbage. isn't it?
For the sake of simplicity I would recommend using simple Video reference not pointers. Pass them by value and all your problems will evaporate.
To answer my own question and that of anyone who might see this. I just needed to change it around a bit and set a temp object pointer inside of print and cout a get function onto that. It's very late so I apologize if there are any errors. I was indeed getting an address like I thought.
void VList::print() {
Node *ptr = m_head;
while (ptr != NULL) {
Video *tempPtr = ptr->m_vid;
cout << tempPtr->getTitle() << endl;
ptr = ptr->m_next;
}
}
I am newbie in C++. The interviewer said it's bad practice to create an object within a function. Is it so?
#include <iostream.h>
class linkedlist {
int value;
linkedlist *next;
static linkedlist *p=NULL;
void insert(int data) {
linkedlist node;
node.value=data;
node.next=NULL;
if(p==NULL)
p=node;
else {
p->next=node;
p=p->next;
}
}
}
int main() {
linkedlist h;
h.insert(10);
h.insert(20);
return 0;
}
The problem is "lifetime"; the node you created lives only in the stack frame of the function and when the function terminates its memory is reclaimed. The static pointer p however will still link it and this will lead to "undefined behavior" when someone later accesses the linked list.
Using local objects is not bad in general, it's only bad if you expect them to survive the end of the function, because they don't.
You should allocate long-living objects the object on the free store, by using new.
Yes, I know it's a duplicate of like a hundred questions, but I have been working on this for hours and nothing is working.
All I want to do is initialize some private variables inside a class definition.
The structure looks like this:
#include <string>
using namespace std;
typedef string DataType;
class Slist {
public:
private:
// private data type: Node
struct Node {
DataType data;
Node *next;
};
// state variables:
Node *head, *tail, *cursor;
};
I am initializing them like so:
Slist::Slist (void) {
cursor -> data = 'n';
cursor -> next = new Node;
And this is giving me a segmentation fault. I know this means I am trying to access memory that doesn't exist, but despite these being private variables, I am trying to access them in the Slist CONSTRUCTOR, which would of course have access to them. If someone would tell me what is up I would be extremely grateful.
You did not initialize or assign the pointer to a memory location. Any pointer requires valid memory location to work with.
you can do
cursor = new Node;
Before using the arrow operator.
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.