Helper function to construct 2D arrays - c++

Am I breaking C++ coding conventions writing a helper function which allocates a 2D array outside main()? Because my application calls for many N-dimensional arrays I want to ensure the same process is followed. A prototype which demonstrates what I am doing :
#include <iostream>
// my helper function which allocates the memory for a 2D int array, then returns its pointer.
// the final version will be templated so I can return arrays of any primitive type.
int** make2DArray(int dim1, int dim2)
{
int** out = new int* [dim1];
for (int i = 0; i < dim2; i++) { out[i] = new int[dim2];}
return out;
}
//helper function to deallocate the 2D array.
void destroy2DArray(int** name, int dim1, int dim2)
{
for (int i = 0; i < dim2; i++) { delete[] name[i]; }
delete[] name;
return;
}
int main()
{
int** test = make2DArray(2,2); //makes a 2x2 array and stores its pointer in test.
//set the values to show setting works
test[0][0] = 5;
test[0][1] = 2;
test[1][0] = 1;
test[1][1] = -5;
// print the array values to show accessing works
printf("array test is test[0][0] = %d, test[0][1] = %d, test[1][0] = %d, test[1][1] = %d",
test[0][0],test[0][1],test[1][0],test[1][1]);
//deallocate the memory held by test
destroy2DArray(test,2,2);
return 0;
}
My concern is this may not be memory-safe, since it appears I am allocating memory outside of the function in which it is used (potential out-of-scope error). I can read and write to the array when I am making a single small array, but am worried when I scale this up and there are many operations going on the code might access and alter these values.
I may be able to sidestep these issues by making an array class which includes these functions as members, but I am curious about this as an edge case of C++ style and scoping.

There is a difference between allocating 2D arrays like this and what you get when you declare a local variable like int ary[10][10] that based on your statement
My concern is that this operation may not be memory-safe, since it
appears that I am allocating memory for an array outside of the
function in which it is used (potential out-of-scope error)
I am guessing you do not fully understand.
You are allocating arrays on the heap. Declaring a local variable like int ary[10][10] places it on the stack. It is the latter case where you need to worry about not referencing that memory outside of its scope-based lifetime; that is, it is the following that is totally wrong:
//DON'T DO THIS.
template<size_t M, size_t N>
int* make2DArray( ) {
int ary[M][N];
return reinterpret_cast<int*>(ary);
}
int main()
{
auto foo = make2DArray<10, 10>();
}
because ary is local to the function and when the stack frame created by the call to make2DArray<10,10> goes away the pointer the function returns will be dangling.
Heap allocation is a different story. It outlives the scope in which it was created. It lasts until it is deleted.
But anyway, as others have said in comments, your code looks like C not C++. Prefer an std::vector<std::vector<int>> rather than rolling your own.

If you must use an array and are allergic to std::vector, create the 2d array (matrix) as one contiguous area in memory:
int * matrix = new int [dim1 * dim2];
If you want to set the values to zero:
std::fill(matrix, (matrix + (dim1 * dim2)), 0);
If you want to access a value at <row, column>:
int value = matrix[(row * column) + column];
Since the matrix was one allocation, you only need one delete:
delete [] matrix;

Related

Calling array with variable size as parameter

I was trying to make a program in which the user decides the dimensions of a 2-D array.
I'm getting an error on the function definition while compiling. Why is this wrong and what would be the correct way to do it?
I'm using the Dev-C++ 5.7.1 compiler (if that's relevant).
#include<iostream>
using namespace std;
int R=0,C=0;
void func(int);
int main() {
cin>>R>>C;
int array[C][R];
// DO STUFF HERE
func(array);
// DO SOME MORE STUFF
return 0;
}
void func(int arr[][R]) {
// DO STUFF HERE
}
ISO-C++ forbids VLAs. To dynamically allocate an array you'll either need to do some raw pointer tricks or use a vector of vectors.
vector of vectors approach:
std::cin >> R >> C;
std::vector<std::vector<int>> array(R, std::vector<int>(C));
The signature for func then becomes (const correctness may be different)
void func(const std::vector<std::vector<int>>& v);
The above is the easier, more maintainable, safer, shorter solution.
With pointers and pointers to pointers you can do it but it becomes more complicated, and you need to delete everything that you new
int R, C;
std::cin >> R >> C;
int **array = new int*[R]; // allocates space for R row pointers
for (int i = 0; i < R; ++i) {
array[i] = new int[C]; // for each row, allocate C columns
}
func(R, C, array);
//then delete everything
for (int i = 0; i < R; ++i) {
delete [] array[i]; // delete all of the ints themselves
}
delete [] array; // delete the row pointers.
with the signature for func being
void func(int r, int c, int **arr);
again, vector of vectors will be a lot easier on you.
An array can be located in two different memory regions - on the stack, or on the heap.
Array like you specified, is located on the stack.
int array[SIZE];
when an array is located on the stack, the compiler needs to know in advance what is its size, therefor SIZE must be a constant expression (known at compile time), and sometimes a defined value (set using #define SIZE 10).
if you want to create an array of unknown size (will be determined in runtime), you need to create the array on the heap, like this:
int **array = new int*[C];
for(int i = 0;i<C; i++)
array[i] = new int[R];
later on, you must remember to delete everything you dynamically allocated (everything you used new on)
for(int i = 0;i<C; i++)
delete[] array[i];
delete[] array;
note the use of delete[], because we are deleting an array (array is an array of arrays of ints, array[i] is an array of ints)
I would recommend passing in a pointer to the array, and two variables for R and C. Then it's up to you to make sure you use pointer math correctly to stay within the bounds of the array.
Otherwise set this up as a template, but you'll still probably need to know the sizes of R & C.

how to allocate dynamic memory to int a[4][3] array

how to allocate run time memory to an array of size[4][3]?
i.e int a[4][3]
If need is to allocate memory to an array at run time than how to allocate memory to 2D array or 3D array.
Editing the answer based on comments. Allocate separately for each dimension. For a 2D array a 2 level allocation is required.
*a = (int**)malloc(numberOfRows*sizeof(int*));
for(int i=0; i<numberOfRows; i++)
{
(*arr)[i] = (int*)malloc(numberOfColumns*sizeof(int));
}
The simplest way to allocate dynamically an array of type int[4][3] is the following
int ( *a )[3] = new int[4][3];
// some stuff using the array
delete []a;
Another way is to allocate several arrays. For example
int **a = new int * [4];
for ( size_t i = 0; i < 4; i++ ) a[i] = new int[3];
// some stuff using the array
for ( size_t i = 0; i < 4; i++ ) delete []a[i];
delete []a;
What have you tried. new int[4][3] is a perfectly valid
expression, and the results can be assigned to a variable with the
appropriate type:
int (*array2D)[3] = new int[4][3];
Having said that: I can't really think of a case where this
would be appropriate. Practically speaking, anytime you need
a 2 dimensional array, you should define a class which
implements it (using std::vector<int> for the actual memory).
A pure C approach is the following:
int (*size)[4][3];
size = malloc(sizeof *size);
/* Verify size is not NULL */
/* Example of access */
(*size)[1][2] = 89;
/* Do something useful */
/* Deallocate */
free(size);
The benefit is that you consume less memory by not allocating intermediate pointers, you deal with a single block of memory and deallocation is simpler. This is especially important if you start to have more than 2 dimensions.
The drawback is that the access syntax is more complicated, as you need to dereference a pointer before being able to index.
Use calloc, i guess this will do.
int **p;
p=(int**)calloc(4,sizeof(int));
In C you can use pointer to pointer
AS #Lundin mentioned this is not 2D array. It is a lookup table using pointers to fragmented memory areas allocated all over the heap.
You need to allocate how many pointers you need and then allocate each pointer. you can allocate fixed size or varaible size depending on your requirement
//step-1: pointer to row
int **a = malloc(sizeof(int *) * MAX_NUMBER_OF_POINTERS);
//step-2: for each rows
for(i = 0; i < MAX_NUMBER_OF_POINTERS; i++){
//if you want to allocate variable sizes read them here
a[i] = malloc(sizeof(int) * MAX_SIZE_FOR_EACH_POINTER); // where as if you use character pointer always allocate one byte extra for null character
}
Where as if you want to allocate char pointers avoid using sizeof(char) inside for loop. because sizeof(char) == 1 and do not cast malloc result.
see How to declare a 2d array in C++ using new
You could use std::vector<> since it is a templated container (meaning array elements can be whatever type you need). std::vector<> allows for dynamic memory usage (you can change the size of the vector<> whenever you need to..the memory is allocated and free'd automatically).
For example:
#include <iostream>
#include <vector>
using namespace std; // saves you from having to write std:: in front of everthing
int main()
{
vector<int> vA;
vA.resize(4*3); // allocate memory for 12 elements
// Or, if you prefer working with arrays of arrays (vectors of vectors)
vector<vector<int> > vB;
vB.resize(4);
for (int i = 0; i < vB.size(); ++i)
vB[i].resize(3);
// Now you can access the elements the same as you would for an array
cout << "The last element is " << vB[3][2] << endl;
}
You can use malloc() in c or new in c++ for dynamic memory allocation.

C++ Initializing a Global Array

Hey everyone. I am an experienced java programmer and am just learning C++.
Now I have a bit of a beginner's problem. I have an array variable x of type int.
The user will input the size of x in method B. I want to use x in method A.
void method A()
{
using int x [] blah blah blah
}
void method B()
{
int n;
cin >>n;
int x [n]; // How can I use this int x in method A without getting error: storage size x is unknown.
// Or the error 'x' was not declared in this scope.
}
EDIT: Parameter passing isn't a solution I am looking for.
DOUBLE EDIT: I do know about the vector option, but my program is cramming on time. I am creating an algorithm where every millisecond counts.
BTW I found out a way of doing it.
int x [] = {}
method B();
method A () { blah blah use x}
method B () {/*int*/ x [n]}
If you actually want an array and not a vector, and you want that array dynamically sized at runtime, you would need to create it on the heap (storing it in a pointer), and free it when you're done.
Coming from Java you need to understand that there's no garbage collection in C++ - anything you new (create on the heap) in an object you will want to clean up in the destructor with delete.
class foo
{
private:
int *array;
public:
foo() { array = NULL; };
~foo()
{
if (array != NULL)
delete [] array;
}
void createArray()
{
array = new int[5];
}
};
More info at: http://www.cplusplus.com/doc/tutorial/dynamic/
This is a version of your example that works in c++.
#include <iostream>
int *my_array;
void methodA(a,b){
my_array[a] = b;
}
int methodB(){
int n;
std::cin >> n;
my_array = new int[n];
}
int main(){
int x;
x = methodB();
methodA(x-1, 20);
delete [] my_array;
return 0;
}
Use a vector:
std::vector<int> x(n);
then pass that to method A as an argument of type std::vector<int> const &.
Edit: Or make the vector a data member of your class and set it with:
size_t n;
std::cin >> n;
x.resize(n);
In C++ you can't directly size an array with a runtime value, only with constants.
You almost certainly want vector instead:
std::vector<int> x(n);
EDIT: flesh out answer.
I can't quite tell if you are trying to learn about arrays, or if you are trying to solve some practical problem. I'll assume the latter.
The only way for method A to have access to any variable is if it is in scope. Specifically, x must either be:
a local, including a parameter (but you said no to parameter passing)
a class member, or
a global
Here is a solution in which x is a class member:
class C {
public:
std::vector<int> x;
void A() {
std::cout << x[2] << "\n"; // using x[], for example.
}
void B() {
int n;
cin >> n;
x = std::vector<int>(n); // or, as others have pointed out, x.resize(n)
}
};
Be aware that arrays in C++ are much more basic (and dangerous) than in Java.
In Java, every access to an array is checked, to make sure the element number you use is within the array.
In C++, an array is just a pointer to an allocated area of memory, and you can use any array index you like (whether within the bounds of the array, or not). If your array index is outside the bounds of the array, you will be accessing (and modifying, if you are assigning to the array element!) whatever happens to be in memory at that point. This may cause an exception (if the memory address is outside the area accessible to your process), or can cause almost anything to happen (alter another variable in your program, alter something in the operating system, format your hard disk, whatever - it is called "undefined behaviour").
When you declare a local, static or global array in C++, the compiler needs to know at that point the size of the array, so it can allocate the memory (and free it for you when it goes out of scope). So the array size must be a constant.
However, an array is just a pointer. So, if you want an array whose size you don't know at compile time, you can make one on the heap, using "new". However, you then take on the responsibility of freeing that memory (with "delete") once you have finished with it.
I would agree with the posters above to use a vector if you can, as that gives you the kind of protection from accessing stuff outside the bounds of the array that you are used to.
But if you want the fastest possible code, use an allocated array:
class C {
int [] x;
void method A(int size)
{
x = new int[size]; // Allocate the array
for(int i = 0; i < size; i++)
x[i] = i; // Initialise the elements (otherwise they contain random data)
B();
delete [] x; // Don't forget to delete it when you have finished
// Note strange syntax - deleting an array needs the []
}
void method B()
{
int n;
cin >> n;
cout << x[n];
// Be warned, if the user inputs a number < 0 or >= size,
// you will get undefined behaviour!
}
}

elegant way to create&pass multi-dimensional array in c++?

first question:
for known dimensions, we don't need new/malloc for the creation
const int row = 3;
const int col = 2;
int tst_matrix[row][col] ={{1,2},{3,4},{5,6}}
however, there is no easy to pass this two-dimensional array to another function, right? because
int matrix_process(int in_matrix[][])
is illegal, you have to specify all the dimensions except the first one. if I need to change the content of in_matrix, how could I easily pass tst_matrix to the function matrix_process?
second question:
what's the standard way to create 2-dimensional array in c++ with new? I dont wanna use std::vector etc.. here.
here is what I come up with, is it the best way?
int **tst_arr = new int*[5];
int i=0, j=0;
for (i=0;i<5;i++)
{
tst_arr[i] = new int[5];
for (j=0;j<5;j++)
{
tst_arr[i][j] = i*5+j;
}
}
In addition, if I pass tst_array to another function, like:
int change_row_col( int **a)
{
.....................
//check which element is 0
for (i=0; i<5; i++)
for(j=0;j<5;j++)
{
if (*(*(a+i)+j)==0) //why I can not use a[i][j] here?
{
row[i]=1;
col[j]=1;
}
}
.....................
}
In addition, if I use ((a+i)+j), the result is not what I want.
Here is the complete testing code I had:
#include <iostream>
using namespace std;
//Input Matrix--a: Array[M][N]
int change_row_col( int **a)
{
int i,j;
int* row = new int[5];
int* col = new int[5];
//initialization
for(i=0;i<5;i++)
{
row[i]=0;
}
for(j=0;j<5;i++)
{
col[j]=0;
}
//check which element is 0
for (i=0; i<5; i++)
for(j=0;j<5;j++)
{
if (*(*(a+i)+j)==0) //why I can not use a[i][j] here?
{
row[i]=1;
col[j]=1;
}
}
for(i=0;i<5;i++)
for (j=0;j<5;j++)
{
if (row[i] || col[j])
{
*(*(a+i)+j)=0;
}
}
return 1;
}
int main ()
{
int **tst_arr = new int*[5];
int i=0, j=0;
for (i=0;i<5;i++)
{
tst_arr[i] = new int[5];
for (j=0;j<5;j++)
{
tst_arr[i][j] = i*5+j;
}
}
for (i=0; i<5;i++)
{
for(j=0; j<5;j++)
{
cout<<" "<<tst_arr[i][j];
}
cout<<endl;
}
change_row_col(tst_arr);
for (i=0; i<5;i++)
{
for(j=0; j<5;j++)
{
cout<<" "<<tst_arr[i][j];
}
cout<<endl;
}
for (i=0;i<5;i++)
{
delete []tst_arr[i];
}
delete []tst_arr;
}
For multidimensional arrays were all the bounds are variable at run time, the most common approach that I know of is to use a dynamically allocated one dimensional array and do the index calculations "manually". In C++ you would normally use a class such as a std::vector specialization to manage the allocation and deallocation of this array.
This produces essentially the same layout as a multidimensional array with fixed bounds and doesn't have any real implied overhead as, without fixed bounds, any approach would require passing all bar one of the array dimensions around at run time.
I honestly think the best idea is to eschew raw C++ arrays in favor of a wrapper class like the boost::multi_array type. This eliminates all sorts of weirdness that arises with raw arrays (difficulty passing them S parameters to functions, issues keeping track of the sizes of the arrays, etc.)
Also, I strongly urge you to reconsider your stance on std::vector. It's so much safer than raw arrays that there really isn't a good reason to use dynamic arrays over vectors in most circumstances. If you have a C background, it's worth taking the time to make the switch.
My solution using function template:
template<size_t M,size_t N>
void Fun(int (&arr)[M][N])
{
for ( int i = 0 ; i < M ; i++ )
{
for ( int j = 0 ; j < N ; j++ )
{
/*................*/
}
}
}
1)
template < typename T, size_t Row_, size_t Col_>
class t_two_dim {
public:
static const size_t Row = Row_;
static const size_t Col = Col_;
/* ... */
T at[Row][Col];
};
template <typename T>
int matrix_process(T& in_matrix) {
return T::Row * T::Col + in_matrix.at[0][0];
}
2) use std::vector. you're adding a few function calls (which may be inlined in an optimized build) and may be exporting a few additional symbols. i suppose there are very good reasons to avoid this, but appropriate justifications are sooooo rare. do you have an appropriate justification?
The simple answer is that the elegant way of doing it in C++ (you tagged C and C++, but your code is C++ new/delete) is by creating a bidimensional matrix class and pass that around (by reference or const reference). After that, the next option should always be std::vector (and again, I would implement the matrix class in terms of a vector). Unless you have a very compelling reason for it, I would avoid dealing with raw arrays of arrays.
If you really need to, but only if you really need to, you can perfectly work with multidimensional arrays, it is just a little more cumbersome than with plain arrays. If all dimensions are known at compile time, as in your first block this are some of the options.
const unsigned int dimX = ...;
const unsigned int dimY = ...;
int array[dimY][dimX];
void foo( int *array[dimX], unsigned int dimy ); // [1]
void foo( int (&array)[dimY][dimX] ); // [2]
In [1], by using pass-by-value syntax the array decays into a pointer to the first element, which means a pointer into an int [dimX], and that is what you need to pass. Note that you should pass the other dimension in another argument, as that will be unknown by the code in the function. In [2], by passing a reference to the array, all dimensions can be fixed and known. The compiler will ensure that you call only with the proper size of array (both dimensions coincide), and thus no need to pass the extra parameter. The second option can be templated to accomodate for different sizes (all of them known at compile time):
template <unsigned int DimX, unsigned int DimY>
void foo( int (&array)[DimY][DimX] );
The compiler will deduct the sizes (if a real array is passed to the template) and you will be able to use it inside the template as DimX and DimY. This enables the use of the function with different array sizes as long as they are all known at compile time.
If dimensions are not known at compile time, then things get quite messy and the only sensible approach is encapsulating the matrix in a class. There are basically two approaches. The first is allocating a single contiguous block of memory (as the compiler would do in the previous cases) and then providing functions that index that block by two dimensions. Look at the link up in the first paragraph for a simple approach, even if I would use std::vector instead of a raw pointer internally. Note that with the raw pointer you need to manually manage deletion of the pointer at destruction or your program will leak memory.
The other approach, which is what you started in the second part of your question is the one I would avoid at all costs, and consists in keeping a pointer into a block of pointers into integers. This complicates memory management (you moved from having to delete a pointer into having to delete DimY+1 pointers --each array[i], plus array) and you also need to manually guarantee during allocation that all rows contain the same number of columns. There is a substantial increase in the number of things that can go wrong and no gain, but some actual loss (more memory required to hold the intermediate pointers, worse runtime performance as you have to double reference, probably worse locality of data...
Wrapping up: write a class that encapsulates the bidimensional object in terms of a contiguous block of memory (array if sizes are known at compile time --write a template for different compile time sizes--, std::vector if sizes are not known until runtime, pointer only if you have a compelling reason to do so), and pass that object around. Any other thing will more often than not just complicate your code and make it more error prone.
For your first question:
If you need to pass a ND array with variable size you can follow the following method to define such a function. So, in this way you can pass the required size arguments to the function.
I have tested this in gcc and it works.
Example for 2D case:
void editArray(int M,int N,int matrix[M][N]){
//do something here
}
int mat[4][5];
editArray(4,5,mat); //call in this way

A variable seems to be de-referencing when I use it in a dynamic array (C++)

Here we are once again good people of the internet.
This is the code I'm using:
//This is what is in the header file
int *myArr[]; // A two-dimensional array representing holding the matrix data
//This is what is in the definition file
Matrix::Matrix(int n, int m)
{
myRows = n;
myColumns = m;
initialize();
}
void Matrix::initialize()
{
*myArr = new int[myRows];
for (int i=0; i < 3; i++)//Only set to 3 since myRows is acting crazy
{
myArr[i] = new int[myColumns];
}
}
For some reason when I use myRows variable to create the myArr array it just seems to stop referencing the value it was pointing towards before.
For instance I give it the value 3 and after the *myArr = new int[myRows] has been executed it changes the value of myRows to 9834496, which I don't understand.
Does the "new" de-reference the variable or something?
Or am I doing something wrong?
Oh and since this is a school practice project (so I won't blame you if you don't answer) I would prefer an answer over working code, so that I could know what I did wrong for future projects.
int *myArr[];
This is wrong! You've to tell the compiler the size also, of your array of pointer. How about if you declare int a[]. You're telling the compiler to create an array of int, of unknown size, which is not allowed in C++. That is why you cannot do that.
I would suggest you to do this:
int **myArr;
void Matrix::initialize()
{
myArr = new int*[myRows]; //note int* here!
for (int i=0; i < myRows; i++)
{
myArr[i] = new int[myColumns];
}
}
This should work now.
Try replacing:
*myArr = new int[myRows];
by
myArr = new int*[myRows];
You should use std::vector<>. It deals with all the problems of memory allocation and deallocation.
And it does so without any bugs.
And then you focus yourself on the real goals of your algorithm. Not on memory management :-)
typedef std::vector<int> Ints;
typedef std::vector<Ints> Matrix;
Matrix myArray;
I'm not sure if you're project requires you to use multi-level pointers, if it doesn't another way you can approach this problem is to just treat the multi-dimensional array as one big flat array.
That means when you reach the end of a row, the index after that would be the first element of the next row. Here's how the code might look:
// In this approach the double pointer int**
// is replaced with just a simple int*
int *myArr;
// Here's your Matrix ctor. Note the use of the initializer list
Matrix::Matrix(int n, int m) : myRows(n), myColumns(m)
{
initialize();
}
void Matrix::initialize()
{
myArr = new int[myRows * myColumns];
/* This loop is no longer needed since we're allocating
one big chunk at once.
for (int i=0; i < 3; i++)//Only set to 3 since myRows is acting crazy
{
myArr[i] = new int[myColumns];
}
*/
}
// To retrieve stuff from your array
// you would do something like this:
int Matrix::operator() (const int x, const int y)
{
return myArr[x * myRows + y];
}