I want to create a dynamic 2d array in a separate function. The size of the array will be determined at runtime.
Pass an array directly:
void foo(int **arr,int width,int height)
{
arr=new int*[width];
for(int i=0;i<height;i++)
{
arr[i]=new int[height];
}
//fill...
}
...
int** array;
foo(array)
doesn't seem to work
Pass an array via a pointer
void foo(int ***arr,int width,int height)
{
*arr=new int*[width];
for(int i=0;i<height;i++)
{
*arr[i]=new int[height];
}
//fill...
}
...
int **array;
foo(&array)
doesnt seem to work either
How do I do that?
I think that your "problem" is caused by ignoring operator precedence
Second code you posted seems to have mistake on line with:
*arr[i]=new int[height];
which should be
(*arr)[i]=new int[height];
Also, as other pointed out, working with raw pointers could sometimes be pretty evil (like in your example with Pointer to Pointer to Pointer), raw pointers could also cause some problems with memory leaks, dangling pointers,etc. Use something "more practical" like std::vector or some of the other STL containers.
(Note: By term "STL", I mean part of Standard library based on STL)
Let's assume you have to create 2d arrays this way (with an int**).
Instead of trying to pass pointers, return the value that denotes the 2d array.
Second, your code had a bug in that you were looping over the height when you should be looping over the width. Your code would have gone into undefined behavior if height > width.
Third, I don't know if you meant width to be the first dimension or height to be the first dimension, so let's assume that what you wrote is what you meant, i.e. width is the first dimension and height is the inner dimension.
int **foo(int width, int height)
{
int **arr = new int*[width];
for(int i=0; i<width; i++)
arr[i]=new int[height];
return arr;
}
//....
int width = 10, height = 10;
int** array = foo(width, height);
Then you have to write code to delete the allocated data:
for (int i = 0; i < width; ++i)
delete [] array [i];
delete [] array;
Now having said the above, and the above should work, a more optimal version is found here, where the data is one contiguous block instead of separate allocated blocks. This reduces the number of times new[] and delete [] would need to be called.
Generally speaking, multidimensional arrays should never, never be created like this. You should be using a single array wrapped in an object that provides row, column, table, etc. access using the operator() function.
You should also never, never be using raw pointers (except in weird, extenuating circumstances) which is why I'm using STL's std::vector class to implement your code.
class array_2d {
public:
array_2d(size_t width, size_t height) :
width(width),
height(height),
_array(width * height)
{}
int & operator()(size_t x, size_t y) {
return _array[y * width + x];
}
const int & operator()(size_t x, size_t y) const {
return _array[y * width + x];
}
std::pair<size_t, size_t> get_size() const {
return std::make_pair<size_t, size_t>(width, height);
}
private:
size_t width, height;
std::vector<int> _array;
};
int main() {
array_2d my_array(5,5);
my_array(3,3) = 7;
std::cout << my_array(3,3) << std::endl;
return 0;
}
====
7
There's a lot of stuff I didn't include (and the code would be significantly more complex if you were to implement this as a raw pointer) but this is a far superior way to write a 2-dimensional (or more dimensions, if you need it) array.
Related
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible? (I am doing this because, I pass an 2d array of unknow size to a func. So I cast 2d array to a void pointer and then in that func I want it to recast back.)
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
//and recast back
int (*tab2)[5] = (int (*)[5])p; //this is working
int (*tab3)[i] = (int (*)[i])p; // but this is not
First I suggest to don't use runtime size for array in C/C++, except you using STL vector as an array. so instead of:
int i = 5;
you must use:
const int i = 5;
except you use Vector that is safe and better than intrinsic arrays.
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time? Is it somehow possible?
If we talk about C intrinsic array, It is not possible!
why it is not possible?
because C/C++ compiler not aware of your the array size, borders,.... so if you cast your 2d array to 1d array, it is possible. it is the reason that tab2 array can access to first 5th element of your array. really C/C++ compiler cannot distinguish the different of
int a[3][3]
with
int a[3*3]
so You must be aware of at least one dimension of your array:
int main() {
const int i = 3,j = 4;
int tab1[i][j] = {1,2,3,4,5,6,7,8,9,10,11};
//cast to void pointer
void *p = (void *)tab1;
auto a = (int (*)[i][12/i])p;
return 0;
}
In the above example, I aware about i and total count(12) and I calculate the second dimension.
I use auto keyword that very easily inferred the data type.
int i = 5; int tab1[i][i]; is a VLA. It's not standard C++ and should be avoided.
An array-of-pointers-to-arrays (and vector-of-vectors) won't be as efficient as a true 2D array since it's no longer contiguous (int tab1[5][5] is a true 2D array and is stored contiguously in memory, but the dimensions must be known at compile-time).
You can easily create a custom 2D container class that would store the data in a contiguous 1D vector and apply some simple math (x + y*width) to access the elements.
Example:
class Matrix {
std::vector<int> data;
public:
const int width;
const int height;
Matrix(int width, int height) : width(width), height(height), data(width*height) {}
int operator()(int x, int y) const {
return data[y * width + x];
}
int& operator()(int x, int y) {
return data[y * width + x];
}
};
void print(Matrix const& mat) {
for (int y = 0; y < mat.height; y++) {
for (int x = 0; x < mat.width; x++)
std::cout << mat(x, y) << " ";
std::cout << std::endl;
}
}
int main() {
Matrix mat(5, 5);
mat(1, 1) = 1;
mat(2, 2) = 2;
mat(3, 3) = 3;
print(mat);
}
For convenience this overloads the () operator. It's still possible with the [] operator but that will require a proxy class to access the inner dimension(s) and also putting y before x since the dimensions are actually reversed.
int tab1[i][i]; is a non-standard compiler extension for variable length arrays. It is better to avoid this because it is not portable and hard to deal with as you are seeing. You would be better with:
std::vector<std::vector<int>> tab1(i, std::vector<int>(i));
Then your function can simply take this vector:
void foo(const std::vector<std::vector<int>>& array) { ....
how can I cast void pointer to a 2d array (array of pointers to arrays of ints), when I dont know array size at compile time?
You can't. You can only cast to a type that is known at compile time.
What you can do is convert to a pointer to first element of the first row: int* p = static_cast<int*>(tab1);. You can then treat the array as one dimensional1. Converting two dimensional indices to one dimensional requires some trivial math: x, y -> x + y * i.
1 As long as you don't mind the technicality that pointer arithmetic across the sub array boundary might technically not be allowed by the standard. But that rule is silly. If you're concerned about this, then you should create a one dimensional array in the first place.
The problem you are having here is that the size of an array must be defined at compile time.
In your case, you have multiple options:
make i a constexpr like constexpr int i = 5;
use a int ** instead:
int i = 5;
int tab1[i][i];
//cast to void pointer
void *p = (void *)tab1;
// cast to int **
auto tab1_p = (int **)p;
// use it like it was an array
tab1_p[1][3] = 5;
I need a 2d character array for use in a trash API that absolutely requires use of arrays and NOT vectors (much emphasis on this because all of my searching just had answers "use a vector". I wish I could).
I figured the way to do it would be to allocate an external array of size rows * character length, instead of doing:
char** arr;
arr = new char*[100];
// for loop that allocates the internal arrays
But I'm not sure what method I would need to use to make it contiguous? Do I need to allocate a massive 1D array first, then assign the 1D array to the 2D array in chunks?
As other answers have said: allocate n * m entries to create the contiguous data, and then it can be wrapped in pointers to create a 2d array.
... absolutely requires use of arrays and NOT vectors ...
I'm not sure if vector is a constraint based on the API being used, or requirements -- but it's worth noting that vector can be used for the memory management of the implementation -- while still using the raw data (which can be accessed by &vec[0] or vec.data(), which returns a pointer to the first element of the array, and can be used with functions accepting raw pointers).
Since this question is about c++, one option is to wrap an array of n * m in a class that acts like a 2-d array while actually being contiguous.
A simple example could be:
class array_2d
{
public:
array_2d( std::size_t rows, std::size_t columns )
: m_rows(rows), m_cols(columns), m_array( new char[rows * columns] )
{
}
~array_2d()
{
delete [] m_array;
}
// row-major vs column-major is up to your implementation
T& operator()( std::ptrdiff_t row, std::ptrdiff_t col )
{
// optional: do bounds checking, throw std::out_of_range first
return m_array[row * m_cols + col];
// alternatively:
// return m_array[col * m_rows + row];
}
// get pointer to the array (for raw calls)
char* data()
{
return m_array;
}
private:
char* m_array;
std::size_t m_rows;
std::size_t m_cols;
};
(Ideally char* would be std::unique_ptr<char[]> or std::vector<char> to avoid memory-leak conditions, but since you said vector is not viable, I'm writing this minimally)
This example overloads the call operator (operator()) -- but this could also be a named function like at(...); the choice would be up to you. The use of such type would then be:
auto array = array_2d(5,5); // create 5x5 array
auto& i01 = array(0,1); // access row 0, column 1
Optionally, if the [][] syntax is important to behave like a 2d-array (rather than the (r,c) syntax), you can return a proxy type from a call to an overloaded operator [] (untested):
class array_2d_proxy
{
public:
array_2d_proxy( char* p ) : m_entry(p){}
char& operator[]( std::ptrdiff_t col ){ return m_entry[col]; }
private:
char* m_entry;
};
class array_2d
{
...
array_2d_proxy operator[]( std::ptrdiff_t row )
{
return array_2d_proxy( m_array + (row * m_cols) );
}
...
};
This would allow you to have the 'normal' 2d-array syntax, while still being contiguous:
auto& i00 = array[0][0];
This is a good way to do it:
void array2d(int m, int n) {
std::vector<char> bytes(m * n);
std::vector<char*> arrays;
for (int i = 0; i != m * n; i += n) {
arrays.push_back(bytes.data() + i);
}
char** array2d = arrays.data();
// whatever
}
The main problem in C++ with "continuous 2d arrays with variable column length" is that an access like myArray[r][c] requires the compiler to know the column size of the type of myArray at compile time (unlike C, C++ does not support variable length arrays (VLAs)).
To overcome this, you could allocate a continuous block of characters, and additionally create an array of pointers, where each pointer points to the begin of a row. With such a "view", you can then address the continuous block of memory indirectly with a myArray[r][c]-notation:
int main() {
// variable nr of rows/columns:
int rows = 2;
int columns = 5;
// allocate continuous block of memory
char *contingousMemoryBlock = new char[rows*columns];
// for demonstration purpose, fill in some content
for (int i=0; i<rows*columns; i++) {
contingousMemoryBlock[i] = '0' + i;
}
// make an array of pointers as a 2d-"view" of the memory block:
char **arr2d= new char*[rows];
for (int r=0; r<rows;r++) {
arr2d[r] = contingousMemoryBlock + r*columns;
}
// access the continuous memory block as a 2d-array:
for (int r=0; r<rows; r++) {
for (int c=0; c<columns; c++) {
cout << arr2d[r][c];
}
cout << endl;
}
}
I need a 2d array with fixed width and height that can only change the individual values stored in it. It is declared in a header and later initialized in a source file.
What I found made me try the following snippets; unfortunately questions were about either 1d or non-const arrays and did not match my situation.
int *const *const a = new int[10][10];
int *const *const b = new int[10][10]();
int *const *const c = new int*[10];
for (int i = 0; i < 10; ++i) {
c[i] = new int[10];
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
Do I not need a different type for this array? I was thinking about int d[][] but it doesn't have constant width and height.
It seems to me like a paradox (if it exists in the c++ world), am I missing something?
I was thinking about int d[][] but it doesn't have constant width and height.
int d[][] does not make sense (and will be rejected by the compiler). As far as multi-dimensional arrays are concerned, only the first dimension's size can be omitted to denote an incomplete type. The other dimensions' sizes are part of the type. You cannot omit them, much like you cannot omit the int.
In other words, if you have something like int d[5][10], then you can think of it as a one-dimensional array of element type int[10]. Generally, think of multi-dimensional arrays as a special case of one-dimensional arrays. It will make everything easier to understand.
The best solution to your problem in C++ is to create a class with private std::array<T, Width * Height> data; and int width member variables inside, and calculate the array offset from individual x and y arguments in a public member function, for example:
T& operator()(int x, int y)
{
return data[y * width + x];
}
If the dimensions are only known at run-time, then the only thing you have to change is using std::vector instead of std::array. Storage will still be contiguous.
Here is a complete example:
#include <vector>
#include <iostream>
class Matrix
{
public:
Matrix(int width, int height, int value) :
width(width),
data(width * height, value)
{}
int& operator()(int x, int y)
{
return data[y * width + x];
}
private:
int width;
std::vector<int> data;
};
int main()
{
Matrix m(5, 10, 123);
std::cout << m(7, 8) << "\n";
m(7, 8) = 124;
std::cout << m(7, 8) << "\n";
}
My hope was in the last example, but how can I use the "inner" arrays of c if they are not initialized and I am not able to initialize them since they are const?
That's not really true at all:
int * const * const c = new int*[10]
{
new int[10], new int[10], new int[10], new int[10], new int[10],
new int[10], new int[10], new int[10], new int[10], new int[10]
};
So if I have a class with a 2D array that I want to initialize with two parameters passed into the constructor, how would I do that, I keep running into errors because it won't let me update the two-d array at all in the constructor.
-- Update from the comments:
In my header file I tried both
int array[][]
and
int **array
and then in the .cpp file in the constructor I'm trying to do
array = new int[arg1][arg2]
Neither declaration of the array in the header file worked.
in the constructor I'm trying to do array = new array[arg1][arg2]
You need to specify the array type, like
array = new int[arg1][arg2];
Note that this works in C++11 only - when using older standards, the second array size needs to be const (which is probably not what you want).
There are also some additional articles discussing the same issue:
Multi-Dimensional Arrays
How to "new" a two-dimension array in C++?
Ideally, since you are using C++ anyway, you should use std::vector as proposed in another answer.
Vectors use a lot of overhead though, don't they? I'm trying to keep my memory use light. –
Start with std::vector. Once your application is running properly from a functional perspective, if you are still concerned about memory usage and/or performance, do benchmarking. If you properly encapsulate your 2D array in a class, you can always change the actual implementation of the array with no impact on the code which uses it.
Technically, if you want to make sure that you have one flat memory area which contains your array, you could use a 1-dimensional array to simulate a 2-dimensional array, like in the following code (just to get you the idea, certainly needs some improvement, especially copy construction and assignment operators are missing):
class Array2D {
private:
int *array;
int size1;
public:
Array2D(int arg1, int arg2) {
size1 = arg1;
array = new int[arg1 * arg2];
}
~Array2D() {
delete[] array;
}
int& at(int i1, int i2) {
return array[i1 * size1 + i2];
}
};
int main() {
Array2D array(10, 10);
array.at(2, 2) = 42;
std::cerr << array.at(2, 2);
return 0;
}
Simplest solution would be:
std::vector<std::vector<VALUE>> arr2(X, std::vector<VALUE>(Y));
Here is an 2d array example with bounds check and custom type, based upon the example from Andreas Fester.
#include <stdexcept>
template <typename T>
class Array2D {
private:
T *array;
unsigned int sizeX;
unsigned int sizeY;
public:
Array2D(unsigned int X, unsigned int Y) {
sizeX = X;
sizeY = Y;
array = new T[X * Y];
}
~Array2D() {
delete[] array;
}
T& at(unsigned int X, unsigned int Y) {
if((X > sizeX) || (Y > sizeY))
throw std::out_of_range("Bla bla");
return array[X * sizeX + Y];
}
};
int main() {
double MyValue;
Array2D<double> *MyArray = new Array2D<double>(10, 100);
MyArray->at(1,1) = 10.1;
MyValue = MyArray->at(1,1);
printf("Array value = %3.3f\n", MyValue);
return 0;
}
I have a program in which the object array's size is determined during the runtime, so it's dynamically allocated (2D array, read from file). I also have a function which takes these objects as parameters. The problem is if the function parameters are 2D arrays that are passed to the function the 2nd dimension should be determined. However, in my case it is not. My program won't compile since the prototype does not have the 2nd dimension mentioned.
Here is what I tried:
//global variables
int residentCount=0;
int hospitalCount=0;
Resident** residents;
Hospital** hospitals;
bool readFromFiles(const string, const string, const int); //sizes are determined in here
void print(Hospital*[hospitalCount], Resident*[residentCount]); //declaration issue
How can I solve this?
You are programming in C++, so you should:
avoid dynamic allocation and handling memory management on your own always when it's possible
take advantage of objects with automatic storage duration instead, follow RAII idiom
avoid using C-style arrays and actually avoid writing C code that is just compilable as C++ in general
use great features that C++ provides, especially those bundled within STL
avoid using global variables when local equivalents suffice
This is how it could look like:
typedef std::vector<Resident> Residents;
typedef std::vector<Hospital> Hospitals;
// passing by const reference:
void print(const std::vector<Hospitals>&, const std::vector<Residents>&);
int main()
{
std::vector<Hospitals> hospitals;
std::vector<Residents> residents;
...
} // <-- lifetime of automatics declared within main ends here
Note that hospitals and residents will be objects with automatic storage duration, usable in similar manner than your C-style 2D arrays. When the execution goes out of the scope of main, these vectors are destructed and memory, where their elements (including elements of their elements) resided before is automatically cleaned up.
Also note that I suggest you to pass by const reference, i.e. const std::vector<Hospitals>&, which prevents the copy of passed object being created and const keyword explicitely tells to the caller: "Although you pass this object by reference, I will not change it."
Just pass a pointer to the first element of the array and the dimensions, that's enough, example:
void PrintHospitals(Hospital* Hospitals, size_t HospitalRows, size_t HospitalColumns)
{
size_t i, j;
Hospital* hospital;
for (i = 0; i < HospitalRows; i++)
for (j = 0; j < HospitalColumns; j++)
{
hospital = Hospitals + HospitalColumns * i + j;
PrintHospital(hospital);
}
}
int main()
{
Hospital hospitals[10][20];
// ...
PrintHospitals(&hospitals[0][0], 10, 20);
return 0;
}
Here is a solution using templates to create two-dimensional array wrappers for existing data:
template<typename T>
class Array2d {
public:
int Rows;
int Cols;
T** Data;
Array2d(int rows, int cols, T** data) :
Rows(rows),
Cols(cols),
Data(data) { }
};
void print(Array2d<Hospital> h, Array2d<Resident> r) {
for (int i = 0; i < h.Rows; i++) {
for (int j = 0; j < h.Cols; j++) {
//Print Data[i][j] element here
}
}
// Other print code
}
int main()
{
Resident** residents;
Hospital** hospitals;
//Init data arrays
Array2d<Hospital> h(10, 10, hospitals);
Array2d<Resident> r(10, 10, residents);
print(h, r);
}