Trying to copy a 2D dimensional array of objects to another function - c++

I'm trying to copy an array from one class to to another class by passing it to a function but I'm running into issues. The array that I'm trying to copy seems to lose all its data.
// A.h
class A
public:
virtual void Test();
private:
A* array2D[30][32];
// A.cpp
void A::Test()
{
B* f = new B();
f->pass(array2D);
}
// B.h
class A;
class B
{
public:
void pass(A *a[][32]);
private:
A *a[30][32];
}
// B.cpp
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++)
{
for (int j = 0; j <= 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.

My guess is that it's happening when I'm passing it but I'm not sure what I'm doing wrong.
First, your for loops to populate the array go out-of-bounds on the last iteration of the nested for loop:
void B::pass(A *array2D[][32])
{
for (int i = 0; i <= 30; i++) // This goes out-of-bounds on the last iteration
{
for (int j = 0; j <= 32; j++) // This also goes out-of-bounds.
{
a[i][j] = array2D[i][j];
}
}
}
Using <= in a for loop is an indication that things can go wrong, and they do go wrong with your code. The fix would simply be:
void B::pass(A *array2D[][32])
{
for (int i = 0; i < 30; i++)
{
for (int j = 0; j < 32; j++)
{
a[i][j] = array2D[i][j];
}
}
}
This will work, however it is inefficient (unless a great optimizing compiler sees that this is inefficient and changes the code).
The better way to do this is a simple call to std::copy:
#include <algorithm>
void B::pass(A *array2D[][32])
{
std::copy(&array2D[0][0], &array2D[29][32], &a[0][0]);
}
The reason why this works is that two-dimensional arrays in C++ have their data layout in contiguous memory, thus it is essentially a one-dimensional array. So giving the starting and ending address of the array elements is all that's required.
A compiler will more than likely see that you are copying a trivially-copyable type (a pointer), thus the call to std::copy results in a call to memcpy.

Related

Allocating pointer to a pointer

I have 5 buffers and 20 frames to write in them. Being one frame per buffer, at a certain moment i will have to overwrite buffers with the newest frame.
At random moments i need to read the oldest frame(its id and data) from all the buffers.
I am obliged to use a pointer to a pointer for my buffers, but since i suck at pointers, not even the allocation works, giving me a SEGMENTATION FAULT and not sure why.
What i have until now:
void fakeFrame(uint16_t *data)
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
int main()
{
uint16_t **p_frameBuffers;
uint32_t *p_frameIdxs;
uint16_t wrIdx = 0;
uint16_t reIdx = 0;
uint16_t currentFrameCounter = 0;
uint16_t nbBuffers = 5;
for(auto i =0; i< nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}
while(currentFrameCounter <= 20)
{
wrIdx++;
wrIdx %= nbBuffers;
if(wrIdx == reIdx)
{
std::cout<<"i passed the limit";
}
currentFrameCounter++;
p_frameIdxs[wrIdx] = currentFrameCounter;
fakeFrame(p_frameBuffers[wrIdx]);
}
std::cout<<"\n";
return 0;
}
I can see a few different problems with this code here.
You declare the long-form of the function for fakeFrame() in the beginning of the program, when the standard is usually to declare the function header first.
This is like a warning to the program that a function is about to be used, and that it's not part of a class or anything. Just standalone.
Example:
#include <iostream>
void fakeFrame();
int main()
{
return 0;
}
void fakeFrame()
{
for (auto i = 0; i < 1440; i++)
for (auto j = 0; j < 1440; j++)
data[(i * 1440) + j] = std::rand()%2;
}
You're also using some of these 16 and 32 bit unsigned ints as if they were arrays, so I was deeply confused about that. Did you mean to set them as arrays?
You also have some variables being declared in a non-array context but being used as arrays. I'm not deeply familiar with the uint variable/object types but I know they aren't usually meant to function as standalone arrays.
Also, no variable called m_pFrameBuffers is actually declared in the code you provided. Plus this is also used as an array, so it should really be declared as one.
I hope this provides at least some insight into what's not working. I'm actually kind of surprised that the void function ran before, it's improperly formatted.
In the end this is what did it: the pointer to a pointer is actually an array of pointers (which i did not know, of course)
p_frameBuffers = (uint16_t**)malloc((sizeof(uint16_t*)*nbBuffers));
for(auto i = 0; i < nbBuffers; i++)
{
p_frameBuffers[i] = (uint16_t*)malloc(1440*1440*2);
}

Scope of dynamic (multidimm) array when initialized with pointer and new

I'm royally confused right now. I have seen similar questions asked, and my implementation seems to be along the lines of these solutions, but I just can't get it to work.
I need to have a UtilClass that can initialize and dump a multi-dimensional dynamic array. I just want to pass the pointer the the array in BaseClass that I want initialized along with the dims. I chose to use the new keyword instead of malloc(), but I'm worried that the scope of the pointers is limited to the init function and not to the lifetime of the BaseClass (or the array pointer for that matter) and that's why the dump function produces a SEGFAULT.
Here is some code to explain:
// BaseClass.h
#pragma once
include "UtilClass.h"
class BaseClass
{
public:
UtilClass* util{nullptr};
double** array{nullptr};
};
// BaseClass.cpp
#include "BaseClass.h"
BaseClass::BaseClass() {
util = new UtilClass();
util->init(array, 4, 6);
util->dump(array, 4, 6);
}
// UtilClass.h
#pragma once
class UtilClass {
void init(double** array, int rows, int cols);
void dump(double** array, int rows, int cols);
};
// UtilClass.cpp
#include "UtilClass.h"
void UtilClass::init(double **darray, int rows, int cols) {
int i,j;
array = new double*[rows];
for (i = 0; i < rows; i++)
array[i] = new double[cols];
for (i = 0; s < rows; i++)
for (j = 0; a < cols; j++) {
data[i][j] = 1;
std::cout << "Data in array " << data[i][j] << std::endl; // This obviously works
}
}
void dump(double** array, int rows, int cols) {
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
std::cout << array[i][j] << " "; // But this produces a SEGFAULT
std::cout << std::endl;
}
Let me start off with a piece of advice: it's best to reuse existing tools. Consider using std::vector for dynamically-allocated array. This is well tested, optimized and easy to use. Otherwise, you'll need to deal with conundrums of memory management (e.g. deallocate the allocated chunks of memory in the dtor of BaseClass).
Regarding your question: when you call init, you pass the pointer by value. This means that the init method allocates some memory and stores the pointer to it in its local copy of darray. At the end of init this local variable is gone (you lose access to it, leaking whole allocated memory). Change the method to:
void UtilClass::init(double ***array, int rows, int cols) {
int i,j;
*array = new double*[rows];
for (i = 0; i < rows; i++)
(*array)[i] = new double[cols];
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++) {
(*array)[i][j] = i*j;
std::cout << "Data in array " << (*array)[i][j] << std::endl; // This obviously works
}
}
When calling dump, you need to pass 4 and 6 (and not 5 and 6).

I am having a bad access issue

I am trying to create a merge function for two array structures in c++ but am coming up with a bad access error that I don't know how to solve. The error comes up when I am trying to swap the element in the smaller array into the larger, merged array. The code doesn't even go through a single iteration. All three of i, j, and k remain at 0. Any help would be greatly appreciated! Here is the code:
struct Array
{
int *A;
int size;
int length;
};
void display(Array arr){
for (int i = 0; i < arr.length; i++)
std::cout << arr.A[i] << std::endl;
}
Array merge(Array arr1, Array arr2){
Array arr3;
arr3.length = arr1.length + arr2.length;
arr3.size = arr1.length + arr2.length;
int i = 0, j =0, k =0;
while(i <arr1.length && j < arr2.length){
if (arr1.A[i] < arr2.A[j])
{
arr3.A[k] = arr1.A[i]; //(The error is displayed here: Thread 1: EXC_BAD_ACCESS (code=1, address=0x28))
k++;
i++;
}
else if (arr2.A[j] < arr1.A[i])
{
arr3.A[k] = arr2.A[j];
k++;
j++;
}
}
for (; i< arr1.length; i++)
{
arr3.A[k]=arr1.A[i];
k++;
}
for (; i< arr2.length; j++)
{
arr3.A[k]=arr2.A[j];
k++;
}
return arr3;
}
int main() {
Array arr1;
arr1.size = 10;
arr1.length = 5;
arr1.A = new int[arr1.size];
arr1.A[0]= 2;
arr1.A[1]= 6;
arr1.A[2]= 10;
arr1.A[3]= 15;
arr1.A[4]= 25;
Array arr2;
arr2.size = 10;
arr2.length = 5;
arr2.A = new int[arr2.size];
arr2.A[0]= 3;
arr2.A[1]= 4;
arr2.A[2]= 7;
arr2.A[3]= 18;
arr2.A[4]= 20;
Array arr3 = merge(arr1, arr2);
display(arr3);
return 0;
}
Your Array arr3 does not allocate any memory for its int *A field. It's natural that it would not work.
Anyway, your implementation of Array is very poor. Don't reimplement arrays unless you have a good reason; use std::vector instead.
If you really need to implement an Array on your own, then learn about encapsulation, make a class with a constructor, and allocate/delete your data (*A) field properly. Remember, using pointers and heap memory without understanding them is a recipe for disaster.
Easy: arr3.A is not initialized. It's a pointer. What does it point to?
Suggestion: learn about dynamic memory allocation.

How can return a matrix pointer in c++?

I have a big problem, i want to put a matrix pointer of objects to a function but i don't know how can do this, the objects that i use they are from derived class. This is an example of my code. Note: class Piece is a base class and class Queen is a derived class from Piece
#include "Queen.h"
void changeToQueen(Piece* mx)
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
mx[i][j] = new Queen();
}
}
}
int main()
{
Piece * matrix[7][7];
changeToQueen(matrix); // this fails
return 0;
}
You can change the input argument to void changeToQueen(Piece * mx[7][7]).
Or you can change the input argument to void changeToQueen(Piece** mx).
Change the assignment operator to mx[7*i + j] = new Queen(); and pass in the first element as input changeToQueen(&(matrix[0][0]));
The reason why both work is because multidimensional array elements are stored contiguously in memory. So all you need is a pointer to the first element.
Both solutions are a bit flawed because if you need to change the dimensions of your matrix, you have to change your code a bit. Changing your prototype to void changeToQueen(Piece** mx, size_t width, size_t height) will be helpful for the future.
Alternatively this could be a way to handle things
template <unsigned int rows, unsigned int columns>
class Board
{
public:
Board() {}
void changeToQueen()
{
for (unsigned int y = 0 ; y < rows ; ++y)
{
for (unsigned int x = 0 ; x < columns ; ++x)
{ _pieces[y][x] = Queen(); }
}
}
Piece &at(unsigned int row, unsigned int column)
{ return _pieces[row][column]; } // you should check for out of range
// you could either have a default null value for Piece to return, or throw an exception
private:
Piece _pieces[rows][columns];
};
int main()
{
Board<8,8> board;
board.changeToQueen();
// return 0; // this is not mandatory in c++
}
So, yeah, no pointers almost no worries ;)
You still want pointers?? uhm... okay maybe you could do that: Piece *_pieces[rows][columns];, i'm not sure you really need it, but I can't tell how much it would modify your existing code to do this.
First of all, I do not understand dependencies between Queen and Piece, so I suppose that Piece is super-type of Queen and assignment Piece * mx = new Queen(); is correct.
To fix the obvious problem of type mismatch you can change your
void changeToQueen(Piece* mx)
to
void changeToQueen(Piece* mx[7][7])
and with changing loops border to 7 (for (int i = 0; i < 7; i++)) or size of matrix to 8 x 8 (with the same loops) this will work.
But my suggestion is to think over method of storing data.
Perhaps you will need to build matrix of size different from 7x7, so consider the following example, where dynamic memory is used to store the matrix (in this example only Queen is used):
void changeToQueen(Queen*** &mx, int size)
{
mx = new Queen**[size]; // allocation of memory for pointers of the first level
for (int i = 0; i < size; i++)
{
mx[i] = new Queen*[size]; // allocation of memory for pointers of the second level
for (int j = 0; j < size; j++)
{
mx[i][j] = new Queen(); // allocation of memory for object
}
}
}
int main()
{
int m_size = 7;
Queen *** matrix = NULL; // now memory not allocated for matrix
changeToQueen(matrix, m_size);
return 0;
}
Note: & sign in void changeToQueen(Queen*** &mx, int size) allows to change pointer Queen *** matrix; inside the function changeToQueen

C++ pointer to int in loops?

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 &