I recently did a school homework assignment and lost points, in the comment the grader said that I didn't deallocate the pointers correctly.
Below is the code I sent, I would just like to know how it would look to deallocate the pointers correctly?
/*Student: Daniel
*Purpose: To reverse a string input using
*pointers.
*/
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int main() {
string input;
char *head = new char, *tail = new char;
char temp;
//Get the string from the user that will be reversed
cout << "Enter in a string that you want reversed: ";
getline(cin, input);
//Create and copy the string into a character array
char arr[input.length()];
strcpy(arr, input.c_str());
//Set the points of head/tail to the front/back of array, respectably
head = &arr[0]; tail = &arr[input.length()-1];
for(int i=0; i<input.length()/2; i++) {
temp = *(tail);
*tail = *head;
*head = temp;
tail --; head ++;
}
for(int i=0; i<input.length(); i++) {
cout << arr[i];
}
//********MY PROBLEM AREA*************
delete head; delete tail;
head = NULL; tail = NULL;
return 0;
}
So take a look here...
char *head = new char, *tail = new char;
And then...
//Set the points of head/tail to the front/back of array, respectably
head = &arr[0]; tail = &arr[input.length()-1];
You reassigned what head and tailpoint to, so you're not actually deleting the right things when you call delete. In fact, I'm surprised you don't crash.
Really you can probably just do:
char *head = NULL; char* tail = NULL;
and then not delete anything since you won't have anything dynamic.
Related
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 };
}
#include<iostream>
#include<process.h>
using namespace std;
template<class T>
class List{
class Node{
public:
T num;
Node*next;
}*head,*tail;
public:
List(){
head = tail = NULL;
}
void insert(T *n){
Node*tmp=new Node;
tmp->next = head;
tmp->num = *n;
head = tmp;
if (tail == NULL){
tail = tmp;
}
}
void append(T*n){
Node*tmp=new Node;
tmp->next=NULL;
tmp->num = *n;
if (tail == NULL){
head = tail = tmp;
}
else {
tail->next = tmp;
tail = tmp;
}
}
T Get(){
if (head == NULL){
exit(0);
}
else{
T t = head->num;
Node*p = head;
if (head->next == NULL){
head = tail = NULL;
}
else{
head = head->next;
}
delete (p);
return t;
}
}
};
class person{
public:
char*name=new char[];//problem lies here!
//char name[20];
int age;
float hight;
person(){}
};
int main(){
person a;
List<int>link1;
List<person>link2;
for (int i = 0; i < 5; i++){
cin >> a.name >> a.age >> a.hight;
link2.insert(&a);
link1.append(&i);
}
for (int i = 0; i < 5; i++){
a = link2.Get();
link2.append(&a);
cout << a.name << " " << link1.Get() << endl;
}
}
As the explanation goes in the code, when using char*name=new char[] to replace char name[20], the program went wrong. It wouldn't output all the names as expected, but only print the last input name 5 times. So what's the difference between these two expressions?
Thanks a lot.
new char[] doesn't compile under GCC. :) new char[20], however, does.
char[20] tells the compiler that you want 20 characters in an array. This is typically allocated on your call stack. Very large allocations can cause stack overflows so this is discouraged in some circles.
If you use new you must call delete[] name or you will have a memory leak. If you call delete name you will have an error in your code because the array will not be deleted, only that one char *.
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);
}
I have been given the task to receive a string input from the user and reverse the order of the string and print the result out. My code is this:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int main() {
string input;
char *head = new char, *tail = new char;
char temp;
//Get the string from the user that will be reversed
cout << "Enter in a string that you want reversed: ";
getline(cin, input);
//Create and copy the string into a character array
char arr[input.length()];
strcpy(arr, input.c_str());
//Set the points of head/tail to the front/back of array, respectably
head = &arr[0]; tail = &arr[input.length()-1];
//Actual reversal part of the code (Does not work)
for(int i=0; i<input.length(); i++) {
temp = *(tail);
*tail = *head;
*head = temp;
tail --; head ++;
}
//Print the character array
for(int i=0; i<input.length(); i++) {
cout << arr[i];
}
//Free up memory
delete head; delete tail;
head = NULL; tail = NULL;
return 0;
}
When I print it, literally nothing has been changed and I can't seem to understand why as I'm brand new to pointers. This is the specific block that I'm having trouble with:
for(int i=0; i<input.length(); i++) {
temp = *(tail);
*tail = *head;
*head = temp;
tail --; head ++;
}
Any input on how to fix this or pointer knowledge in general that'd help is greatly appreciated.
Your approach is good but...
for(int i=0; i<input.length(); i++) {
temp = *(tail);
*tail = *head;
*head = temp;
tail --; head ++;
}
Didn't you try working this out on paper? You swap each pair of letters twice, bringing the array back to its original order.
Just change the limit of iteration, to stop when head and tail meet in the middle, and you'll be all right:
for(int i=0; i<input.length()/2; i++) {
...
}
I've tried to help a friend with a list code in c++. I've wrote:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct list* createlist(FILE *m);
struct list
{
char *data;
struct list *next;
}list;
main()
{
char a[100], ch;
struct list* obj;
cout<<"Enter the name of the file for obtaining input.."<<endl;
cin>>a;
FILE *in;
in=fopen(a,"r");
if(in!=NULL)
{
ch=fgetc(in);
if(ch=='1')
obj=createlist(in);
fclose(in);
}
return 0;
}
struct list* createlist(FILE *m)
{
cout<<"Entered createlist function..!"<<endl;
char *tempStr = (char *)malloc(30 * sizeof(char));
struct list *curr, *head = (struct list *)malloc(sizeof(struct list));
curr = head;
curr->data = tempStr;
char c;
int i=0;
curr=NULL;
while(EOF!=(c=fgetc(m)))
{
if((c==' ') || (c=='\0') || i == 29)
{
if(i==0)
{
continue;
}
tempStr[i]='\0';
i=0;
struct list *temp = curr;
curr = (struct list *)malloc(sizeof(struct list));
temp->next = curr;
tempStr = (char *)malloc(30 * sizeof(char));
curr->data = tempStr;
continue;
}
tempStr[i]=c;
i++;
}
return head;
}
But the code throw exception. I tried to understand what went wrong and change the code for 2-3 hours, and could not understand. I'm allocating space for the list item, but when I try to assign value to next at the line
temp->next = curr;
I get segmentation fault.
At the end I've managed to solve it by taking some code from the net instead of mine:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct list* createlist(FILE *m);
struct list
{
char *data;
struct list *next;
}list;
main()
{
char a[100], ch;
struct list* obj;
cout<<"Enter the name of the file for obtaining input.."<<endl;
cin>>a;
FILE *in;
in=fopen(a,"r");
if(in!=NULL)
{
ch=fgetc(in);
if(ch=='1')
obj=createlist(in);
fclose(in);
}
return 0;
}
struct list* createlist(FILE *m)
{
cout<<"Entered createlist function..!"<<endl;
char *tempStr = (char *)malloc(30 * sizeof(char));
struct list *curr, *head = (struct list *)malloc(sizeof(struct list));
curr = head;
curr->data = tempStr;
char c;
int i=0;
curr=NULL;
while(EOF!=(c=fgetc(m)))
{
if((c==' ') || (c=='\0') || i == 29)
{
if(i==0)
{
continue;
}
tempStr[i]='\0';
i=0;
struct list *temp = curr;
curr = (struct list *)malloc(sizeof(struct list));
temp->next = curr;
tempStr = (char *)malloc(30 * sizeof(char));
curr->data = tempStr;
continue;
}
tempStr[i]=c;
i++;
}
return head;
}
But I still don't know what went wrong in my code. Can anyone help me understand so I won't repeat my mistake in the future?
The two versions are identical as far as I can see, but the error is easy to tell. Here's your code with some comments
// at this point curr is NULL (see start of while loop)
struct list *temp = curr;
// so now temp is NULL
curr = (struct list *)malloc(sizeof(struct list));
// now curr is pointing at some memory, but temp is still NULL
temp->next = curr;
// temp is NULL so this crashes
Like everyone else I think if you remove curr = NULL; you'll be closer.
Your 'temp' is NULL:
curr=NULL;
Afterwards:
struct list *temp = curr;
And finally:
temp->next = curr;
You are trying to use structure pointer that has a NULL value.
I know this is not going to help you much, but I see several other problems with the code and it's not easy to read.
Since you marked this C++, did you considet using one of the std containers? Like std::list ?
Before the while loop, you are assigning NULL into curr
curr=NULL;
Then, you are assigning curr to temp
struct list *temp = curr;
Then when you do
temp->next = curr;
you get a segmentation fault because NULL does not have a next pointer.
If you remove curr=NULL;, you should be ok.
the problem is the you do
curr=NULL;
just before he while loop