I am given a task to simulate a linked list structure, but using an array of Nodes rather than an actual linked list. When I call my append function, I want to check to see if my existing array is full, and if it is, I want to double the array size, and append my Node to the end of the "list" (array).
I am having trouble doubling my array size.
To give you context, here is my some of my .h file:
...
const int NULL_INDEX = -1;
struct Node {
char info;
int next;
};
class LList1 {
private:
Node free [4];
// When more memory is called for, the array will double in size
// returns true if reallocation of memory was successful
bool doubleSize();
.
.
.
}
and here is the part of my .cpp file that tries to double the array size:
bool LList1::doubleSize() {
Node* newArray = new Node[this->length()*2];
memcpy(newArray, free, this->length()*2);
free = newArray;
return true;
}
I also tried using realloc and other functions. I keep having the same problem.
The line
"free = newArray"
keeps giving me this error in XCode: "Array type 'Node[4]' is not assignable"
Please give me some insight into a better way to do this. All solutions online seem to work fine for arrays of ints, but not for my array of Nodes.
Much appreciated.
A couple of things are incorrect in your code:
Your free property is a static array. In your case you need a dynamic one, with proper constructor.
The memcpy command takes the size in bytes, hence you need to multiply by sizeof(Node).
Perhaps it was intended, but the doubleSize() method was private.
Here is a corrected version of the code that compiles and runs:
...
const int NULL_INDEX = -1;
struct Node {
char info;
int next;
};
class LList1 {
public:
LList1();
~LList1();
int getLength();
bool doubleSize();
private:
int length;
Node* free;
// When more memory is called for, the array will double in size
// returns true if reallocation of memory was successful
};
int LList1::getLength() {
return this->length;
}
LList1::LList1() {
this->free = new Node[4]; // Default size
this->length = 4;
}
LList1::~LList1() {
delete []this->free;
}
bool LList1::doubleSize() {
Node* newArray = new Node[this->length*2];
memcpy(newArray, free, this->length * sizeof(Node));
free = newArray;
this->length *= 2;
return true;
}
int main(int, char **) {
LList1 l;
std::cout << "Original length: " << l.getLength() << std::endl;
l.doubleSize();
std::cout << "After doubling length: " << l.getLength() << std::endl;
return 0;
}
You are getting confused between arrays and pointers. Your variable free is a constant pointer which cannot be reassigned. You need to change Node free [4] to Node *free if you want to modify its value.
C/C++ int[] vs int* (pointers vs. array notation). What is the difference?
Related
I have written this code and am confused about why is it showing segmentation fault. I think my dynamic memory allocation is causing problems for me here. Can anyone tell me what is causing the segmentation fault in here and how to improve the code.
Also, please tell me if I can create the object with the ClassName obj(); and store it in the stack instead of the heap. Or would this implementation be needed in some problems
#include<bits/stdc++.h>
using namespace std;
class Queue
{
public:
int rear, front, size,capacity;
int* arr;
Queue(int c)
{
capacity=c;
rear=c-1;
front=0;
int *arr= new int[c*sizeof(int)];
}
};
int isEmpty(Queue* queue)
{
return (queue->size==0);
}
int isFull(Queue* queue)
{
return (queue->size==queue->capacity);
}
void enqueue(Queue* queue, int x)
{
if(isFull(queue))
return;
queue->rear=(queue->rear+1)%queue->capacity;
queue->arr[queue->rear]=x;
queue->size+=1;
}
int dequeue (Queue* queue)
{
if(isEmpty(queue))
return 0;
int x = queue->arr[queue->front];
queue->front= (queue->front+1)%queue->capacity;
queue->size-=1;
}
int front (Queue* queue)
{
if(isEmpty(queue))
return 0;
return queue->arr[queue->front];
}
int rear (Queue* queue)
{
if(isEmpty(queue))
return INT_MIN;
return queue->arr[queue->rear];
}
int main()
{
Queue* queue=new Queue();
enqueue(queue,10);
enqueue(queue,20);
enqueue(queue,30);
enqueue(queue,40);
cout << "Front item is "
<< front(queue) << endl;
cout << "Rear item is "
<< rear(queue) << endl;
}
Your code have at least 3 problems:
Firstly,
Queue* queue=new Queue();
will lead to compilation error because no default constructor is defined and another constructor is defined in the class Queue.
To fix this, you should do one of:
Change this line to match the defined constructor like Queue* queue=new Queue(1024);
Add default constructor to the class Queue
Add default value of the argument c for the constructor of the class Queue like Queue(int c = 1024)
Secondly, the function dequeue have an execution path in which the execution reach at end of funciton without executing any return statement.
It seems return x; should be added at end of the function.
Thirdly, the line
int *arr= new int[c*sizeof(int)];
is bad because:
This stores the pointer to local variable that will vanish at end of this constructor instead of the member variable.
You don't need to multiply sizeof(int) because what to specify is the number of elements to allocate, not number of bytes.
The line should be
arr= new int[c];
I'm passing an array to a constructor. Constructor has two parameters, pointer to int called data and int which is size of an array.
I'm allocation dynamic memory in constructor definition for this array and passing array pointer to this storage.
Last but one step is printing values in array through the pointer which is pointing to the first int value of this array.
The last step is freeing up memory in destructor delete [] data. In this step I got an error message: Debug Assertion Failed! Expression: _CrtlsValidHeapPpinter(block).
I'm very new in C++ so I'm struggling what I did wrong in below program. Could you give me a hint, please?
#include <iostream>
class Test
{
private:
int* data;
int size;
public:
// constructor and destructor
Test(int* d, int s);
~Test();
// few void methods
void display_data(int size)
{
for (int i{ 0 }; i < size; ++i)
{
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
Test::Test(int* d, int s)
: data{nullptr}, size(s)
{
data = new int[s];
data = d;
}
Test::~Test()
{
std::cout << "Destructor is freeing memory" << std::endl;
delete[] data;
}
int main()
{
int data_array[5]{ 2,8,6,10,20 };
Test* t1 = new Test(data_array, 5);
t1->display_data(5);
delete t1;
return 0;
}
In yout Test::Test constructor you don't copy the array, you just copy the pointer. You need to use std::copy or memcpy (C-style) to copy the contents of d into data.
However, I would recommend to use STL containers (i.e., std::vector) instead of raw pointers. It will allow you to get rid of manual resource management (new/delete), which is error-prone and redundant.
You need to copy the data here. Instead of :
data = new int[s];
data = d;
Which creates an array and then forgets about it. This would lead to the array being deleted multiple times!
Copy the content of your array:
std::copy(d, d+s, data);
Or even better, use std::vector.
Hello stackoverflow
so my question is: I want to make a function to generate the array of structures but i get an error whenever i finish inserting the values what is the problem?
like so
struct INFO
{
char name[20]; // creating the strucure
int age;
};
void generateArr(INFO *p); // a function to generate the array
void readArr(INFO *p); // a function to read the array
int main()
{
INFO *ptr =new INFO; // a pointer that points to the structure
generateArr(ptr); // calling the functions
readArr(ptr);
delete[]ptr; // deallocating memory
}
void generateArr(INFO *p)
{
p = new INFO [3]; // generating three INFO structures
}
void readArr(INFO *p)
{
for (int i = 0; i < 3; i++)
{
cin >> p[i].name>> p[i].age; // inputting the elements
cout << endl;
}
}
I tried to make the code as clear as possible, ask me if anything is ambiguous.
This function :
void generateArr(INFO *p)
{
p = new INFO [3]; // generating three INFO structures
}
is not working as you expect it does. It assigns allocated memory to local 'p` parameter, which is not returned to a main. To fix it change p to reference:
void generateArr(INFO *&p)
[edit]
but since you already assigned ptr in main with INFO *ptr =new INFO;, you will get a memory leak this way. So you should remove that line.
In generateArr(INFO *p), you allocate an array which address is stored in local variable p; on return from the function, any local variable (such as p) is lost, as long as address of the allocated array.
You should get rid of function generateArr(INFO *p), which is useless, and allocate your array into main(), this way :
int main()
{
INFO *ptr =new INFO[3];
readArr(ptr);
delete[]ptr; // deallocating memory
}
Rewrite the functions at least the following way
INFO * generateArr( size_t n )
{
return new INFO [n]; // generating three INFO structures
}
void readArr(INFO *p, size_t n )
{
for (int i = 0; i < n; i++)
{
cin >> p[i].name>> p[i].age; // inputting the elements
cout << endl;
}
}
and in main call them like
const size_t N = 3;
INFO *ptr = generateArr( N ); // a pointer that points to the structure
readArr( ptr, N );
delete []ptr; // deallocating memory
As for your code then in this statement
INFO *ptr =new INFO; // a pointer that points to the structure
there is allocated only one object of the structure type however it is deleted using operator delete [] instead of the operator delete.
delete[]ptr; // deallocating memory
And inside this function
void generateArr(INFO *p)
{
p = new INFO [3]; // generating three INFO structures
}
there is a memory leak because variable p is a local variable of the function that was initialized by the value of the function's argument and that will be destroyed after exiting the function. As result the address of the dynamically allocated memory will be lost.
This realization of linked list is broken. Address of nodes[0].next doesn't match the nodes[1] address. So nodes[1].next is NULL (as default value). I added some address printing to the search method. It looks like the nodes[1] wasn't initialized?
#include <iostream>
#include <vector>
using namespace std;
typedef struct Node_T {
int data;
Node_T *next;
} Node;
class LinkedList{
public:
vector<Node> nodes;
LinkedList(){
}
void insert(int data) {
Node temp_node;
temp_node.data = data;
temp_node.next = NULL;
size_t len = nodes.size();
nodes.push_back(temp_node);
if (len > 0) {
nodes[len - 1].next = &nodes[len];
}
}
int search(int val){
if (nodes.empty())
return -1;
Node *node_ptr = &nodes[0];
// Debug
cout << &nodes[1] << "\n";
cout << &nodes[0].next << "\n";
int i = 0;
do {
if (node_ptr->data == val) return i;
i++;
} while((node_ptr = node_ptr->next) != NULL);
return -1;
}
};
int main()
{
LinkedList llist;
llist.insert(1);
llist.insert(2);
llist.insert(3);
llist.insert(4);
llist.insert(5);
cout << llist.search(3) << "\n";
return 0;
}
It shows me: 0x8e6a060 0x8e6a05c -1
When you add elements to a vector, references to (and hence addresses of) vector elements are invalidated. You must therefore not use values such as &nodes[0] or &nodes[len], as they are meaningless.
The point with an exercise like this is to get the hang of the internal structure in a linked list. You have replaced that internal structure with a vector<Node>.
Instead of a vector, the idea is to have a
private:
Node* head;
As you data member.
In your insert function you are supposed to dynamically allocate memory for the Node with
Node* newNodePointer = new Node;
And manipulate the pointer with next and such.
It is worth to point out, that this is fine as an exercise, but your "real" code should use standard library facilities.
First, Your printout is incorrect: this line
cout << &nodes[0].next << "\n";
prints the address of next, rather than printing the next itself. Changing to
cout << nodes[0].next << "\n";
gives the correct printout (demo).
However, the main issue is that you keep pointers to elements of std::vector. These become invalid after the first write, because new storage gets allocated for the growing vector.
You can certainly work around this by reserving sufficient space upfront (call nodes.reserve(1000) from the constructor of your list; demo) but that is merely a hack: you should use new and delete to allocate elements of your linked list manually. That is the whole point of this exercise.
But I still need a container to ensure that nodes will be live as expected?
No, you do not. Your class is a container. By referencing the whole chain of nodes from the head pointer it can ensure that the entire chain is kept "live".
so I'm currently trying to migrate my Java experience to C++ by implementing various Data Structures for the sake of having them implemented at least once.
Would you mind giving me some advise? The problem I am having is mainly concentrated around the pointers in push(int value) and especially pop(). As push seems to be working correctly I found myself struggling to get the correct value back when pop'ing things. What's the matter?
PS: I also think, that since I allocate my array space manually I'd need to delete it aswell. How do I do that?
#ifndef STACK_H
#define STACK_H
class Stack
{
private:
int *stackArray;
int elementsInArray;
int allocatedArraySize;
int alpha;
int beta;
public:
Stack();
void push(int aValue);
int pop();
bool isEmpty();
int size() const;
};
#endif
and the implementation:
#include <iostream>
#include "Stack.h"
Stack::Stack()
{
alpha = 4;
beta = 2;
elementsInArray = 0;
allocatedArraySize = 1;
stackArray = new int[1];
}
void Stack::push(int aValue)
{
if (elementsInArray == allocatedArraySize)
{
int temporaryArray[allocatedArraySize*beta];
for (int i = 0; i < elementsInArray; i++)
temporaryArray[i] = stackArray[i];
stackArray = temporaryArray;
allocatedArraySize *= beta;
}
elementsInArray++;
stackArray[elementsInArray] = aValue;
}
int Stack::pop()
{
int result = -INT_MAX;
if (elementsInArray == 0)
return result;
if (elementsInArray > 0)
{
result = stackArray[elementsInArray-1];
elementsInArray--;
if (elementsInArray <= allocatedArraySize/alpha)
{
int temporaryArray[allocatedArraySize/alpha];
for (int i = 0; i < elementsInArray; i++)
temporaryArray[i] = stackArray[i];
stackArray = temporaryArray;
allocatedArraySize /= beta;
}
}
return result;
}
bool Stack::isEmpty()
{
if (elementsInArray == 0)
return true;
return false;
}
int Stack::size() const
{
return allocatedArraySize;
}
For starters, you should be post incrementing the index on the array, so change:
elementsInArray++;
stackArray[elementsInArray] = aValue;
to:
stackArray[elementsInArray++] = aValue;
or:
stackArray[elementsInArray] = aValue;
elementsInArray++;
Second, when you create the new temp array you are doing it inside the if statement... therefore it is a local variable and placed on the system stack and lost after you exit the if statement. So change
int temporaryArray[allocatedArraySize*beta];
to:
int *temporaryArray = new int[allocatedArraySize*beta];
Third, add in the delete you were talking about by saving the original pointer from stackArray before copying the location of tempArray and then perform the delete after you've made the pointer copy.
Finally, you'll have to make similar changes to your pop function...
You are using an array on the stack (not your stack - the program execution stack). It's the one called temporaryArray in your push function. The address of that array will be invalid when you return from that function (because other functions will use the stack to hold other data).
what you want to do is allocate that array on the heap. This is memory that stays around for your program as long as you need it. To do this, you would allocate your temporaryArray like
int * temporaryArray(new int[allocatedArraySize*beta]);
Then, after copying the elements from your old array, you would delete it by using:
delete [] stackArray;
Do this before assigning the stackArray with the temporaryArray.
There may be other issues with your data structure, but you are doing the basic indexing correctly and incrementing / decrementing the current index appropriately (though I would suggest preferring to use the preincrement / decrement forms when not using the temporary as a good habit to get in - ie. ++elementsInArray / --elementsInArray).
well, i'm sure you already know that you have stack as a generic (c++ call it templates) in the STD library. Assuming you are doing this as a code kata, i would start writing it as a template, so it can't take object types others than integers.
Also, if you are going to write more of these low-level structures (as part of your kata), write a thin class where you delegate all allocation, reallocation and allocated size tracking, and use that instead of using arrays directly.