Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &
Related
I have a class array inside which I have declared an array its size and length. I am trying to merge two sorted arrays by creating the third array on the heap and both the sorted array will be merged on the third array. But whenever I create a new arr on heap the compiler gives me this error: request for member '..' in '..' which is of non-class type
class Array
{
public:
int A[10];
int length;
int Size;
};
void display(Array arr)
{
int i;
for(i=0;i<arr.length;i++)
{
cout<<arr.A[i]<<" ";
}
}
void Merge(Array *arr1,Array *arr2)
{
int i,j,k;
i=j=k=0;
int *arr3;
arr3=new int[10];
while(i<arr1->length && j<arr2->length)
{
if(arr1->A[i]<arr2->A[j])
arr3->A[k++]=arr1->A[i++];
else
arr3->A[k++]=arr2->A[j++];
}
for(;i<arr1->length;i++)
{
arr3->A[k++]=arr1->A[i];
}
for(;j<arr2->length;j++)
{
arr3->A[k++]=arr1->A[j];
}
}
int main()
{
Array arr1{{1,3,5,7},4,4};
Array arr2{{2,4,6,8},4,4};
Array *arr3;
arr3=Merge(&arr1,&arr2);
display(*arr3);
return 0;
}
The root cause of all your problems is that you use C-Style array with a magical size 10. Like in int A[10];. This is a major problem and should be avoided in C++.
Additionally, and the same, In C++ we usually do not use raw pointer for owned memories or newand such stuff.
Anyway. The design will never work, if the number of elements in both Array classes is greater then 5. Because then you will definitely get an out of bounds problem.
You must use a std::vector.
So, all bad. But I know that I will hear now, that the teacher said, no vector but new. The teacher should be fired or begin to teach C instead of C++.
Anyway again, I will fix the major bugs for you. But the sorting algorithm will work neither.
So,
If you want to return an Array, then change the signature of your function aand return an Array.
You do want to have a new Array, not new intes. So, please allocate a new Array instead.
Do not forget to release the newed Arrary at then end.
Set size and length of the new array.
Refactor your complete code.
Code example with some fixes:
#include <iostream>
class Array
{
public:
int A[10];
int length;
int Size;
};
void display(Array arr)
{
int i;
for (i = 0; i < arr.length; i++)
{
std::cout << arr.A[i] << " ";
}
}
Array* Merge(Array* arr1, Array* arr2)
{
int i, j, k;
i = j = k = 0;
Array *arr3 = new Array;
while (i < arr1->length && j < arr2->length)
{
if (arr1->A[i] < arr2->A[j])
arr3->A[k++] = arr1->A[i++];
else
arr3->A[k++] = arr2->A[j++];
}
for (; i < arr1->length; i++)
{
arr3->A[k++] = arr1->A[i];
}
for (; j < arr2->length; j++)
{
arr3->A[k++] = arr1->A[j];
}
arr3->length = arr1->length + arr2->length;
return arr3;
}
int main()
{
Array arr1{ {1,3,5,7},4,4 };
Array arr2{ {2,4,6,8},4,4 };
Array* arr3;
arr3 = Merge(&arr1, &arr2);
display(*arr3);
delete[]arr3;
return 0;
}
I have an array called int **grid that is set up in Amazon::initGrid() and is made to be a [16][16] grid with new. I set every array value to 0 and then set [2][2] to 32. Now when I leave initGrid() and come back in getGrid() it has lost its value and is now 0x0000.
I don't know what to try, the solution seems to be really simple, but I'm just not getting it. Somehow the data isn't being kept in g_amazon but I could post the code.
// Returns a pointer to grid
int** Amazon::getGridVal()
{
char buf[100];
sprintf_s(buf, "Hello %d\n", grid[2][2]);
return grid;
}
int Amazon::initGrid()
{
int** grid = 0;
grid = new int* [16];
for (int i = 0; i < 16; i++)
{
grid[i] = new int[16];
for (int j = 0; j < 16; j++)
{
grid[i][j] = 0;
}
}
grid[2][2] = 32;
return 0;
}
int **grid;
g_amazon = Amazon::getInstance();
g_amazon->initGrid();
grid = g_amazon->getGridVal();
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int index;
index = (width * 4 * i) + (4 * j);
int gridval;
gridval = grid[i][j];
lpBits[index] = gridval;
lpBits[index + 1] = gridval;
lpBits[index + 2] = gridval;
}
}
It crashes when I run it at the line where sprintf_s prints out [2][2] and it also crashes when I get to gridval = grid[i][j] because it's at memory location 0x000000.
The variable
int** grid
in the initGrid() function is a local variable. Edit** When the function returns the variable is popped off the stack. However, since it was declared with the new operator the memory still exists on the heap; it is simply just not pointed to by your global grid variable.
#Dean said in comment:
I have grid as an int** grid; in class Amazon {}; so shouldn't it stay in memory or do I need a static var.
That is the problem:
local int **grid; on Amazon::initGrid::
is masking
member int **grid; on Amazon::
as the first context has higher priority in name lookup.
So initGrid() allocates memory referenced only by a local pointer. That pointer no longer exists when you return from this function, Amazon::grid was never touched on initialization and you're also left with some bad memory issues.
So, as commented by #Remy-Lebeau, I also suggest
Consider using std::vector> or std::array, 16> instead. There is no good reason to use new[] manually in this situation.
I am trying to implement a class template for an Array class that should provide a method to count elements equal to a given element, but I get wrong results. This is my code:
main.cpp
#include <iostream>
#include "array.h"
int main() {
int arr[] = {1, 2, 3, 2, 5, 2};
char brr[] = {'a', 'b', 'c', 'd', 'a'};
Array<int> A(arr, 6);
Array<int> B(0, 7);
Array<char> C(brr, 5);
std::cout << A.getCount(2) << std::endl;
std::cout << B.getCount(0) << std::endl;
std::cout << C.getCount('a') << std::endl;
return 0;
}
array.h
template <typename T> class Array {
private:
T* ptrStart;
int size;
public:
Array() {
this->ptrStart = nullptr;
this->size = 0;
}
Array(T defaultValue, int size) {
T arr[size];
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr;
}
Array(T* arr, int size) {
this->size = size;
this->ptrStart = arr;
}
int getCount(T);
};
template <typename T> int Array<T>::getCount(T element) {
int count = 0;
for (int i = 0; i < this->size; i++) if (this->ptrStart[i] == element) count++;
return count;
}
expected output:
3
7
2
actual output:
3
0
2
Both of these functions are invalid:
Array(T defaultValue, int size) {
T arr[size];
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr;
}
Array(T* arr, int size) {
this->size = size;
this->ptrStart = arr;
}
The first function sets the data member ptrStart to a local variable arr that will not be alive after exiting the function.
The second function should dynamically allocate an array and copy elements from the array pointed to by arr.
For example, the second function can be defined the following way:
Array( const T *arr, int size) : ptrStart( new T[size] ), size( size ) {
for ( int i = 0; i < size; i++ )
{
ptrStart[i] = arr[i];
}
// or you can use standard algorithm std::copy
}
Also, you need to include a destructor and either make the class uncopyable or define at least the copy constructor and copy assignment operator.
This is an error
Array(T defaultValue, int size) {
T arr[size];
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr;
}
The array arr only exists in the constructor. When the constructor exits the array no longer exists. But ptrStart is pointing to this array even after it has been destroyed. So you get unpredictable results.
In C++ you must always think about the lifetime of objects. Objects don't keep existing just because a pointer is pointing at them (this is different in some other languages). If you have a pointer pointing at an object which no longer exists, that is called a dangling pointer. In your code ptrStart is a dangling pointer (when you use this particular constructor).
Also T arr[size]; is not legal C++ since in C++ array sizes must be compile time constants and size is a variable.
Array(T defaultValue, int size) {
T arr[size];
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr;
}
Here you set ptrStart to point at the local variable in a function. Once that function is done, the pointer is dangling and you have Undefined Behavior. Your program might crash, format your hard drive, output one or more wrong values or, possibly, output the right value.
Your constructor
Array(T defaultValue, int size) {
T arr[size];
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr;
}
has at least 2 problems.
First T arr[size] is not standard C++ but uses a compiler extension. Also it is a local variable and this->ptrStart = arr; only assigns its adress to the member. Note that arr is an array, not a pointer, but it can decay to a pointer.
The problem lies in this function:
Array(T defaultValue, int size) {
T arr[size]; // Create array on stack - it will be deleted when the function returns
for (int i = 0; i < size; i++) arr[i] = defaultValue;
this->size = size;
this->ptrStart = arr; // Storing address to array which won't exist after this line
}
After the function returns the pointer this->ptrStart points to some random place in memory and at the point when you call B.getCount(0), it can be pretty much any data in there. Reading memory pointed by that dangling pointer is an Undefined Behavior. If you are unlucky, this can even cause a runtime exception, not only wrong result. (Or maybe it is lucky, at least the result isn't wrong ;) )
To fix that problem, you should use operator new to create the array. This way, the array will be created on heap instead of stack.
T arr[size]; // bad
T *arr = new T[size]; // good
Heap is not cleared when function returns.
This mean it is safe to use array from heap outside of the function it was created in.
Unfortunately, it also mean you need to delete it manually in the destructor of Array.
~Array() {
if (createdInConstructor)
delete[] this->ptrStart;
}
createdInConstructor is a new bool field of the class so the destructor don't try to delete the array in case of objects A & C.
You could also use a smart pointer to achieve that a little easier.
I am trying to shrink an array of *bool but I am not sure if it is being deleted correctly.
This is my source code...
bool *oldStore;
void shrinkArray(int i)
{
int k;
bool *newStore;
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
for(; k<originalSize; k++)
{
delete[] oldStore[k];
}
delete[] oldStore;
oldStore = newStore;
}
For example, if I wanted to shrink the array to 5 and the original size of the array was 15, it would keep the first five and delete the last ten, however I am not too sure if my memory is being managed correctly.
Think about you method design before going into the coding specifics. I assume you have an ínt array that you new somewhere in your code.
Think about who "owns" this array? It's probably no good idea to create the int array at some place and to simply delete[] it somewhere else. Check out the following links: What is a smart pointer and when should I use one?
Think about what should happen to your newStore array. Is it supposed to replace the oldStore or do you want both arrays to exist in parallel. If you simply put the newStore on the heap who/when and where are you going to delete[] it again.
Simplest code would be:-
void shrinkArray(int i)
{
int k;
bool *newStore = new bool[i];
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
delete [] oldStore; //assuming oldstore was allocated using new []..
oldStore = newStore;
}
Your code is wrong. You declared pointer newStore but neither initialize it nor allocated memory that would be pointed to by this pointer
bool *newStore;
So the next loop has undefined behaviour.
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
Moreover if each element of the array pointed to by pointer oldStore has type bool * that is in turn is a pointer then oldStore itself shall have type bool **
If so then the correct function could look like
void shrinkArray( int n )
{
if ( n < originalSize )
{
bool **newStore = new bool * [n];
int i = 0;
for ( ; i < n; i++ ) newStore[i] = oldStore[i];
for ( ; i < originalSize; i++ ) delete oldStore[i];
delete [] oldStore;
oldStore = newStore;
originalSize = n;
}
}
Take into account that oldStore also shall have type bool **.
Otherwise if each element of the original array has type bool then the code will look like
void shrinkArray( int n )
{
if ( n < originalSize )
{
bool *newStore = new bool [n];
int i = 0;
for ( ; i < n; i++ ) newStore[i] = oldStore[i];
// Or
// std::copy( oldStore, oldStore + n, newStore );
delete [] oldStore;
oldStore = newStore;
originalSize = n;
}
}
Take into account that it would be much better and simpler to use standard container std::vector<bool *> or std::vector<bool> depending on the type of the element of the container.
Constructor
This is how I'm allocating it:
char **board = new char*[width];
for(i = 0; i < width; i++){
board[i] = new char[height];
for(j = 0; j < height; j++)
board[i][j] = 0;
}
this->board = &board;
Inside the class, it's:
char ***board;
Destructor:
Now I want to delete it, so I wrote this (the board it the class field):
for(i = 0; i < width; i++)
delete (*board)[i];
delete (*board);
When running this:
Board* b = new Board(16, 30, 99);
delete b;
I get an Unhandled exception. Why?
You are storing a pointer to a variable on the stack, which becomes invalid as soon as the constructor returns. You should declare your class's data member as char **board and assign this->board = board.
EDIT: See also #Kerrek SB's comment. The local variable is redundant. Just use the data member directly (without the this->).
EDIT 2: Rectangular arrays are best created as a single array, using pointer arithmetic to index (which is what the compiler does with declared 2D arrays anyway):
char *board;
...
board = new char[width*height];
for(i = 0; i < width*height; ++i){
board[i] = 0;
}
...
char& operator()(int i, int j) { return board[width*i + j]; }
This has the advantage of requiring just one memory allocation (and therefore one delete[]). It also improves cache locality because the cells are contiguous.
Even better, if you know the dimensions at compile-time, use templates:
template <int W, int H>
class Board {
char board[W][H];
...
};
...
Board<8, 8>* b = new Board<8, 8>(...);
This requires no memory allocation at all (other than the new Board, of course).
Anything that you new you need to delete, in the exact same way:
board = new char*[width];
...
board[i] = new char[height];
...
...
delete[] board[i];
delete[] board;
No dereferencing is needed in this case.
You should use the powers of C++.
class Board
{
std::vector<std::vector<char>> board;
public:
Board(std::vector<std::vector<char>> const& board) : board(board) {}
Board(size_t x, size_t y, char val = 0)
{
std::vector<char> x2(x, val);
this->board(y, x2);
}
};
All you've got to do now is board[y].push_back(char_x_val) in order to append a new element to the end. You can treat board[y][x] just like any other 2D array (well, almost), but not worry about the deallocation.
Read up more on vectors here. (Anyone know a good tutorial?)