Why can't a multidimensional array be allocated with one new call in C++? - c++

In C++ you can easily allocate one dimensional array like this:
T *array=new T[N];
And you can delete it with one statement too:
delete[] array;
The compiler will know the magic how to deallocate the correct number of bytes.
But why can't you alloc 2-dimensional arrays like this?
T *array=new T[N,M];
Or even like this?
T *array=new T[N,M,L];
If you want a multidimensional you have to do it like this:
T **array=new T*[N];
for(int i=0;i<N;i++) array[i]=new T[M];
If you want a fast program that uses matrices (matrix operations, eigenvalue algorithms, etc...) you might want to utilize the cache too for top performance and this requires the data to be in the same place. Using vector<vector<T> > is the same situation. In C you can use variable length arrays on the stack, but you can't allocate them on the heap (and stack space is quite limited), you can do variable length arrays in C++ too, but they won't be present in C++0x.
The only workaround is quite hackish and error-phrone:
T *array=new T[N*M];
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
T[i*N+j]=...;
}

Your workaround of doing T *array=new T[N*M]; is the closest you can get to a true multi-dimensional array. Notice that to locate the elements in this array, you need the value of M (I believe your example is wrong, it should be T[i*M+j]) which is known only at run-time.
When you allocate a 2D array at compile-time, say array[5][10], the value 10 is a constant, so the compiler simply generates code to compute i*10+j. But if you did new T[N,M], the expression i*M+j depends on the value of M at the time the array was allocated. The compiler would need some way to store the value of M along with the actual array itself, and things are only going to get messy from here. I guess this is why they decided not to include such a feature in the language.
As for your workaround, you can always make it less "hackish" by writing a wrapper class that overloads operator (), so that you could do something like array(i, j) = ....

Because multidimensional array is something different then array of arrays/pointers.

use std::vector

Why can't a multidimensional array be allocated with one new call in C++?
Because when the ISO wrote the C++ language standard, they didn't decide to add that feature to the language. I don't know why they decided not to.
If you don't like that, you can create helper functions to allocate/free multidimensional arrays, or you can switch to a language like C# or Java that does support easily allocating multidimensional arrays.

What you can do, however, is allocate an object containing a two-dimensional array off the heap. I would just write a wrapper class for it.

I was thinking about this question last night, and this solution came to me.
T * raw = new T[N*M];
T ** array = new T*[N];
for(int i=0; i<N; i++)
array[i] = raw + i * M;
Now "array" acts just like a contiguous static sized two dimensional array. You just have to take care of deleting both the raw array, and the multi-dimensional array.

I would recommend that you use a Boost::multi_array, from the library of the same name, which provides a simple interface to a multidimensional array. It can be allocated in one line, and at a sufficiently high optimization level is usually as fast as a native array.
Here's some example code from the library's website:
#include "boost/multi_array.hpp"
#include <cassert>
int
main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}

Because the comma is an operator.
int a = (3, 5, 7, 9);
The program will evaluate 3, discard the result,
evaluate 5, discard the result,
evaluate 7, discard the result,
evaluate 9, and assign it to a.
Hence the syntax you are looking for can't be use,
and retain backward compatibility to c.

Related

C++ : How to safely deallocate a heap-allocated array of vectors?

I am currently working with code that at the moment requires me to make an array of vectors (I am new to C++ - if this is an absolutely terrible idea, I would greatly appreciate the feedback).
Let's say I allocate memory on the heap for my vectors like so:
#include <iostream>
#include <vector>
#include <random>
int main() {
typedef std::vector<double> doubleVec;
long N = 1000;
long M = 1000;
doubleVec *array = new doubleVec[N];
for (long i = 0; i < N; i++) {
doubleVec currentVec = array[i];
currentVec.resize(M);
for (long j = 0; j < M; j++)
currentVec[j] = std::rand();
}
// ... do something with the data structure
delete [] array;
}
When I've done everything I need to do with the data, how should I safely deallocate this data structure?
NOTE: There were other things I did wrong in my inital post that I didn't intend to be the focus of the discussion (uninitialized variables, didn't resize vectors, etc). I fixed those now. Thank you all for pointing those out.
f this is an absolutely terrible idea, I would greatly appreciate the feedback).
Yes, this is a terribly bad idea. To be specific, owning bare pointers are a bad idea. Instead of manually allocating a dynamic array, it is usually better to use a container such as std::vector.
How to safely deallocate a heap-allocated array of vectors?
By using a vector instead of manual dynamic array. In this case, a simple solution is to use a vector of vectors.
A potentially better solution would be to allocate a single flat vector of doubles of size 1000*1000 where elements of each "subvector" is after another. This requires a bit of simple math to calculate the index of the sub vectors, but is in most use cases faster.
Other notes:
typedef std::vector<double> doubleVec;
Avoid obfuscating the program by hiding type names like this.
for (long j; j < M; j++)
^^^^^^
You leave this variable uninitialised. When the indeterminate value is used later, the behaviour of the program is undefined.
Furthermore, you forgot to include the standard headers which define std::vector and std::rand.
I got a seg fault
See the other answer regarding you not actually adding any elements to the vectors that are in the array. This, and the uninitialised variables are the most likely reason for your segfault depending on what "do something" does.
The problem is not in deallocating but in each vector allocation. Where in your code do you use the M value (except while accessing the elements)? There are other problems in your code, so the quick fix is:
for (long i; i < N; i++) {
doubleVec &currentVec = array[i];
currentVec.resize(M);
for (long j; j < M; j++)
currentVec[j] = std::rand();
}
Pay special attention that currentVec is a reference: otherwise no changes would be stored in the array.
Anyway, the main question everybody would have is: why do you need to have an array of vectors?.. The vector of vectors is a much more elegant solution.
Update: I've missed the fact that you have forgotten to initialize both i and j. In addition to the advice to initialize them I would recommend to use the auto keyword that would make it impossible to leave the variable uninitialized:
for (auto i=0UL; i < N; i++) {
doubleVec &currentVec = array[i];
currentVec.resize(M);
for (auto j=0UL; j < M; j++)
currentVec[j] = std::rand();
}
0UL means zero of the type unsigned long.

Dynamic 2D array without using new

I've been posed with creating a dynamic 2D array in C++ without using new in C++. I have been trying for a while to make something work but I'm clueless as to what I'm supposed to do.
Edit: Sorry, should have been more specific. Just to be transparent, yes it is homework, and no I don't want it solved I just want to be pointed (no pun intended) in the right direction to code it myself.
The order, for reference, is as follow: Develop a console application to create a type int matrix of size m x n using pointers. The user must input the values for the size of the matrix from the keyboard and its contents must be randomly generated (1 - 100). Then, the transpose of the matrix must be calculated and shown (it's necessary to create classes).
We can't use new, nor vector, as we have to do it just via pointers with uni-dimensional arrays. So far I created a class that represent the "rows", and another class which represents the "columns". The columns go into the rows and the rows go into another class called matrix. That was the idea but was having trouble implementing it.
new is the only way to create dynamic objects or arrays in standard C++. So, depending on how you interpret the task, it could be considered impossible.
If we assume that it is OK for you to call a standard function that internally calls new, then the problem is solvable. A commonly used way to create a dynamic array in C++ is to use std::vector. Elements of std::vector may not be arrays however, so a 2D dynamic array is not technically possible using it. One workaround is to wrap the array within a class, and use the class as element of the vector. There is a standard template for such array wrapper: std::array. An example of a vector of array wrappers:
std::vector<std::array<type_of_element, 10>> name_of_vector(number_of_arrays);
The elements of the arrays within the dynamic array managed by the vector will have effectively the same layout as a 2D array would.
malloc did the trick. Here is the code I used to test it. It was a bit convoluted to figure out how to write the matrix loop but once I got it down I realized how obvious it was.
Matriz::Matriz(int numFil, int numCol)
:numFil(numFil), numCol(numCol)
{
mat = (int *)malloc(numFil * numCol * sizeof (int));
int c = 0;
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
*(mat + i * numCol + j) = ++c;
}
}
}
void Matriz::printMat()
{
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
std::cout << *(mat + i*numCol + j);
}
std::cout << std::endl;
}
}

Should I use matrix[][max] or **matrix in C++?

I think it will be very easy when I do it with this:
int n = 4;
int matrix[n][n];
rather then:
p = new int *[n];
for (int i = 0; i < n; i++)
p[i] = new int [n];
So, Which is better? When do we use ** to create a matrix or a array?
int n = 4;
int matrix[n][n];
Your first example isn't c++ standard conform, the standard doesn't support variable length arrays.
int** p = new int *[n];
for (int i = 0; i < n; i++)
p[i] = new int [n];
For your second example you should better use a std::vector<int> instead and organize matrix rows and columns as sections in the vector:
int n = 4;
std::vector<int> matrix(n*n);
Using new and delete yourself is usually not necessary in C++ and peppered with pitfalls and obstacles, which are taken care of in the appropriate standard library container and smart pointer classes.
First declaration is non-standard: n must be known at compile time in order for the code to compile. Some compilers offer variable-length arrays as an extension, but the code remains non-standard.
The standard approach to situations when you need a matrix in C++ is to use std::vector<std::vector<T>> for situations when the size is not known until the runtime. When the size is known at compile time and you prefer allocation in automatic area, use std::array<N,std::array<N,T>> instead of vectors.
Both these approaches let you construct objects that behave exactly like arrays of arrays, but you don't need to manage their memory explicitly.

Declaring array with user-defined size before the main function

I have a an array int matrix[10][10] as well as other arrays with similar size which is declared before the prototype functions and main function. This 2d array is used by all of the functions. However, I need my program to have a function that asks the user the size of the matrix he wants. So, it's gotta be something like this: int matrix[ROWS][COLUMNS]. I know for sure that I can't place the declare the array inside the main function since this array is used by all the other functions. How do I declare this kind of array?
First of all, it is impossible to declare an array with variable sizes, as they are not legal in C++ (although they are legal in C). So you're out of luck here.
Second, you want the declaration before main. Hence, you have to use either
A dynamic array, defined globally like int** matrix; and initialized in main() as
matrix = new int*[ROWS];
for(size_t i = 0 ; i < ROWS; ++i)
matrix[i] = new int[COLS];
then you'd have to release its memory at the end of the day
for(size_t i = 0; i < ROWS; ++i)
delete[] matrix[i];
delete[] matrix;
or
A standard container like std::vector<>
std::vector<int> matrix; // defined globally
and in main() reserve memory for it, like
matrix.reserve(ROWS*COLUMNS); // reserve memory for M rows
Then you'd need to play around with the indexes, so you can map from pairs of indexes to 1D index, i.e. the "logical" element [i][j] is represented by the index i * COLS + j in matrix.
Of course, you could have used a std::vector<std::vector<int>>, however this approach is faster since the memory is guaranteed to be contiguous (same applies to the first example, where you could have used an int* instead).

Multi-dimensional array and pointers in C++?

int *x = new int[5]();
With the above mentality, how should the code be written for a 2-dimensional array - int[][]?
int **x = new int[5][5] () //cannot convert from 'int (*)[5]' to 'int **'
In the first statement I can use:
x[0]= 1;
But the second is more complex and I could not figure it out.
Should I use something like:
x[0][1] = 1;
Or, calculate the real position then get the value
for the fourth row and column 1
x[4*5+1] = 1;
I prefer doing it this way:
int *i = new int[5*5];
and then I just index the array by 5 * row + col.
You can do the initializations separately:
int **x = new int*[5];
for(unsigned int i = 0; i < 5; i++)
x[i] = new int[5];
There is no new[][] operator in C++. You will first have to allocate an array of pointers to int:
int **x = new int*[5];
Then iterate over that array. For each element, allocate an array of ints:
for (std::size_t i = 0; i < 5; ++i)
x[i] = new int[5];
Of course, this means you will have to do the inverse when deallocating: delete[] each element, then delete[] the larger array as a whole.
This is how you do it:
int (*x)[5] = new int[7][5] ;
I made the two dimensions different so that you can see which one you have to use on the lhs.
Ff the array has predefined size you can write simply:
int x[5][5];
It compiles
If not why not to use a vector?
There are several ways to accomplish this:
Using gcc's support for flat multidimensional arrays (TonyK's answer, the most relevant to the question IMO). Note that you must preserve the bounds in the array's type everywhere you use it (e.g. all the array sizes, except possibly the first one), and that includes functions that you call, because the produced code will assume a single array. The allocation of $ new int [7][5] $ causes a single array to be allocated in memory. indexed by the compiler (you can easily write a little program and print the addresses of the slots to convince yourself).
Using arrays of pointers to arrays. The problem with that approach is having to allocate all the inner arrays manually (in loops).
Some people will suggest using std::vector's of std::vectors, but this is inefficient, due to the memory allocation and copying that has to occur when the vectors resize.
Boost has a more efficient version of vectors of vectors in its multi_array lib.
In any case, this question is better answered here:
How do I use arrays in C++?