2 dimensional step array in c++ - c++

I'm new to c++ and I've spent a night thinking about this. I want to create a 2 dimensional array, length of first dimensional is given. Length of second dimensional, is increased from 1. e.g. for 2d array a[][], a[0][] has 1 element, a[1][] has 2 elements, a[2][] has 3 elements, etc.
It doesn't sound like a hard structure, but I can't find a two to create it - all I can do is to create a x * x array which means half of the space is wasted for me.
Anyone has any idea? Thanks in advance.

std::vector solution:
vector< vector<int> > stairs;
for(int i = 0; i < n; i++) // n is size of your array
stairs[i].resize(i+1);
You can also do this using plain pointers:
int * stairs[n];
for(int i = 0; i < n ; i++)
stairs[i] = new int[i+1];
But this time you will have to worry about deleting this structure when it is no longer needed.

Try considering dynamic allocation for your array.
Dynamic array allocation
Another way to make multi dimensional arrays is using a concept known
as pointer to pointers. Like Ron was saying on thursday, most of think
of a 2D array like a spreadsheet with rows and columns (which is just
fine), but 'under the hood', C++ is using ptr to ptrs. First, you
start off with creating a base pointer. Next, allocate an array of row
pointers and assign the address of the first one to the base pointer.
Next, allocate memory to hold each rows column data and assign the
address in the row pointer array
But if you're new to CPP, I assume that you won't be dealing with a large number of data so don't worry about memory !

One solution is to define a class that holds a single dimensional data array of size x*(x+1)/2, and overload type & operator()(int r, int c) to do the right type of indexing.
template<class datatype, int size>
class strange2dArray {
datatype data[size*(size+1)/2];
datatype & operator()(int r, int c) {
// assert if the indexes are correct
return data[r*(r+1)/2+c];
}
};
BTW, unless you're doing this for learning C++, you should probably use some kind of math library (or whatever) to provide you with such elementary data structures. They'll implement it much more efficiently and safely.

First let's see a test of Python:
>>> a=[]
>>> a[0]=3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> a={}
>>> a[0]=3
Oops, looks like array, does't means it is array. If you want dynamic size of "array", you can use mapping.
Yes, it is the first solution:
#include <map>
#include <iostream>
using namespace std;
typedef std::map<int, int> array_d2; //length of second dimensional is increased
array_d2 myArray[10] ; //length of first dimensional is given
int main()
{
myArray[0][1] = 3;
myArray[0][2] = 311;
//following are tests
cout << myArray[0][1] << endl;
cout << myArray[0][2] << endl;
return 0;
}
(output is:)
$ ./test
3
311
My second solution is to use , something more like a array , but have the resize capability, you should override the opertation [] to make it automatically for user.
#include <vector>
#include <iostream>
using namespace std;
//length of second dimensional is increased
class array_d2 {
int m_size;
vector<int> m_vector;
public:
array_d2 (int size=10) {
m_size = size;
m_vector.resize(m_size);
};
int& operator[] ( int index ) {
if (index >= m_size) {
m_size = index + 1;
m_vector.resize(m_size);
}
return m_vector[index];
};
};
array_d2 myArray[10] ; //length of first dimensional is given
int main()
{
myArray[0][1] = 3;
myArray[0][20] = 311;
myArray[1][11] = 4;
myArray[1][12] = 411;
//following are tests
cout << myArray[0][1] << endl;
cout << myArray[0][20] << endl;
cout << myArray[1][11] << endl;
cout << myArray[1][12] << endl;
return 0;
}
(output is)
$ ./test1
3
311
4
411

Related

Is it dumb to make a dynamic 2d array where the second dimension is a constant?

I am trying to make an array with a variable number of rows, but it will always have 4 columns. Is doing something like:
int** numGrades = new int* [num_exams];
for (int i = 0; i < num_exams; ++i)
{
numGrades[i] = new int[4];
}
a good way to do this? I feel like there's an easier way, but I can't think of one. Also, the array keeps giving me memory leaks so I'm wondering if that is because I'm doing something I shouldn't be. Vectors are banned for this program fyi.
You could make an array of rows.
struct Row{
int values[4];
};
Row* numGrades = new Row[num_exams];
Maybe you can try this.
typedef int row[4];
//or
using row = int[4];
row *numGrades = new row[num_exams];
Allocating some number of arrays of fixed size is fine and advantageous in many cases.
In addition to a struct (which is a very good option), another option is to declare a Pointer-To-Array of a fixed number of elements. The benefit there is you have a Single-Allocation and Single-Free for the block of memory. (as you do with an array of struct) If you need to grow the block of memory (with a -- declare bigger block, copy existing to bigger, delete existing reallocation), it simplifies the process. In your case:
int (*numGrades)[4] = new int[num_exams][4];
Which will allocate num_exams number of arrays of 4 int all at once. That provides the benefit of a single delete[] numGrades; when you are done with the memory.
A short example that uses a std::istringstream to hold example values to be read into a block of memory containing fixes size arrays could be:
#include <iostream>
#include <sstream>
int main (void) {
std::istringstream iss { "1 2 3 4 5 6 7 8 9" };
int npoints = 3,
(*points)[3] = new int[npoints][3],
n = 0;
while (n < 3 && iss >> points[n][0] >> points[n][1] >> points[n][2])
n++;
for (int i = 0; i < n; i++)
std::cout << points[i][0] << " " << points[i][1] << " " << points[i][2] << '\n';
delete[] points;
}
(note: you should avoid using new and delete in favor of a container such as std::vector if this is for other than educational purposes)
Example Use/Output
$ ./bin/newptr2array3
1 2 3
4 5 6
7 8 9
Worth noting, the benefit of the struct is that it will allow you to overload >> and << with std::istream and std::ostream to provide a convenient functions to read and write the data you need.
So either way, a Pointer-to-Array of fixed elements, or creating a struct and then an Array of struct is perfectly fine.
You could skip the for loop:
int* numGrades = new int[num_exams*4];
int firstElement = numGrades[x];
int secondElement = numGrades[x+1];
int thirdElement = numGrades[x+2];
int fourthElement = numGrades[x+3];
By skipping the for loop you gain this:
You don't have to have a for-loop for freeing the memory:
delete[] numGrades;
The heap does not fragment so much because you don't call "new" so many times.
BUT it all depends what you are using it for. In modern C++ is not such a good idea to use dynamic but make a struct in a std::vector.

Dynamically allocating memory

I am new to C++ and programming in general so i apologize if this is a trivial question.I am trying to initialize 2 arrays of size [600][600] and type str but my program keeps crashing.I think this is because these 2 arrays exceed the memory limits of the stack.Also,N is given by user so i am not quite sure if i can use new here because it is not a constant expression.
My code:
#include<iostream>
using namespace std;
struct str {
int x;
int y;
int z;
};
int main(){
cin>>N;
str Array1[N][N]; //N can be up to 200
str Array2[N][N];
};
How could i initialize them in heap?I know that for a 1-D array i can use a vector but i don't know if this can somehow be applied to a 2-D array.
How 2-or-more-dimensional arrays work in C++
A 1D array is simple to implement and dereference. Assuming the array name is arr, it only requires one dereference to get access to an element.
Arrays with 2 or more dimensions, whether dynamic or stack-based, require more steps to create and access. To draw an analogy between a matrix and this, if arr is a 2D array and you want access to a specific element, let's say arr[row][col], there are actually 2 dereferences in this step. The first one, arr[row], gives you access to the row-th row of col elements. The second and final one, arr[row][col] reaches the exact element that you need.
Because arr[row][col] requires 2 dereferences for one to gain access, arr is no longer a pointer, but a pointer to pointer. With regards to the above, the first dereference gives you a pointer to a specific row (a 1D array), while the second dereference gives the actual element.
Thus, dynamic 2D arrays require you to have a pointer to pointer.
To allocate a dynamic 2D array with size given at runtime
First, you need to create an array of pointers to pointers to your data type of choice. Since yours is string, one way of doing it is:
std::cin >> N;
std::string **matrix = new string*[N];
You have allocated an array of row pointers. The final step is to loop through all the elements and allocate the columns themselves:
for (int index = 0; index < N; ++index) {
matrix[index] = new string[N];
}
Now you can dereference it just like you would a normal 2D grid:
// assuming you have stored data in the grid
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << matrix[row][col] << std::endl;
}
}
One thing to note: dynamic arrays are more computationally-expensive than their regular, stack-based counterparts. If possible, opt to use STL containers instead, like std::vector.
Edit: To free the matrix, you go "backwards":
// free all the columns
for (int col = 0; col < N; ++col) {
delete [] matrix[col];
}
// free the list of rows
delete [] matrix;
When wanting to allocate a 2D array in C++ using the new operator, you must declare a (*pointer-to-array)[N] and then allocate with new type [N][N];
For example, you can declare and allocate for your Array1 as follows:
#define N 200
struct str {
int x, y, z;
};
int main (void) {
str (*Array1)[N] = new str[N][N]; /* allocate */
/* use Array1 as 2D array */
delete [] Array1; /* free memory */
}
However, ideally, you would want to let the C++ containers library type vector handle the memory management for your. For instance you can:
#include<vector>
..
std::vector <std::vector <str>> Array1;
Then to fill Array1, fill a temporary std::vector<str> tmp; for each row (1D array) of str and then Array1.push_back(tmp); to add the filled tmp vector to your Array1. Your access can still be 2D indexing (e.g. Array1[a][b].x, Array1[a][b].y, ..., but you benefit from auto-memory management provided by the container. Much more robust and less error prone than handling the memory yourself.
Normally, you can initialize memory in heap by using 'new' operator.
Hope this can help you:
// Example program
#include <iostream>
struct str {
int x;
int y;
int z;
};
int main()
{
int N;
std::cin>>N;
str **Array1 = new str*[N]; //N can be up to 200
for (int i = 0; i < N; ++i) {
Array1[i] = new str[N];
}
// set value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
Array1[row][col].x=10;
Array1[row][col].y=10;
Array1[row][col].z=10;
}
}
// get value
for (int row = 0; row < N; ++row) {
for (int col = 0; col < N; ++col) {
std::cout << Array1[row][col].x << std::endl;
std::cout << Array1[row][col].y << std::endl;
std::cout << Array1[row][col].z << std::endl;
}
}
}

What is the recommended way loop through an array in C++?

I'm learning C++ (reasonably confident in JavaScript) and I can't find a C++ equivalent to the JS array.length;. I want a simple way to loop through an array based on the array length?
I have followed a number of tutorials but all seam to require the array length to be manually stated in the for loop (or pushed into the function)?
Below code gets an error and adding the #include causes a compiler error (DEV++).
Is there a C++ or reason why there is no simple call of the array length?
#include <iostream>
using namespace std;
int main () {
int shoppingList [3] = {1, 2, 3};
for (int i=0; i < shoppingList.size(); i++) {
cout << shoppingList[i] << endl;
}
}
For a C-style array like you have you can use range-based for loops:
for (int value : shoppingList)
{
std::cout << value << '\n';
}
As for getting the number of elements from an array, there's a "trick": You know the size of the array itself, and you know the size of each element in the array. That means if you divide the size of the array with the size of each element, you will get the number of elements.
In short
size_t numberElements = sizeof shoppingList / sizeof shoppingList[0];
Important note: This "trick" only works with actual arrays! Once an array have decayed to a pointer (to its first element, which often happens) all you're left with is the pointer. There's no way to get the size of the memory it points to, and this "trick" can not be used.
And as mentioned in my comment, the "best" solution is to use either std::array or std::vector.
Built-in types don’t have member functions with C++. However, there is a non-member std::size(array) function:
for (std::size_t i{}; i != std::size(shoppingList); ++i) {
// ...
}
Note that the counter is usinf std::size_t to match the signedness of the result of std::size(...). Also, do not use the sizeof hack suggested in other answers: it is a trap! The cde will happily compile when passing pointers to it but it will also produce the wrong result.
Of course, the idiomatic way to iterate over a range in C++, including arrays, is (assuming you only need the values and not their position):
for (int val: shoppingList) {
// ...
}
Array doesn't have a direct size() member function, you can find the size of an array like this int size = sizeof(arr)/sizeof(arr[0]); and use it in the for loop.
#include <iostream>
using namespace std;
int main () {
int shoppingList [3] = {1, 2, 3};
int size = sizeof(shoppingList)/sizeof(shoppingList[0]);
for (int i=0; i < size(); i++) {
cout << shoppingList[i] << endl;
}
}
You can do something like, sizeof(A)/sizeof(A[0]). This would give you the total number of elements in the array.
Let's take an example A = {1,2,3,4,5} // all ints
If you evaluate sizeof(A)/sizeof(A[0]), it would give you 5 and as you see, you would not need to manually enter the size of the array.
Hope this helps. :)
#include <iostream>
using namespace std;
int main()
{
A = {1,2,3,4,5};
for (int i = 0; i< sizeof(A)/sizeof(A[0]); i++)
//whatever you want to do with this
return 1;
}

3D array C++ using int [] operator

I'm new to C/C++ and I've been cracking my head but still got no idea how to make an "structure" like this
It's supposed to be a 3D dynamic array using pointers.
I started like this, but got stuck there
int x=5,y=4,z=3;
int ***sec=new int **[x];
It would be enough to know how to make it for a static size of y and z;
Please, I'd appreciate that you help me.
Thanks in advance.
To create dynamically 3D array of integers, it's better you understand 1D and 2D array first.
1D array: You can do this very easily by
const int MAX_SIZE=128;
int *arr1D = new int[MAX_SIZE];
Here, we are creating an int-pointer which will point to a chunk of memory where integers can be stored.
2D array: You may use the solution of above 1D array to create a 2D array. First, create a pointer which should point to a memory block where only other integer pointers are held which ultimately point to actual data. Since our first pointer points to an array of pointers so this will be called as pointer-to-pointer (double pointer).
const int HEIGHT=20;
const int WIDTH=20;
int **arr2D = new int*[WIDTH]; //create an array of int pointers (int*), that will point to
//data as described in 1D array.
for(int i = 0;i < WIDTH; i++){
arr2D[i] = new int[HEIGHT];
}
3D Array: This is what you want to do. Here you may try both the scheme used in above two cases. Apply the same logic as 2D array. Diagram in question explains all. The first array will be pointer-to-pointer-to-pointer (int*** - since it points to double pointers). The solution is as below:
const int X=20;
const int Y=20;
const int z=20;
int ***arr3D = new int**[X];
for(int i =0; i<X; i++){
arr3D[i] = new int*[Y];
for(int j =0; j<Y; j++){
arr3D[i][j] = new int[Z];
for(int k = 0; k<Z;k++){
arr3D[i][j][k] = 0;
}
}
}
// one-liner
typedef std::vector<std::vector<std::vector<int> > > ThreeDimensions;
// expanded
typedef std::vector<int> OneDimension;
typedef std::vector<OneDimension> TwoDimensions;
typedef std::vector<TwoDimension> ThreeDimensions;
(this is tagged c++, after all)
EDIT in response to Joe's question
hello again Joe =) sure. here's the example:
#include <vector>
#include <iostream>
int main(int argc, char* const argv[]) {
/* one-liner */
typedef std::vector<std::vector<std::vector<int> > >ThreeDimensions;
/* expanded */
typedef std::vector<int>OneDimension;
typedef std::vector<OneDimension>TwoDimensions;
typedef std::vector<TwoDimensions>ThreeDimensions;
/*
create 3 * 10 * 25 array filled with '12'
*/
const size_t NElements1(25);
const size_t NElements2(10);
const size_t NElements3(3);
const int InitialValueForAllEntries(12);
ThreeDimensions three_dim(NElements3, TwoDimensions(NElements2, OneDimension(NElements1, InitialValueForAllEntries)));
/* the easiest way to assign a value is to use the subscript operator */
three_dim[0][0][0] = 11;
/* now read the value: */
std::cout << "It should be 11: " << three_dim[0][0][0] << "\n";
/* every other value should be 12: */
std::cout << "It should be 12: " << three_dim[0][1][0] << "\n";
/* get a reference to a 2d vector: */
TwoDimensions& two_dim(three_dim[1]);
/* assignment */
two_dim[2][4] = -1;
/* read it: */
std::cout << "It should be -1: " << two_dim[2][4] << "\n";
/* get a reference to a 1d vector: */
OneDimension& one_dim(two_dim[2]);
/* read it (this is two_dim[2][4], aka three_dim[1][2][4]): */
std::cout << "It should be -1: " << one_dim[4] << "\n";
/* you can also use at(size_t): */
std::cout << "It should be 12: " << one_dim.at(5) << "\n";
return 0;
}
You can try:
for(int i=0;i<x;i++) {
sec[i] = new int *[y];
for(int j=0;j<y;j++) {
sec[i][j] = new int [z];
}
}
And once you are done using this memory you can deallocate it as:
for(int i=0;i<x;i++) {
for(int j=0;j<y;j++) {
delete [] sec[i][j];
}
delete [] sec[i];
}
delete [] sec;
Comprehensive answers.
If you are really writing this in C++ (not rough C) I think you should take another look at this complicated data structure. IMO redesign while keeping in mind what you are trying to do would be better.
What you're trying to do is not idiomatic in C++. Of course, you can use a int***pointer for this, but this is strongly discouraged. In C++ we have better ways to get there.
vector<vector<vector<int> > > foo (5,vector<vector<int> >(4, vector<int>(3)));
This will result in something with the memory layout similar to what you asked for. It supports dynamic resizing and inner vectors to have different sizes just like in your picture. In addition, you don't have to worry about manual allocation / deletion of any of it. Also, the vectors know their size so you don't have to remember it somewhere.
But if you just want a "rectangular" 3D array where all the elements are consecutivly stored in the same memory block, you could use a boost::multiarray.
OK let us take your beginnings
int ***sec = new int**[x];
sec is now an array of int**s of length x, so now I am just going to focus on making the zeroeth element be what you want
sec[0] = new int*[y];
Now sec[0] points to array of int*s of length y, now just need to get the last bit of the tree done, so
sec[0][0] = new int[z];
And finally to get it to the form in your diagram
sec[0][0][z-1] = 0;
This does seem a little like a homework question, make sure you actually understand the answer and why it works.
If it's the actual arrays you'r having problems with look here: Declaring a pointer to multidimensional array and allocating the array
Not sure exactly what you want but you might want to read up on about linked lists.

How do I best handle dynamic multi-dimensional arrays in C/C++?

What is the accepted/most commonly used way to manipulate dynamic (with all dimensions not known until runtime) multi-dimensional arrays in C and/or C++.
I'm trying to find the cleanest way to accomplish what this Java code does:
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int rows=sc.nextInt();
int cols=sc.nextInt();
int[][] data=new int[rows][cols];
manipulate(data);
}
public static void manipulate(int[][] data){
for(int i=0;i<data.length;i++)
for(int j=0;j<data[0].length.j++){
System.out.print(data[i][j]);
}
}
(reads from std_in just to clarify that dimensions aren't known until runtime).
Edit:I noticed that this question is pretty popular even though it's pretty old. I don't actually agree with the top voted answer. I think the best choice for C is to use a single-dimensional array as Guge said below "You can alloc rowscolssizeof(int) and access it by table[row*cols+col].".
There is a number of choices with C++, if you really like boost or stl then the answers below might be preferable, but the simplest and probably fastest choice is to use a single dimensional array as in C.
Another viable choice in C and C++ if you want the [][] syntax is lillq's answer down at the bottom is manually building the array with lots of malloc's.
Use boost::multi_array.
As in your example, the only thing you need to know at compile time is the number of dimensions. Here is the first example in the documentation :
#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;
}
Edit: As suggested in the comments, here is a "simple" example application that let you define the multi-dimensional array size at runtime, asking from the console input.
Here is an example output of this example application (compiled with the constant saying it's 3 dimensions) :
Multi-Array test!
Please enter the size of the dimension 0 : 4
Please enter the size of the dimension 1 : 6
Please enter the size of the dimension 2 : 2
Text matrix with 3 dimensions of size (4,6,2) have been created.
Ready!
Type 'help' for the command list.
>read 0.0.0
Text at (0,0,0) :
""
>write 0.0.0 "This is a nice test!"
Text "This is a nice test!" written at position (0,0,0)
>read 0.0.0
Text at (0,0,0) :
"This is a nice test!"
>write 0,0,1 "What a nice day!"
Text "What a nice day!" written at position (0,0,1)
>read 0.0.0
Text at (0,0,0) :
"This is a nice test!"
>read 0.0.1
Text at (0,0,1) :
"What a nice day!"
>write 3,5,1 "This is the last text!"
Text "This is the last text!" written at position (3,5,1)
>read 3,5,1
Text at (3,5,1) :
"This is the last text!"
>exit
The important parts in the code are the main function where we get the dimensions from the user and create the array with :
const unsigned int DIMENSION_COUNT = 3; // dimension count for this test application, change it at will :)
// here is the type of the multi-dimensional (DIMENSION_COUNT dimensions here) array we want to use
// for this example, it own texts
typedef boost::multi_array< std::string , DIMENSION_COUNT > TextMatrix;
// this provide size/index based position for a TextMatrix entry.
typedef std::tr1::array<TextMatrix::index, DIMENSION_COUNT> Position; // note that it can be a boost::array or a simple array
/* This function will allow the user to manipulate the created array
by managing it's commands.
Returns true if the exit command have been called.
*/
bool process_command( const std::string& entry, TextMatrix& text_matrix );
/* Print the position values in the standard output. */
void display_position( const Position& position );
int main()
{
std::cout << "Multi-Array test!" << std::endl;
// get the dimension informations from the user
Position dimensions; // this array will hold the size of each dimension
for( int dimension_idx = 0; dimension_idx < DIMENSION_COUNT; ++dimension_idx )
{
std::cout << "Please enter the size of the dimension "<< dimension_idx <<" : ";
// note that here we should check the type of the entry, but it's a simple example so lets assume we take good numbers
std::cin >> dimensions[dimension_idx];
std::cout << std::endl;
}
// now create the multi-dimensional array with the previously collected informations
TextMatrix text_matrix( dimensions );
std::cout << "Text matrix with " << DIMENSION_COUNT << " dimensions of size ";
display_position( dimensions );
std::cout << " have been created."<< std::endl;
std::cout << std::endl;
std::cout << "Ready!" << std::endl;
std::cout << "Type 'help' for the command list." << std::endl;
std::cin.sync();
// we can now play with it as long as we want
bool wants_to_exit = false;
while( !wants_to_exit )
{
std::cout << std::endl << ">" ;
std::tr1::array< char, 256 > entry_buffer;
std::cin.getline(entry_buffer.data(), entry_buffer.size());
const std::string entry( entry_buffer.data() );
wants_to_exit = process_command( entry, text_matrix );
}
return 0;
}
And you can see that to accede an element in the array, it's really easy : you just use the operator() as in the following functions :
void write_in_text_matrix( TextMatrix& text_matrix, const Position& position, const std::string& text )
{
text_matrix( position ) = text;
std::cout << "Text \"" << text << "\" written at position ";
display_position( position );
std::cout << std::endl;
}
void read_from_text_matrix( const TextMatrix& text_matrix, const Position& position )
{
const std::string& text = text_matrix( position );
std::cout << "Text at ";
display_position(position);
std::cout << " : "<< std::endl;
std::cout << " \"" << text << "\"" << std::endl;
}
Note : I compiled this application in VC9 + SP1 - got just some forgettable warnings.
There are two ways to represent a 2-dimension array in C++. One being more flexible than the other.
Array of arrays
First make an array of pointers, then initialize each pointer with another array.
// First dimension
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
// Second dimension
array[i] = new int[4];
}
// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
for( int j = 0; j < 4; ++j )
{
std::cout << array[i][j];
}
}
THe problem with this method is that your second dimension is allocated as many arrays, so does not ease the work of the memory allocator. Your memory is likely to be fragmented resulting in poorer performance. It provides more flexibility though since each array in the second dimension could have a different size.
Big array to hold all values
The trick here is to create a massive array to hold every data you need. The hard part is that you still need the first array of pointers if you want to be able to access the data using the array[i][j] syntax.
int* buffer = new int[3*4];
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
array[i] = array + i * 4;
}
The int* array is not mandatory as you could access your data directly in buffer by computing the index in the buffer from the 2-dimension coordinates of the value.
// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
for( int j = 0; j < 4; ++j )
{
const int index = i * 4 + j;
std::cout << buffer[index];
}
}
The RULE to keep in mind
Computer memory is linear and will still be for a long time. Keep in mind that 2-dimension arrays are not natively supported on a computer so the only way is to "linearize" the array into a 1-dimension array.
You can alloc rowscolssizeof(int) and access it by table[row*cols+col].
Here is the easy way to do this in C:
void manipulate(int rows, int cols, int (*data)[cols]) {
for(int i=0; i < rows; i++) {
for(int j=0; j < cols; j++) {
printf("%d ", data[i][j]);
}
printf("\n");
}
}
int main() {
int rows = ...;
int cols = ...;
int (*data)[cols] = malloc(rows*sizeof(*data));
manipulate(rows, cols, data);
free(data);
}
This is perfectly valid since C99, however it is not C++ of any standard: C++ requires the sizes of array types to be compile times constants. In that respect, C++ is now fifteen years behind C. And this situation is not going to change any time soon (the variable length array proposal for C++17 does not come close to the functionality of C99 variable length arrays).
The standard way without using boost is to use std::vector :
std::vector< std::vector<int> > v;
v.resize(rows, std::vector<int>(cols, 42)); // init value is 42
v[row][col] = ...;
That will take care of new / delete the memory you need automatically. But it's rather slow, since std::vector is not primarily designed for using it like that (nesting std::vector into each other). For example, all the memory is not allocated in one block, but separate for each column. Also the rows don't have to be all of the same width. Faster is using a normal vector, and then doing index calculation like col_count * row + col to get at a certain row and col:
std::vector<int> v(col_count * row_count, 42);
v[col_count * row + col) = ...;
But this will loose the capability to index the vector using [x][y]. You also have to store the amount of rows and cols somewhere, while using the nested solution you can get the amount of rows using v.size() and the amount of cols using v[0].size().
Using boost, you can use boost::multi_array, which does exactly what you want (see the other answer).
There is also the raw way using native C++ arrays. This envolves quite some work and is in no way better than the nested vector solution:
int ** rows = new int*[row_count];
for(std::size_t i = 0; i < row_count; i++) {
rows[i] = new int[cols_count];
std::fill(rows[i], rows[i] + cols_count, 42);
}
// use it... rows[row][col] then free it...
for(std::size_t i = 0; i < row_count; i++) {
delete[] rows[i];
}
delete[] rows;
You have to store the amount of columns and rows you created somewhere since you can't receive them from the pointer.
2D C-style arrays in C and C++ are a block of memory of size rows * columns * sizeof(datatype) bytes.
The actual [row][column] dimensions exist only statically at compile time. There's nothing there dynamically at runtime!
So, as others have mentioned, you can implement
int array [ rows ] [ columns ];
As:
int array [ rows * columns ]
Or as:
int * array = malloc ( rows * columns * sizeof(int) );
Next: Declaring a variably sized array. In C this is possible:
int main( int argc, char ** argv )
{
assert( argc > 2 );
int rows = atoi( argv[1] );
int columns = atoi( argv[2] );
assert(rows > 0 && columns > 0);
int data [ rows ] [ columns ]; // Yes, legal!
memset( &data, 0, sizeof(data) );
print( rows, columns, data );
manipulate( rows, columns, data );
print( rows, columns, data );
}
In C you can just pass the variably-sized array around the same as a non-variably-sized array:
void manipulate( int theRows, int theColumns, int theData[theRows][theColumns] )
{
for ( int r = 0; r < theRows; r ++ )
for ( int c = 0; c < theColumns; c ++ )
theData[r][c] = r*10 + c;
}
However, in C++ that is not possible. You need to allocate the array using dynamic allocation, e.g.:
int *array = new int[rows * cols]();
or preferably (with automated memory management)
std::vector<int> array(rows * cols);
Then the functions must be modified to accept 1-dimensional data:
void manipulate( int theRows, int theColumns, int *theData )
{
for ( int r = 0; r < theRows; r ++ )
for ( int c = 0; c < theColumns; c ++ )
theData[r * theColumns + c] = r*10 + c;
}
If you're using C instead of C++ you might want to look at the Array_T abstraction in Dave Hanson's library C Interfaces and Implementations. It's exceptionally clean and well designed. I have my students do a two-dimensional version as an exercise. You could do that or simply write an additional function that does an index mapping, e.g.,
void *Array_get_2d(Array_T a, int width, int height, int i, int j) {
return Array_get(a, j * width, i, j);
}
It is a bit cleaner to have a separate structure where you store the width, the height, and a pointer to the elements.
I recently came across a similar problem. I did not have Boost available. Vectors of vectors turned out to be pretty slow in comparison to plain arrays. Having an array of pointers makes the initialization a lot more laborious, because you have to iterate through every dimension and initialize the pointers, possibly having some pretty unwieldy, cascaded types in the process, possibly with lots of typedefs.
DISCLAIMER: I was not sure if I should post this as an answer, because it only answers part of your question. My apologies for the following:
I did not cover how to read the dimensions from standard input, as other commentators had remarked.
This is primarily for C++.
I have only coded this solution for two dimensions.
I decided to post this anyway, because I see vectors of vectors brought up frequently in reply to questions about multi-dimensional arrays in C++, without anyone mentioning the performance aspects of it (if you care about it).
I also interpreted the core issue of this question to be about how to get dynamic multi-dimensional arrays that can be used with the same ease as the Java example from the question, i.e. without the hassle of having to calculate the indices with a pseudo-multi-dimensional one-dimensional array.
I didn't see compiler extensions mentioned in the other answers, like the ones provided by GCC/G++ to declare multi-dimensional arrays with dynamic bounds the same way you do with static bounds. From what I understand, the question does not restrict the answers to standard C/C++. ISO C99 apparently does support them, but in C++ and prior versions of C they appear to be compiler-specific extensions. See this question: Dynamic arrays in C without malloc?
I came up with a way that people might like for C++, because it's little code, has the ease of use of the built-in static multi-dimensional arrays, and is just as fast.
template <typename T>
class Array2D {
private:
std::unique_ptr<T> managed_array_;
T* array_;
size_t x_, y_;
public:
Array2D(size_t x, size_t y) {
managed_array_.reset(new T[x * y]);
array_ = managed_array_.get();
y_ = y;
}
T* operator[](size_t x) const {
return &array_[x * y_];
}
};
You can use it like this. The dimensions do not
auto a = Array2D<int>(x, y);
a[xi][yi] = 42;
You can add an assertion, at least to all but the last dimension and extend the idea to to more than two dimensions. I have made a post on my blog about alternative ways to get multi-dimensional arrays. I am also much more specific on the relative performance and coding effort there.
Performance of Dynamic Multi-Dimensional Arrays in C++
You could use malloc to accomplish this and still have it accessible through normal array[][] mean, verses the array[rows * cols + cols] method.
main()
{
int i;
int rows;
int cols;
int **array = NULL;
array = malloc(sizeof(int*) * rows);
if (array == NULL)
return 0; // check for malloc fail
for (i = 0; i < rows; i++)
{
array[i] = malloc(sizeof(int) * cols)
if (array[i] == NULL)
return 0; // check for malloc fail
}
// and now you have a dynamically sized array
}
There is no way to determine the length of a given array in C++. The best way would probably be to pass in the length of each dimension of the array, and use that instead of the .length property of the array itself.