C++ Attempting to define 2D array using function arguments - c++

I'm looking to define a 2 dimensional character array where arguments I pass to a function holding the array will be used to determine the size each dimension of the array.
int func(const int x, const int y) {
char maze[x][y] = { 0 };
return 0;
}
When defining x & y inside the function as constant integers the array is defined just fine. When x and y are arguments to the function the program won't compile. Why is this and how do I get around it?

You can make a wrapper around 1-dimensial array like this:
class Maze {
friend class Row;
public:
/* This helper class represents a single row of the maze */
class Row {
friend class Maze;
Maze& owner;
std::size_t row;
Row(Maze& owner_, std::size_t row_) : owner(owner_), row(row_) {}
/* this operator resolves 2nd pair of brackets */
public:
inline char& operator[](std::size_t col) { return owner.data[col + row*owner.cols]; }
};
Maze(std::size_t rows_, std::size_t cols_)
: data(rows_ * cols_, 0)
, cols(cols_)
{}
/* this operator resolves 1st pair of brackets */
inline Row operator[](std::size_t index) { return Row(*this, index); }
private:
std::vector<char> data;
std::size_t cols;
};
...
Maze m(5, 10);
m[2][3] = 1;

You need to use dynamic memory allocation. Variadic length arrays is not a part of c++ standart. However variadic length arrays available as an extension for GCC. Although you can use STL or implement your class, dont forget about new[] and the one-dimensional representation for two-dimensional array:
char* maze = new char[x*y]; // create
maze[i + j * x]; // access
delete[] maze; // delete
It is compact and in most cases fast.

When defining x & y inside the function as constant integers the array is defined just fine
It works because the size of your array is defined and known by your compiler, known at compile-time
When x and y are arguments to the function the program won't compile.
When you wish to define you array only when you call your function, you ask your program to do that during runtime
. As answered by Dmytro Dadyka, you have to use use dynamic memory allocation and manage yourself memory deallocation (delete[] maze; // delete)
Here is an alternative of defining dynamically your 2D array using template! Notice that it is always done at compile-time.
template<int X, int Y>
int f()
{
char c[X][Y];
for(int x=0; x < X; ++x)
{
for(int y=0; y < Y; ++y)
{
c[x][y] = '1';
}
}
// write your algorithm now!....
c[2][2] = 'a';
for(int x=0; x < X; ++x)
{
for(int y=0; y < Y; ++y)
{
std::cout << c[x][y] << " ";
}
std::cout << std::endl;
}
return 0;
}
int main()
{
f<5,5>();
f<7,4>();
return 0;
}

Related

Initialise global array with respect to function input

I want to do something like:
int a[][]; // I know this code won't work, its to demonstrate what I want to do
void func(int n, int m){
a = int[n][m];
}
that is, initialise a global array whose size depends on function input. If this array was local, it would be a trivial case, but I don't know how to do this in the case shown above. Any help would be very useful!
You can create a matrix with std::vector:
std::vector<std::vector<int>> a;
void func(int n, int m) {
a.resize(n);
for(int i = 0; i < n; i++) {
a[i].resize(m);
}
}
Then you can access elements in the same way you do with int a[][]:
a[i][j] = number;
One way to achieve this is to encapsulate a flat std::vector in a Matrix class and use math to get an element with row and column as in this example:
template<typename T>
class Matrix {
private:
vector<T> vec;
//...
public:
T& get_value(size_t const row, size_t const col) {
return vec[row * col_count + col];
}
};
you can try this
int ** a; // is a pointer of two dimension
void func(int n, int m){
a = new int*[n]; //dynamic allocation global pointer a
for(int i = 0; i < n; i++)
a[i] = new int[m]();
}

How to reference a 2d pointer?

In my code I create a function outside of the main, which creates a 1D array and initializes to 0.
void create_grid(double *&y, int Npoints)
{
y = new double[Npoints];
for (int i = 0; i < Npoints; i++)
{
y[i] = 0;
}
}
If I didn't have the syntax of declaring in the function as double *&y I couldn't access the values of y.
I tried doing the same for a 2D array but i don't know the syntax. I tried &&**y and &*&*y but it didn't work. Does anyone know how to create a function outside of the main, which initializes a 2d dynamic array so I can use it in the main?
E.g.:
void create_grid_2D(double **&&y, int Npoints1, int Npoints2)
{
y = new double*[Npoints1];
for (int i = 0; i < Npoints1; i++)
{
y[i] = new double[Npoints2];
}
for (int i = 0; i < Npoints1; i++)
{
for (int j = 0; j < Npoints2; j++)
{
y[i][j] = 0;
}
}
}
int main()
{
int N = 10;
double **z;//correcting this line, i wrote z**
create_grid_2D(z, N, N);
delete[]z;
return 0;
}
C++ does not allow forming a pointer to reference or reference to reference. (And without a space between the characters, && is a single token meaning something entirely different.)
And your declaration double z**; is incorrect - you probably mean double **z;.
To write a function that takes the argument double **z by reference, you just want a reference to pointer to pointer:
void create_grid_2D(double **&y,int Npoints1,int Npoints2)
{
//...
}
Except don't use new and delete. Using them slightly wrong leads to memory leaks and bugs with dangling pointers and double deletes. For example, you tried to clean up your memory in main with delete []z;, but new-expressions were evaluated 11 times to your one delete-expression, so this misses out on deleting the row arrays z[0], z[1], ... z[9]. There's pretty much always a better and simpler way using std::unique_ptr, std::shared_ptr, std::vector, or other RAII (Resource Allocation Is Initialization) tools.
So I would change the function to:
void create_grid_2D(std::vector<std::vector<double>>& y,
unsigned int Npoints1,
unsigned int Npoints2)
{
y.assign(Npoints1, std::vector<double>(Npoints2, 0.0));
}
int main()
{
unsigned int N=10;
std::vector<std::vector<double>> z;
create_grid_2D(z, N, N);
// No manual cleanup necessary.
}
Or even use a return value rather than assigning an argument:
std::vector<std::vector<double>> create_grid_2D(
unsigned int Npoints1,
unsigned int Npoints2)
{
return std::vector<std::vector<double>>(
Npoints1, std::vector<double>(Npoints2, 0.0));
}
int main()
{
unsigned int N=10;
std::vector<std::vector<double>> z = create_grid_2D(N, N);
}
An easy trick to resolve/write such complicated references is (simplified version for the sake of this problem - it's a bit more complicated with braces present): start from the variable name and go to the left, step by step. In your case:
... y
y is ...
... & y
y is a reference ...
... *& y
y is a reference to a pointer ...
... **& y
y is a reference to a pointer to a pointer ...
double**& y
y is a reference to a pointer to a pointer to a double
So, the correct definition is:
void create_grid_2D(double**& y,int Npoints1,int Npoints2)
But as mentioned in the comments, please do really consider avoiding raw pointers in favor of std::vector and other standard containers.
So you want a reference on a pointer to a pointer.
2d pointer is int**, and the reference is int**&. That's what you want to use.
Then, you should a container or at least a smart pointer instead.
This approach would be a little different than what you currently have but basically you want a 2D grid and another name for this is simply a MxN Matrix! We can do this very easily with a simple template structure. This template class will hold all of the contents without having to put the data into dynamic memory directly. Then once you have your class object that you want to use we can then put that into dynamic memory with the use of smart pointers!
#include <iostream>
#include <memory>
template<class T, unsigned M, unsigned N>
class Matrix {
static const unsigned Row = M;
static const unsigned Col = N;
static const unsigned Size = Row * Col;
T data[Size] = {};
public:
Matrix() {};
Matrix( const T* dataIn ) {
fillMatrix( dataIn );
}
void fillMatrix( const T* dataIn );
void printMatrix() const;
};
template<class T, unsigned M, unsigned N>
void Matrix<T, M, N>::fillMatrix( const T* dataIn ) {
for ( unsigned i = 0; i < Size; i++ ) {
this->data[i] = dataIn[i];
}
}
template<class T, unsigned M, unsigned N>
void Matrix<T,M,N>::printMatrix() {
for ( unsigned i = 0; i < Row; i++ ) {
for ( unsigned j = 0; j < Col; j++ ) {
std::cout << this->data[i*Col + j] << " ";
}
std::cout << '\n';
}
}
int main() {
// our 1 day array of data
double data[6] = { 1,2,3,4,5,6 };
// create and print a MxN matrix - in memory still a 1 day array but represented as 2D array
Matrix<double,2,3> A;
A.fillMatrix( data );
A.printMatrix();
std::cout << '\n';
Matrix<double, 3,2> B( data );
B.printMatrix();
std::cout << '\n';
// Want this in dynamic memory? With shared_ptr the memory is handled for you
// and is cleaned up upon it's destruction. This helps to eliminate memory leaks
// and dangling pointers.
std::shared_ptr<Matrix<float,2,3>> pMatrix( new Matrix<float,2,3>( data ) );
pMatrix->printMatrix();
return 0;
}
Output:
1 2 3
4 5 6
1 2
3 4
5 6
1 2 3
4 5 6

Create array of not pre-determined size inside a structure

I want to work with Images, and I want to create my structure Image with first 2 values to be it's size (grayscale) and the third - data (2D array of size m by n).
How can I implement it? If I don't know the image's size in advance. Something like this:
struct Image{
int n;
int m;
data = 2D array of size mxn
}
Instead I would use
struct Image{
int n;
int m;
vector<vector<int>> data;
}
Of you could use a 1D vector that has size
vector<int> data(m * n);
Ignoring encapsulation, something like this could work:
#include <vector>
struct Image {
int n;
int m;
std::vector<std::vector<int>> data; // May want to change int type ?
Image(int n, int m) : n(n), m(m), data(n) {
for (int row = 0; row < n; row++) {
data[row].resize(m);
}
}
};
// Example Usage
Image img(10, 10);
for (int row = 0; row < img.n; row++) {
for (int col = 0; col < img.m; col++) {
img.data[row][col] = valueFromImageFile;
}
}
If you're not just looking for something quick and dirty, and this is going to be an ongoing project, I would recommend that you learn more about object oriented concepts :)
There are two common patterns for that (even if inherited from C). Both share a common principle : a logical separation between a fixed size header and a variable part.
First method : the struct contains the fixed size part and a pointer (or pointers in a generic case) to memory allocated with new (in constructor) and deallocated in destructor. It is a bit hand-driven, but easy to use and to understand.
Image could look like (I assume Pixel is a class representing a single pixel):
class Image {
private:
int _x, _y;
Pixel *data;
public:
Image(int x, int y);
~Image();
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image::Image(int x, int y) {
data = new Pixel[x * y];
_x = x;
_y = y;
}
Image::~Image() {
delete[] data;
data = NULL;
}
Second method : the pseudo-struct is composed of a fixed size header, and of a dynamic part. The dynamic part is declared in the struct to be of size 1. It is obviously false, and you cannot use sizeof on such a struct, but as C does not inforce comparison of array to the declared size it works :
class Image {
private:
int _x, _y;
Pixel data[1];
Image(int x, int y); // private to force usage of createImage
public:
static Image* createImage(int x, int y);
Pixel& getPixel(int i, int j) {
return data[i * _y + j];
}
};
Image* Image::createImage(int x, int y) {
Image* image = (Image *) malloc(sizeof(Image) + (x * y - 1) * sizeof(Pixel));
image->_x = x;
image->_y = y;
return image;
}
I must admit it is really C code embedded in C++, but I cited it because it is heavily used in Microsoft Win32 API.

Converting multidimensional arrays to pointers in c++

I have a program that looks like the following:
double[4][4] startMatrix;
double[4][4] inverseMatrix;
initialize(startMatrix) //this puts the information I want in startMatrix
I now want to calculate the inverse of startMatrix and put it into inverseMatrix. I have a library function for this purpose whose prototype is the following:
void MatrixInversion(double** A, int order, double** B)
that takes the inverse of A and puts it in B. The problem is that I need to know how to convert the double[4][4] into a double** to give to the function. I've tried just doing it the "obvious way":
MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix))
but that doesn't seem to work. Is that actually the right way to do it?
No, there's no right way to do specifically that. A double[4][4] array is not convertible to a double ** pointer. These are two alternative, incompatible ways to implement a 2D array. Something needs to be changed: either the function's interface, or the structure of the array passed as an argument.
The simplest way to do the latter, i.e. to make your existing double[4][4] array compatible with the function, is to create temporary "index" arrays of type double *[4] pointing to the beginnings of each row in each matrix
double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] };
double *inverseRows[4] = { /* same thing here */ };
and pass these "index" arrays instead
MatrixInversion(startRows, 4, inverseRows);
Once the function finished working, you can forget about the startRows and inverseRows arrays, since the result will be placed into your original inverseMatrix array correctly.
For given reason that two-dimensional array (one contiguous block of memory) and an array of pointers (not contiguous) are very different things, you can't pass a two-dimensional array to a function working with pointer-to-pointer.
One thing you could do: templates. Make the size of the second dimension a template parameter.
#include <iostream>
template <unsigned N>
void print(double a[][N], unsigned order)
{
for (unsigned y = 0; y < order; ++y) {
for (unsigned x = 0; x < N; ++x) {
std::cout << a[y][x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(arr, 3);
}
Another, a bit clumsier way might be to make the function accept a pointer to a single-dimensional array, and both width and height given as arguments, and calculate the indexes into a two-dimensional representation yourself.
#include <iostream>
void print(double *a, unsigned height, unsigned width)
{
for (unsigned y = 0; y < height; ++y) {
for (unsigned x = 0; x < width; ++x) {
std::cout << a[y * width + x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(&arr[0][0], 3, 3);
}
Naturally, a matrix is something that deserves a class of its own (but the above might still be relevant, if you need to write helper functions).
Since you are using C++, the proper way to do something like this would be with a custom class and some templates. The following example is rather rough, but it gets the basic point across.
#include <iostream>
using namespace std;
template <int matrix_size>
class SquareMatrix
{
public:
int size(void) { return matrix_size; }
double array[matrix_size][matrix_size];
void copyInverse(const SquareMatrix<matrix_size> & src);
void print(void);
};
template <int matrix_size>
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src)
{
int inv_x;
int inv_y;
for (int x = 0; x < matrix_size; x++)
{
inv_x = matrix_size - 1 - x;
for (int y = 0; y < matrix_size; y++)
{
inv_y = matrix_size - 1 - y;
array[x][y] = src.array[inv_x][inv_y];
}
}
}
template <int matrix_size>
void SquareMatrix<matrix_size>::print(void)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
cout << array[x][y] << " ";
}
cout << endl;
}
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix);
int main(int argc, char * argList[])
{
SquareMatrix<4> startMatrix;
SquareMatrix<4> inverseMatrix;
Initialize(startMatrix);
inverseMatrix.copyInverse(startMatrix);
cout << "Start:" << endl;
startMatrix.print();
cout << "Inverse:" << endl;
inverseMatrix.print();
return 0;
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix)
{
for (int x = 0; x < matrix_size; x++)
{
for (int y = 0; y < matrix_size; y++)
{
matrix.array[x][y] = (x+1)*10+(y+1);
}
}
}
Two dimensional array is not a pointer to pointer or something similar. The correct type for you startMatrix is double (*)[4]. For your function, the signature should be like:
MatrixInversion( double (*A)[4], int order, double (*B)[4] );
There is a solution using the pointer to point by bobobobo
William Sherif (bobobobo) used the C version and I just want to show C++ version of bobobobo's answer.
int numRows = 16 ;
int numCols = 5 ;
int **a ;
a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
a[row] = new int[ numCols*sizeof(int) ];
}
The rest of code is the same with bobobobo's.
You can definitely do something like the code below, if you want.
template <typename T, int n>
class MatrixP
{
public:
MatrixP operator()(T array[][n])
{
for (auto i = 0; i < n; ++i) {
v_[i] = &array[i][0];
}
return *this;
}
operator T**()
{
return v_;
}
private:
T* v_[n] = {};
};
void foo(int** pp, int m, int n)
{
for (auto i = 0; i < m; ++i) {
for (auto j = 0; j < n; ++j) {
std::cout << pp[i][j] << std::endl;
}
}
}
int main(int argc, char** argv)
{
int array[2][2] = { { 1, 2 }, { 3, 4 } };
auto pa = MatrixP<int, 2>()(array);
foo(pa, 2, 2);
}
The problem is that a two-dimensional array is not the same as an array of pointers. A two-dimensional array stores the elements one row after another — so, when you pass such an array around, only a pointer to the start is given. The receiving function can work out how to find any element of the array, but only if it knows the length of each row.
So, your receiving function should be declared as void MatrixInversion(double A[4][], int order, double B[4][]).
by nice coding if c++:
struct matrix {
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
so the interface would be
void MatrixInversion(matrix &A, int order, matrix &B);
and use it
MatrixInversion(startMatrix, 4, inverseMatrix);
The benefit
the interface is very simple and clear.
once need to modify "m" of matrix internally, you don't need to update the interface.
Or this way
struct matrix {
void Inversion(matrix &inv, int order) {...}
protected:
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
...
An ugly way in c
void MatrixInversion(void *A, int order, void *B);
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix);
EDIT: reference code for MatrixInversion which will not crash:
void MatrixInversion(void *A, int order, void *B)
{
double _a[4][4];
double _b[4][4];
memcpy(_a, A, sizeof _a);
memcpy(_b, B, sizeof _b);
// processing data here
// copy back after done
memcpy(B, _b, sizeof _b);
}

Is there a way to initialize an array with non-constant variables? (C++)

I am trying to create a class as such:
class CLASS
{
public:
//stuff
private:
int x, y;
char array[x][y];
};
Of course, it doesn't work until I change int x, y; to
const static int x = 10, y = 10;
Which is impractical, because I am trying to read the values of x and y from a file. So is there any way to initialize an array with non-contant values, or declare an array and declare its size on different statements? And I know this would probably require the creation of an array class, but I'm not sure where to start on this, and I don't want to create a 2D dynamic list when the array itself is not dynamic, just the size is not known at compile-time.
use vector.
#include <vector>
class YourClass
{
public:
YourClass()
: x(read_x_from_file()), y(read_y_from_file())
{
my_array.resize(x);
for(int ix = 0; ix < x; ++ix)
my_array[ix].resize(y);
}
//stuff
private:
int x, y;
std::vector<std::vector<char> > my_array;
};
The compiler need to have the exact size of the class when compiling, you will have to use the new operator to dynamically allocate memory.
Switch char array[x][y]; to char** array; and initialize your array in the constructor, and don't forget to delete your array in the destructor.
class MyClass
{
public:
MyClass() {
x = 10; //read from file
y = 10; //read from file
allocate(x, y);
}
MyClass( const MyClass& otherClass ) {
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
// This can be replace by a memcopy
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<x ; ++j )
array[i][j] = otherClass.array[i][j];
}
~MyClass(){
deleteMe();
}
void allocate( int x, int y){
array = new char*[x];
for( int i = 0; i < y; i++ )
array[i] = new char[y];
}
void deleteMe(){
for (int i = 0; i < y; i++)
delete[] array[i];
delete[] array;
}
MyClass& operator= (const MyClass& otherClass)
{
if( this != &otherClass )
{
deleteMe();
x = otherClass.x;
y = otherClass.y;
allocate(x, y);
for( int i=0 ; i<x ; ++i )
for( int j=0 ; j<y ; ++j )
array[i][j] = otherClass.array[i][j];
}
return *this;
}
private:
int x, y;
char** array;
};
*EDIT:
I've had the copy constructor
and the assignment operator
Not in that manner, as in c++, c-style array sizes have to be known at compile time, with some vendor specific extensions allowing certain runtime sizes (to enhance compatibility with C99), but not in the situation you are describing (if you are interested, here's a description). The easiest thing to do would be:
std::vector< std::vector<char> > array;
And apply the size in the constructor:
array.resize(x);
for(std::vector< std::vector<char> >::iterator curr(array.begin()),end(array.end());curr!=end;++curr){
curr->resize(y);
}
There are many advantages of vector over c style arrays, see here
Put all the memory into one block.
Because it is private you can then get your access methods to retrieve the correct value.
Quick example:
#include <vector>
#include <iostream>
class Matrix
{
public:
class Row
{
public:
Row(Matrix& p,unsigned int x)
:parent(p)
,xAxis(x)
{}
char& operator[](int yAxis)
{
return parent.data(xAxis,yAxis);
}
private:
Matrix& parent;
unsigned int xAxis;
};
Matrix(unsigned int x,unsigned int y)
:xSize(x)
,ySize(y)
,dataArray(x*y)
{}
Matrix::Row operator[](unsigned int xAxis)
{
return Row(*this,xAxis);
}
char& data(unsigned int xAxis,unsigned int yAxis)
{
return dataArray[yAxis*xSize + xAxis];
}
private:
unsigned int xSize;
unsigned int ySize;
std::vector<char> dataArray;
};
int main()
{
Matrix two(2,2);
two[0][0] = '1';
two[0][1] = '2';
two[1][0] = '3';
two[1][1] = '4';
std::cout << two[1][0] << "\n";
std::cout << two.data(1,0) << "\n";
}
Take a look at boost::multi_array.
You can't allocate or initialize a global or static array declaratively using non-constant values (compile-time). It's possible for local arrays though (C99 variable sized arrays, as their initializer essentially runs at runtime every time the function is executed).
For your situation, I suggest using a pointer instead of an array and create the actual array dynamically at runtime (using new):
class CLASS
{
public:
CLASS(int _x, int _y) : x(_x), y(_y) {
array = new char*[x];
for(int i = 0; i < x; ++i)
array[i] = new char[y];
}
~CLASS() {
for (int i = 0; i < x; ++i)
delete[] array[i];
delete[] array;
}
//stuff
private:
int x, y;
char **array;
};
You can allocate memory to your 2-dimensional array in the constructor and free it in the destructor. The simplest way:
array = (char **)malloc(sizeof(char *) * x);
if (array) {
for (i = 0; i < x; i++) {
array[i] = (char *)malloc(sizeof(char) * y);
assert(array[i]);
}
}
If the size is not known at compile time, the array is dynamic. What you could do to keep it static is to make them larger than your largest expected size.
If you want a dynamically sized array as a class member, you need to array new it and assign that value to a pointer. The char array[size] syntax is only for statically-sized arrays.
Better yet, you really should use an std::vector< std::vector<char> >, there are very few good reasons to manually work with dynamically sized arrays these days.