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.
Creating Multidimensional Arrays You can create a multidimensional array by creating a 2-D matrix first, and then extending it. For example, first define a 3-by-3 matrix as the first page in a 3-D array. Now add a second page. To do this, assign another 3-by-3 matrix to the index value 2 in the third dimension.
In C programming, you can create an array of arrays. These arrays are known as multidimensional arrays. For example, float x[3][4];
The data items in a multidimensional array are stored in the form of rows and columns. Also, the memory allocated for the multidimensional array is contiguous. So the elements in multidimensional arrays can be stored in linear storage using two methods i.e., row-major order or column-major order.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With