C++ Set 2d array sizes of class member array in constructor - c++

I only found solutions for 1d arrays, but couldn't apply them to 2d arrays.
The possible solutions included "vectors", "templates", and "pointers to arrays".
I know I can get vectors to work, but I would rather use either of the other 2. Preferably templates because I don't want to manually destruct, but pointers work too. (the pointer would be pointed to an array created in the constructor).
The class contains an empty 2d array called screen. The constructor is supposed to set its size. I tried too many things for me to list them all here, but I'll show what I currently have. (last thing i tried were pointers to arrays created in the constructor. in this case screen was a char pointer)
Screen::Screen(const int w, const int h) : screen(new char[h][w]) {} {
width = w;
height = h;
}
array size in new-expression must be constant
I failed implementing either of those strategies and received many kinds of errors while trying to make it work. How would I solve this problem? (primarily I want to know how to do this with templates. if not possible then with pointers to arrays created in the constructor)

The question was a little ambiguous, but it sounds like you want to dynamically allocate an array given some input.
Edit I changed the answer to match the code you provided. This creates a 2d array of chars given the height and width.
class Screen {
private:
char **data;
int rows;
int columns;
public:
Screen(int num_rows, int num_cols);
};
Screen::Screen(int num_rows, int num_cols) {
data = new char * [num_rows];
for (int i = 0; i < num_rows; ++i) {
data[i] = new char[num_cols];
}
rows = num_rows;
columns = num_cols;
}
This creates an empty 2D array of chars.
Explanation: All arrays in c are just pointers to the first block in memory of the type you have declared. By having the member variable as double pointer, you have an array of char pointers, which each point to the first value in each of their respective arrays.
BUT be careful, you WILL need to free the data variable to avoid memory leaks, by declaring a destructor.
Screen::~Screen() {
for (int i = 0; i < rows; ++i) {
delete[] data[i];
}
delete[] data;
}

Related

Helper function to construct 2D arrays

Am I breaking C++ coding conventions writing a helper function which allocates a 2D array outside main()? Because my application calls for many N-dimensional arrays I want to ensure the same process is followed. A prototype which demonstrates what I am doing :
#include <iostream>
// my helper function which allocates the memory for a 2D int array, then returns its pointer.
// the final version will be templated so I can return arrays of any primitive type.
int** make2DArray(int dim1, int dim2)
{
int** out = new int* [dim1];
for (int i = 0; i < dim2; i++) { out[i] = new int[dim2];}
return out;
}
//helper function to deallocate the 2D array.
void destroy2DArray(int** name, int dim1, int dim2)
{
for (int i = 0; i < dim2; i++) { delete[] name[i]; }
delete[] name;
return;
}
int main()
{
int** test = make2DArray(2,2); //makes a 2x2 array and stores its pointer in test.
//set the values to show setting works
test[0][0] = 5;
test[0][1] = 2;
test[1][0] = 1;
test[1][1] = -5;
// print the array values to show accessing works
printf("array test is test[0][0] = %d, test[0][1] = %d, test[1][0] = %d, test[1][1] = %d",
test[0][0],test[0][1],test[1][0],test[1][1]);
//deallocate the memory held by test
destroy2DArray(test,2,2);
return 0;
}
My concern is this may not be memory-safe, since it appears I am allocating memory outside of the function in which it is used (potential out-of-scope error). I can read and write to the array when I am making a single small array, but am worried when I scale this up and there are many operations going on the code might access and alter these values.
I may be able to sidestep these issues by making an array class which includes these functions as members, but I am curious about this as an edge case of C++ style and scoping.
There is a difference between allocating 2D arrays like this and what you get when you declare a local variable like int ary[10][10] that based on your statement
My concern is that this operation may not be memory-safe, since it
appears that I am allocating memory for an array outside of the
function in which it is used (potential out-of-scope error)
I am guessing you do not fully understand.
You are allocating arrays on the heap. Declaring a local variable like int ary[10][10] places it on the stack. It is the latter case where you need to worry about not referencing that memory outside of its scope-based lifetime; that is, it is the following that is totally wrong:
//DON'T DO THIS.
template<size_t M, size_t N>
int* make2DArray( ) {
int ary[M][N];
return reinterpret_cast<int*>(ary);
}
int main()
{
auto foo = make2DArray<10, 10>();
}
because ary is local to the function and when the stack frame created by the call to make2DArray<10,10> goes away the pointer the function returns will be dangling.
Heap allocation is a different story. It outlives the scope in which it was created. It lasts until it is deleted.
But anyway, as others have said in comments, your code looks like C not C++. Prefer an std::vector<std::vector<int>> rather than rolling your own.
If you must use an array and are allergic to std::vector, create the 2d array (matrix) as one contiguous area in memory:
int * matrix = new int [dim1 * dim2];
If you want to set the values to zero:
std::fill(matrix, (matrix + (dim1 * dim2)), 0);
If you want to access a value at <row, column>:
int value = matrix[(row * column) + column];
Since the matrix was one allocation, you only need one delete:
delete [] matrix;

What does this code do? (c++, classes and arrays)

IntArray::IntArray (int *array, int sz)
{
_size = sz;
int ia = new int[_size];
for (int ix=0; ix<_size; ++ix)
ia[ix] = array[ix];
}
Hello, I'm currently studying C++ for beginners by Stanley Lipmann and I'm going through creating of abstract arrays with Classes help. Can someone explain me what does this code do? By my guess it assigns "sz" value (from outside of class) to "_size", then we create the "ia" dynamic array and after all it assigns values from "array" pointer (that outside of class) to an "ia" array. Thanks :D
That cannot be the full code, where is _size defined? Is it a class member? The leading underscore suggests that. I presume that ia is also a class member of type int *.
What it does is to copy the value of sz into the (presumably) member variable _size. Then it allocates a new array of int. The for loop then copies the elements from the given array into the new memory allocated. Looking at the name it will tell you that this is a constructor. It constructs a new array of ints by copying the given array.
And by the way, indent your code such that it is easier to read, that will make understanding it easier!
IntArray::IntArray(int *array, int sz) {
_size = sz;
ia = new int[_size];
for (int ix = 0; ix < _size; ++ix)
ia[ix] = array[ix];
}
You can use the amazing clang-format for all your formatting needs.
You can throw in a const to the array and sz parameters, that way you can also create new IntArray instances from constant arrays.

C++ Pointer of Array of Ints Initialization

I want to have an array accessible by all functions of a class.
I put the array as private variable in the header file.
private:
int* arrayName;
In the .cpp file where I implement the class, the constructor takes in an int value (size) and creates the array. The goal is to fill it up
ClassName::ClassName(int numElements){
arrayName = new int[numElements]; //make arrays the size of numElements
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
}
I feel like this is quite inefficient. I know you can do int array[5] = {0}; but how do you do it when you don't initially know the size.
If you want to zero-initialize a newed array, just do value-initialize it. This has the effect of zero-initializing its elements:
arrayName = new int[numElements]();
// ^^
But you really want to be using an std::vector<int>.
private:
std::vector<int> vname;
and
ClassName::ClassName(int numElements) : vname(numElements) {}
This way you don't have to worry about deleting an array and implementing copy constructors and assignment operators.
You can use the memset function:
memset(arrayName,0,sizeof(int)*numElements);
This void * memset ( void * ptr, int value, size_t num ); function sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).
To use it you must include the string.h header file.
For more information: http://www.cplusplus.com/reference/cstring/memset/
What you want to do is progressively expand the array on demand.
arrayName = new int[numElements];
for(int i = 0; i<numElements; i++)
arrayName[i] = 0;
The above code (what you gave) will give you an array of size numElements, and THEN the for loop will fill it. This is allocated now, and can't, as I understand it, be simply or easily resized (memset will overwrite previously held values in the array).
You could copy the whole array over every time you want to resize it:
int * oldarr = new int[OldSize];
//fill your old array
int * newarr = new int[NewSize];
for(int i = 0; i<OldSize; i++)
newarr[i] = oldarr[i];
Other than that, you could make the array much larger, or you could use various STLs, such as std::vector. Vector can be increased with a simple push_back function, and allows [] operator access (like arr[5] and whatnot).
Hope this helps!

proper memory allocation for a 2D array in a class in C++

I am writing a C++ class that uses some fixed arrays, as well as some dynamically allocated arrays.
I was wondering if anybody can guide me for the proper way to allocate memory for the dynamic arrays , probably in the constructor/deconstructor, and also if I need to explicitly call them to make sure I don't get a seg fault.
Here is a simplified version of the related part of my code:
class Network {
public:
int n_nodes;
int user_index[MAX_USERS]; //a fixed array
int adjacency_matrix[][MAX_ITEMS];
//Network(int n_node, int** adjacency); //I would rather to set the element s in a function other than the constructor
Initializer(int n_node, int** adjacency);
~Netowrk();
}
So here are my specific question for this class:
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
2 - where should I delete the 2D array? should I write it in the deconstructor? Should I call the deconstructor explicitly? Is there anything else I need to destroy in the deconstructor?
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes. The best way to do this, however, is not to use arrays at all. Instead, use std::vector, which manages the memory for you. There are two ways that you can do this. If you actually want to be able to use the [row][column] syntax to access elements, you'll need to use two dimensions of std::vectors:
std::vector<std::vector<int> > adjacency_matrix;
Once you know the dimensions, you can populate it:
adjacency_matrix.assign(rows, std::vector<int>(columns));
It is often easier to use a single-dimensional array (or a std::vector<int>) containing all of the elements and use row * row_count + column to access the element at index (row, column). This way, there are fewer dynamic allocations. You can wrap up the logic of accessing elements into a couple of helper functions.
2 - where should I delete the 2D array? should I write it in the deconstructor?
You don't have to delete anything if you use a std::vector. It cleans itself up.
Should I call the [destructor] explicitly?
No.
Is there anything else I need to destroy in the [destructor]?
Ideally, no. If you use the Standard Library containers, like std::vector and smart pointers, you shouldn't have to clean anything up. You should avoid trying to manage resources on your own in C++: there are library facilities to do this tedious task for you and you should take advantage of them.
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes you can. For example:
int* adjacency_matrix_;
int* getAdjacency(int i, int j)
{
if (!adjacency_matrix_)
return 0;
else
return adjacency_matrix_ + i*n_nodes + j;
}
Network()
: n_nodes(0),
adjacency_matrix_(0)
{}
void Initializer(int n_node, int** adjacency)
{
adjacency_matrix_ = new int[n_nodes * n_nodes];
// Copy over data.
}
As to whether you should, that depends on whether you have a reason for not using std::vector<>.
2 - where should I delete the 2D array? should I write it in the deconstructor?
Should I call the deconstructor explicitly?
Is there anything else I need to destroy in the deconstructor?
Yes, definitely free in the destructor using array operator delete:
~Network()
{
delete [] adjacency_matrix_;
}
No, your destructor will be called whenever the Network object itself goes out of scope. It is (very) rarely necessary to make an explicit destructor call.
No, all a destructor needs to explicitly release is whatever your explicitly acquire.
You may like the example matrix class I wrote in an answer to another question
The question itself was about good C++ design practices, but the chosen example was a multi-dimensional array.
There are several ways to do this.
The easiest way is to use vectors, and if you don't like to manage your own memory, this is perfect for you. However, because I like to manage my own memory, and I have found this method to be slow and cumbersome at times, I have learned of other ways.
The fastest way is to allocated a one dimensional array and treat it as you would a two dimensional array. Here is an example:
int *array = new int[width*height];
int get_array(int column, int row)
{
return array[row*width + column];
}
delete [] array;
This can be generalized to the nth-dimension:
int *array = new int[w1*w2*...*wn];
int get_array(int i1, int i2, ..., int in)
{
return array[in*(w1*w2*...*w(n-1)) + i(n-1)*(w1*w2*...*w(n-2)) + ... + i2*w1 + i1];
}
delete [] array;
If you want to be able to have different widths for each row, then you can make an array of pointers. This solution is slow to initialize and clean up, but flexible, tunable, and has relatively fast execution time. It can also be extremely dangerous if you make a mistake though.
int **array = new int*[height];
for (int i = 0; i < height; i++)
array[i] = new int[width(i)];
at which point, to access it, all you have to do is the customary
array[i][j]
however, to free this array you have to do it row by row
for (int i = 0; i < height; i++)
delete [] array[i];
delete [] array;
This can also generalize to the nth dimension.
int **....*array = new int**...*[w1];
for (int i1 = 0; i1 < w1; i1++)
{
array[i1] = new int**..*[w2];
for (int i2 = 0; i2 < w2; i2++)
{
array[i1][i2] = new int**.*[w3];
...
for (int in = 0; in < wn; in++)
array[i1][i2]...[in] = new int[wn];
}
}
for (int i1 = 0; i1 < w1; i1++)
{
for (int i2 = 0; i2 < w2; i2++)
{
...
for (int in = 0; in < wn; in++)
delete [] array[i1][i2]...[in];
...
delete [] array[i1][i2];
}
delete [] array[i1];
}
delete [] array;
This kind of setup tends to wreak havoc on memory. Just a two dimensional array of these would result in width+1 separate arrays to be malloc-ed. It would be faster to just malloc one big array and figure out the indices yourself.

Access Violation with static arrays?

I need to parallelise an application using win32 threads. One of the portions of the code involves modifying an static array using threads.
I pass the array as a parameter like this:
struct threadParameter {
float **array;
int row;
}
An example code would be like this:
// Main
float data[100][100]
for (int i = 0; i < 100; i ++) {
tp = (*threadParameter) new threadParameter;
tp->array = (float **) data;
tp->row = i;
AfxBeginThread... // Begin thread code
}
// Thread Code
UINT myThread(LPVOID param) {
threadParameter *pp = (threadParameter *) param;
for (int j = 0; j < 100; j ++) {
pp->array[pp->row][j] = NEWVALUE;
}
}
However, when executing the project, I get an "Access Violation Error" when I try to acceess the array via the **array pointer. This problem does not occur if the array data is
dynamic. Is there any way to sort this problem out (I am not allowed to change the array data from static to dynamic)?
Static arrays are NOT pointers to pointers -- the entire array is a single huge chunk of data, and addressable with a single pointer, namely, the pointer to the base of the array. Hence
tp->array = (float **) data;
is incorrect, because you're dereferencing a number inside the array. (The fact that you needed to cast also should've raised a red flag, since arrays are implicitly converted to the appropriate pointer types.)
That's why the common phrase "arrays are just pointers" is incorrect; it's half-true for single-dimensional arrays, but completely false with multidimensional arrays. If you need to use two indices, convert a single index into a row-column index by multiplying the row by the row size, then adding the column and indexing into the array with a pointer.