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.
Related
I am essentially trying to declare something like this but I am unable to because of "too many initializer variables".
int** a = { {1},{2,3},{3,4,5} };
As a side question, if this were to work with some slight modification would it have the size of 9 (3x3) or 6 (1+2+3)?
I can implement this behavior with vectors such as the following, but I am curious as to why can't I do it more directly.
vector<int*>a = vector<int*>();
for (int i = 0; i < 20; i++)
{
a.push_back(new int[i]);
for (int j = 0; j <= i; j++)
a[i][j] = i+j;
}
Using a double pointer in C++ statically has a different memory arrangement than using new dynamically. The difference is that a static ** takes continuous memory automatically at compile time, where a dynamic one will not. Static multidimensional arrays are stored continuously, as discussed here.
Related: my question here.
Since your array cannot be stored continuously, it cannot be declared statically.
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).
I have long used pointers to arrays in C programs of the form:
int (*myarray)[2] = (int (*)[2]) malloc(n*sizeof(int[2]));
However, how can I do this in C++ using new? Can I do this?
int (*myarray)[2] = (int (*)[2]) new int[n][2];
EDIT:
Looks like my original post was incomplete and confusing. Here is a code snippet that I compiled and tested which appears to do the right thing but I wanted to confirm from C++ experts that I was using an appropriate C++ construct.
#include <iostream>
int main() {
int n=5;
int (*A)[2] = new int[n][2];
for (int i = 0; i < n; i++)
for (int j = 0; j < 2; j++)
A[i][j] = 2*i+j;
for (int i = 0; i < n; i++)
std::cout << A[i][0] << " " << A[i][1] << "\n";
delete myarray;
}
The joys of using C++ and STL is you get a vector class that provides array like behaviour.
This also makes it easier to manage and read...
std::vector< std::vector<int> > myarray(n);
If you don't want to use the STL then there is always...
typedef int intarray[2];
intarray* ints = new intarray[n];
ints[0][0] = 1;
...
ints[n-1][1] = 6;
I personally would write an extra line of code if it made the code easier to read.
I think the clearest way to do what you ask for is to use a typedef for the array:
typedef int array_t[2];
array_t* yourarray = new array_t[n];
Don't do that though, because it requires doing manual memory management and that tends to be tedious, error-prone and brittle, in particular with respect to exception safety. Instead, take a look at the std::array class template (new in C++11, but otherwise available via Boost) and at the std::vector class template.
To clarify the different between storing std::vector and std::array in a container, the latter is typically more efficient when there is a small and fixed number of elements involved. The reason is that the array class doesn't allocate things dynamically as the vector does. For that, vector needs three pointers (beginning, end of used storage and end of allocated storage) plus of course the storage for the data itself (plus maybe some overhead induced by the allocator) all of which need to be loaded into the CPU cache for use. Considering an LP64 system, that would require 32 bytes to store 8 bytes of data, compared to just 8 bytes using std::array.
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++?
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.