C++: How to create a member 2D-array of size determined at runtime - c++

I've tried to declare an empty pointer to a pointer, assign to it pointer to allocated during construction memory and iterate over it doing the assignment again, but I'm missing something. Also I wonder if it's possible to do this with the std::array. Attaching the code:
// Cell.h
class Cell {
char contents;
bool is_free;
};
// Memory.h
#include "Cell.h"
#include <cstddef>
class Memory {
public:
Memory(std::size_t nlines, std::size_t ncols);
private:
Cell **cells;
};
// Memory.cpp
#include "Memory.h"
Memory::Memory(std::size_t nlines, std::size_t ncols):
cells(new Cell[nlines]) // Cannot initialize a member subobject of type 'Cell **' with an rvalue of type 'Cell *'
{
for (std::size_t i = 0; i < nlines; ++i)
cells[i] = new Cell[ncols];
}
In addition I need my array to contain Cells with values char contents = '.', bool is_free = true after it is initialized. Which is the best way to do it?
UPD: I've thought of creating a 2D pseudo-array using a single pointer (not a pointer to a pointer) and accessing a cell with i*ncols + j.

Also I'm curious if it's possible to do this with the std::array
You can not, the size of an std::array is specified as a template parameter and your array is dynamically sized.
Rather than dealing with raw pointers, you should look at std::vector for dynamically sized arrays:
std::vector<std::vector<Cell>> cells{ncols, std::vector{nlines, Cell{}}};
The key benefit is that you avoid having to manually allocate and manage memory.
UPD: I've thought of creating a 2D pseudo-array using a single pointer (not a pointer to a pointer) and accessing a cell with i*ncols + j.
This is a much better idea, keeping your data in a single flat vector reduces fragmentation.
std::vector<Cell> cells(nlines*ncols, Cell{});
To make access easier, you can wrap this 1D vector in a class which exposes a operator()(std::size_t row, std::size_t col), that does the conversion from (row, col) indices to the location in the 1d array.

You need to write
Memory::Memory(std::size_t nlines, std::size_t ncols)
:cells(new *Cell[nlines])
{
...
}
(Note the Cell * instead of Cell).
std::array is compile-time fixed array size only, so it is not suitable for your purpose.
I would agree to your edit. Do not an array of pointers for matrices, use the flat array approach with indexing i*ncols + j. This former is more difficult to work with and has higher overhead (due to many new calls).
If you are worried about the multiplications overhead, you could make a look-up table for i*ncols. But I doubt that it is worth it.

Related

C++ Pointer not being updated?

Not exactly sure how to word the title but I'll explain as best I can.
I have a program that originally used a 2D array of a set size and so it was defined as:
typedef char Map[Row][Col];
I'm now trying to dynamically allocate memory for it and it has now also become of variable size based on input. It's now defined as:
typedef char** Map;
In my main method, I originally had:
Map map;
readUserInput(map);
Basically readUserInput takes the map array as a parameter, and assigns values to it based on user input. The map then contains values and is used in other functions.
I've updated the readUserInput function so that it dynamically sizes the array and it allocates/deallocates memory for it. This works fine, but the problem comes from the fact that now in the main method, map is not being updated. The above code in main now looks like:
Map map = nullptr;
readUserInput(map);
but after running the readUserInput function, map is still null. Inside of the function, map is updated fine, so I'm not understanding the difference made between the changes.
What you pass to function is a pointer to array and fuction can't change it. But replacing array with pointer to pointer is incorrect in most case.Pointer to pointer suggest that have a 1D array of pointers. Which may (or may not) point to other arrays. Such data organization sometimes referred to as jagged arrays, because it allows each row to be of separate length. But on practtice jagged arrays and their subclass, sparse matrices, usually implemented as 1D array to avoid re-allocation.
To avoid decaying and to actually store a monolithic array in memory, you should use 1d array and, preferably, encapsulation for pointer arithmetic and reallocation, and then pass reference to object that stores all required states. Reference ensures that object is mutable by function ( a smart-pointer-less version for an example):
class Map
{
int rows, cols;
char *data;
public:
Map() : rows(), cols(), data(nullptr) {}
Map(int r, int c) : rows(r), cols(c), data(new char[r*c]()) {}
~Map() { delete[] data; }
void resize(int r, int c) {
if(rows == r && cols == c) return;
char* tmp = new char[r*c]();
if(data)
{
// copy old data here if required
delete[] data;
}
row = r; col = c;
data = tmp;
}
char& operator() (int r, int c) { return data[r*cols + c]; }
char operator() (int r, int c) const { return data[r*cols + c]; }
};
NB: this class requires a copy and move operations to be implemented if any copy must be allowed.
The function prototype would be:
void readUserInput(Map& map);
With such class you can do dynamic resizing, store its size, and address element as simple as this:
int main()
{
Map test(4, 5); // declaring and allocating memory
test.resize(3,3); // reallocating
test(1,1) = 3; // writing
//reading
std::cout << +test(1,1) << std::endl;
}
The function should accept the array by reference in the C terms like
readUserInput( &map );
when the function is declared like
void readUserInput( Map *map );
or in the C++ terms when the function is declared like for example
void readUserInput( Map &map );
and called like
readUserInput(map);
Instead of allocating dynamically arrays you could use the container std::vector<std::string>.
The code you have used is a pure C-style code, and is prone to many mistakes:
You use typedef instead of: using Map = char**;
You use a function which gets a pointer and fills it, which is more common in C than in C++.
You use raw pointer instead of smart pointers (added in C++11), which may cause a memory leak in the end.
I've updated the readUserInput function so that it dynamically sizes the array and it allocates/deallocates memory for it.
This means that now it should be a class named Map, since it should be able to allocate/deallocate, insert and remove values, and is a valid container. Actually, you are creating a type of std::vector here, and if you don't create it for you own learning process, I strongly suggest you to use the std containers!
It is possible to pass both pointer and references in C++, notice that:
You can pass a reference only if the value isn't nullptr.
When there should be a value, reference is recommended.
In this case, your function should look like
void readUserInput(Map* map);
and should be called using:
readUserInput(&map);

Creating a dynamic 2D array

I need to have a 2D array of double.
Its width is around 900. Its height as well (the same width value).
Dealing with two loops (one for the width and one for the height), I really need to get access to all the pixels of the 900X900 image that I will process.
The size of the array is too big (error when specifying the number of raw and column).
I thought about establishing that with a dynamic array to optimize the time of calculation and to free the memory everytime I deal with one pixel on the two loops.
But I really cannot find the syntax I would like to have to declare a 2D dynamic array (malloc, setting array element values and freeing the memory).
Wrap it in a class:
class Matrix2D {
typedef std::vector<double> Column;
std::vector<Column> columns;
public:
Matrix2D(unsigned int width, unsigned int height) :
columns(width, Column(height)) {
}
double& at(unsigned int i, unsigned int j) {
return columns[i][j];
}
};
Matrix2D matrix(900, 900);
matrix.at(45, 65) = 1234.5678;
I need to have a 2D array of double
Since you are using C++ you should use STL classes that will take care of ugly memory management for you. So you are actually looking for std::vector< std::vector<double> >, or for the sake of the readability of your code:
#include <vector>
typedef std::vector<double> DVector; // row represented by vector of doubles
typedef std::vector<DVector> MyVector; // 2D array as a vector of these rows
And then avoid using dynamic allocation wherever it's possible to do so. Take advantage of RAII idiom:
{
MyVectorarr; // vector object with automatic storage duration
} // <-- vector is automatically destructed when execution goes out of scope
Questions that might help you:
Multi-dimensional vector
Initialization of a vector of vectors?
vector of vector
I associate malloc with pure C, not C++ (as the prior answer points yout, you should use std::vector). However, if you really want to:
// allocate the memory in a block
double* block = (double *) malloc(sizeof(double) * xSize * ySize);
// allocate memory for the accessor array
double* accessor = (double*) malloc(sizeof(double*) * xSize);
// assign memory addresses
double* curPtr = block;
for (int i = 0; i < xSize; ++i) {
accessor[i] = curPtr;
curPtr += ySize;
}
// you can now access the array via accessor[x][y]
// now need to free malloced memory:
free(accessor);
free(block);
If you do it this way, I highly suggest tying it to the RAII pattern, otherwise you'll eventually get a memory leak. Using the STL's containers is a better approach.

access violation in 3-dimensional array c++(using malloc)

I am trying to make a 3-d integer array where I know the number of columns is 2.
I am initializing the array sequentially using malloc. Please suggest what could be wrong?
int **output_vertex[2];
for(int j=0;j<4;j++)
output_vertex[j]= (int **)malloc(sizeof(int **));
output_vertex[1][0]==(int*)malloc(2*sizeof(int));
output_vertex[1][0][0] =11;
//also tried *output_vertex[1][0] =11;
I'm having a bit of trouble understanding what your error is (or which one you'd be referring to). Firstly I don't know why you're statically creating an array and then using malloc. Secondly, I don't understand why you're iterating through your for loop four times (0, 1, 2, 3). Shouldn't your allocation be something like this:
int **output_vertex;
output_vertex = (int **)malloc(2*(sizeof(int **)));
The array declaration you have is not what you intended. You have a two-element array of pointers to pointers to int. This page is a good guide to reading those declarations.
Personally, I prefer to use typedefs and build a complex type like this from the ground up:
typedef int[2] element_type; // this is the 2-element array of ints
typedef element_type* inner_type; // this is the array of unknown size
typedef inner_type[5] outer_type; // this is the actual type we want to use
outer_type output_vertex; // we now have an array of 5 inner_type variables on the stack
// The output_vertex is *uninitialized* so we have to initialize each of its elements
for (int i=0; i < 5; ++i) {
output_vertex[i] = new inner_type[SOME_SIZE];
}
// do stuff with output_vertex now that it's initialized
// then, to prevent memory leaks, delete the memory you allocated
for (int i=0; i < 5; ++i) {
delete[] output_vertex[i];
}
There are probably ways to simplify, but that should be a start.
If you want the inner_type to be appendable, I would strongly recommend using std::vector instead of raw arrays. There is far much bookkeeping to be done with raw arrays, so I won't give an example of that; however, here's more-or-less what you would do with std::vector:
typedef std::pair<int,int> element_type; // this is the 2-element array of ints as a pair
typedef std::vector<element_type> inner_type; // dynamic vector this time
inner_type output_vertex[5]; // we now have an array of 5 inner_type variables on the stack
// do stuff with output_vertex
std::vector is just as fast as a dynamically-allocated array, but you don't have to do any of the bookkeeping yourself. You also have the benefit of not needing to manage as many heap-allocated objects.
Note that raw arrays aren't compatible with containers (e.g. std::vector), so I use std::pair here instead.
If you're able to use C++11 (or boost) and you need a fixed-size array of greater than two items that can fit into a standard container, use std::array.

Transfering a dynamically allocated matrix in a method of a class in C++

I'm trying to make a dynamically allocated bidimensional array with variable size but I don't know why if I create my own constant value it won't compile:
const int oConstanta=N+1;
int (*m)[oConstanta]=new int[oConstanta][oConstanta];
But when I use a normal constant such as 1000 between the brackets it compiles successfully.
const int oConstanta=N+1;
int (*m)[1000]=new int[1000][1000];
Does anyone know the reason for this?
PS: I know that:
int **m=new int*[oConstanta];
for(i=1;i<=N;i++)
{
m[i]=new int[oConstanta];
init(m[i]);
}
will solve my problems but I want to learn why my former method was a bad idea.
Unless N is a compile-time constant expression, oConstanta is not a compile-time constant either.
The best way of making a two-dimensional array in C++ is using std::vector of std::vectors, for example, like this:
#include <vector>
std::vector<std::vector<int> > m(N+1, std::vector<int>(N+1, 0));
Ultimately the reason is that you can't create static arrays of variable length.
In your code you are trying to create a static array of dynamic arrays, both of variable length.
Now, static arrays live in the stack, while dynamic arrays live in the heap. While the memory management of the heap is "flexible", the stack is different: the compiler needs to be able to determine the size of each frame in the stack. This is clearly not possible if you use an array of variable length.
On the other hand, if you use a pointer the size of the stack frame is known (a pointer has a known size) and everything is fine.
If you want to try, this should compile fine
int (*m)[1000]=new int[oConstanta][1000]
since it's a fixed-size static array, whose entries are dynamically allocated arrays of variable length (allowed).
In short: whenever the size of an object is not known at compile time, that object cannot be in the stack, it has to be dynamically allocated.
To make a dynamically sized, 2D matrix with contiguous elements and a single allocation:
std::vector<int> matrix(Rows*Columns);
Access an element in the i th row and j th column:
matrix[Columns*i + j] = 1;
You can wrap this all up in a class. Here's a very basic example:
struct Matrix {
std::vector<int> m;
size_t rows,columns;
Matrix(size_t rows,size_t columns)
: rows(rows)
, columns(columns)
, m(rows*columns)
{}
int &at(size_t i,size_t j) {
return m.at(i*columns + j);
}
};

std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless.
Suppose I wish to create a vector of a multidimensional, static array. Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5].
Can I be certain that all N*5 integers are now contiguous in memory? So that I in principle could access all of the integers simply by knowing the address of the first element? Is this implementation dependent?
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
The standard does require the memory of an std::vector to be
contiguous. On the other hand, if you write something like:
std::vector<std::vector<double> > v;
the global memory (all of the v[i][j]) will not be contiguous. The
usual way of creating 2D arrays is to use a single
std::vector<double> v;
and calculate the indexes, exactly as you suggest doing with float.
(You can also create a second std::vector<float*> with the addresses
if you want. I've always just recalculated the indexes, however.)
Elements of a Vector are gauranteed to be contiguous as per C++ standard.
Quotes from the standard are as follows:
From n2798 (draft of C++0x):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
C++03 standard (23.2.4.1):
The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Also, see here what Herb Sutter's views on the same.
As #Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. I would not, however, simulate a 2D matrix with an array of pointers. Instead, I'd recommend one of two approaches. The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector:
template <class T>
class matrix2D {
std::vector<T> data;
int columns;
public:
T &operator()(int x, int y) {
return data[y * columns + x];
}
matrix2D(int x, int y) : data(x*y), columns(x) {}
};
If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer.
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
That's not a 2D array, that's an array of pointers. If you want a real 2D array, this is how it's done:
float (*p)[5] = new float[N][5];
p [0] [0] = 42; // access first element
p[N-1][4] = 42; // access last element
delete[] p;
Note there is only a single allocation. May I suggest reading more about using arrays in C++?
Under the hood, a vector may look approximately like (p-code):
class vector<T> {
T *data;
size_t s;
};
Now if you make a vector<vector<T> >, there will be a layout like this
vector<vector<T>> --> data {
vector<T>,
vector<T>,
vector<T>
};
or in "inlined" form
vector<vector<T>> --> data {
{data0, s0},
{data1, s1},
{data2, s2}
};
Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. It most probably stores an array of pointers (and some other variables) to external places.
The standard only requires that the data of a vector is contiguous, but not the vector as a whole.
A simple class to create, as you call it, a 2D array, would be something like:
template <class T> 2DArray {
private:
T *m_data;
int m_stride;
public:
2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
~2DArray() { delete[] m_data; }
T* operator[](int row) { return m_data + m_stride * row; }
}
It's possible to use this like:
2DArray<int> myArray(30,20);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 20; j++)
myArray[i][j] = i + j;
Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers".
But as you see, it turns naive expectations around in that it's myarray[y][x].
Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ?
Edit: As said, the above is simple. No bounds check attempts whatsoever. Just like, "an array".