Error initializing matrix with nembers of the same struct - c++

I'm learning C++.
I only need a matrix and SPECIALLY how many rows and columns are in the matrix. I've though that I can use the following structure:
struct map {
int rows;
int columns;
int matrix[rows][columns];
}
But, it doesn't compile. There is an error on line: int matrix[rows][columns];
I have also tried:
struct map {
int rows;
int columns;
int matrix[map.rows][this.columns];
}
But, it doesn't compile.
The map.matrix will have map.rows and map.columns. I have declared this way because I don't know if I can declared without specifying its dimensions.
If it is correct to do: int matrix[][];.
What do I have to do to make the map.matrix have map.rows rows and map.columns columns?

In order to create an array on the stack (i.e. not allocating it on the heap with new), the size of the arrays need to be known at compile time (your rows and columns are not known at compiletime).
Alternative 1: allocate on the heap (for big arrays which don't fit on the stack) or simply use vectors (vectors use heap memory).
Alternative 2: if you really need it to be on the stack, you could use a template class:
template <size_t ROWS, size_t COLUMNS>
class MyMatrix
{
int _matrix[ROWS][COLUMNS];
};

Related

c++ Declaring a 2D array as a global variable

I am struggling to figure out how to declare a 2D Array as a global variable so i can use it in all of my methods. So far it is only declared in a single method hence why it cannot be used in other methods.I have figured out how to declare a normal string array by just typing string* array = new string[1] at the start of my code before the methods (i then alter the size of this array later on based of a variable) but i am unsure how to do it with a 2D array:
void WordSearch::ReadSimplePuzzle()
int columns = 9;
int rows = 9;
string **simple2DArray = new string*[columns];
for (int i = 0; i < columns; i++)
simple2DArray[i] = new string[rows];
//code that populates the array too long to post but not relevant.
I then have a method later on where i need to access the simple2DArray but i cannot figure out how to define it at the start of the code any help would be appreciated.
If you columns and rows variables never change, you can do this:
const int columns = 9;
const int rows = 9;
string simple2DArray[columns][rows];
By statically allocating the memory, you now don't have to worry about freeing it.
Since you clarified that the size is not known until run-time, you will not be able to allocate the memory statically. A very simple solution would be:
std::vector<std::vector<std::string>> simple2DArray; // This will have size 0 at start
Then, in your initialization step, just do this:
simple2DArray.resize(rows);
for (auto& row : simple2DArray)
{
row.resize(columns);
}
There are other ways to do this, of course, such as allocating all the memory in one block of size rows*columns and then exposing it as if it were a 2-d matrix but that might be overkill for your purposes.
My suggestion is hide the array behind a functional interface.
std::string const& getElement(size_t m, size_t n);
void setElement(size_t m, size_t n, std::string const& val);
The calling functions have the abstractions of a 2D array but they don't need to know how the it is represented in code.
In the implementation, you have various options:
Use a 1D array. Map the 2D indices to the right index in the 1D array.
Use a std::vector. Still need to map the indices.
Use a 2D array. No mapping of indices needed.
Use a std::vector<std::vector<std::string>>. No mapping of indices needed.
I am struggling to figure out how to declare a 2D Array as a global
variable so i can use it in all of my methods.
As with any global var, you need to declare your pointer in global space:
string **simple2DArray;
and then you can assign to it from inside your method
simple2DArray = new string*[columns];
If you are asking this for making it easier to solve competitive programming problems, then look at the constraints given in the question. For example if the matrix can be an N*N with 1 <= N <= 1000 Then you can globally declare int arr[1000][1000];
Here's some code for a better idea.
//global declarations
int N;
int arr[1000][1000];
int functionA()
{
// some code
}
int functionB()
{
// some code
}
int main()
{
// Get the input of both N and your array arr
// Now you can use them in any where in your code
}

Invalid use of non static data member

class matrix
{
public:
int m;
int n;
int mat[m][n];
};
I get this error:
[Error]: Invalid use of non static data member 'matrix::n'
On declaring static:
class matrix
{
public:
static int m;
static int n;
int mat[m][n]; //Error
};
I get this error:
[Error]: Array bound is not an integer constant before ']' token
Please tell me what these errors mean and how to fix this problem.
The sizes of arrays in C++ must be compile-time evaluable.
The compiler doesn't know what to do with int mat[m][n]; since the values of m and n are not known at compile time.
If you want a good reliable matrix class then consider using the BLAS library in Boost. A std::vector<std::vector<int>> can work but it is a jagged-edged matrix with a rather poor memory model.
The problem is that when you declare mat the member variables m and n doesn't actually exist. They don't exist until you create a an instance of the matrix class. However that won't do much good as arrays in C++ must have a fixed size at the time of compilation.
If you want to set the size of mat at run-time, then the simple solution here is to use a std::vector of std::vector objects.
Like e.g.
std::vector<std::vector<int>> mat;

Dynamic memory allocation of 2d arrays that are in the struct

I have a struct and I am finding the beginning and end of the lines in an image and in those lines beginning and end of the word, letter etc. (Implementing a basic OCR.)
typedef struct _IMAGE {
int row;
int col;
int max_value;
int **line;
int **space;
int **word;
int **letter;
int **matrix;//holds the image pixels
} IMAGE;
I want to alter my code with dynamically allocated matrices. But since I don't know how many lines and words that will be I don't know the size at the beginning so cannot do simple dynamic allocation. Do you recommend for me to use vectors in this situation? If so how should I use it?
You clarified in a comment that the number of columns in the 2D arrays will be constant, whereas the number of rows can change.
Therefore, you can use 1D vectors and address the elements by mapping the (i, j) indexes to a single index with the formula: k = i * number_of_columns + j.
However, you said that the line array will have only 2 columns, one for the beginning o the line and one for the end. This makes me think that it is more convenient (especially for semantics) to have a Line struct/class with two fields (start, end) and put instances of this struct/class into a simple 1D vector.
When you design an array in which each element has a different meaning depending on its position, and the elements are few, I think it is better to devise an appropriate struct.
Last, since this is C++, you can declare structs in this way:
struct X
{
int a;
// ...
}
No professional image library out there holds image data in a matrix. You should simply do:
struct Image
{
int col;
std::vector<int> matrix;
};
And access the pixels like matrix[x+ col* y]. That will be the quickest, most memory-friendly layout for pixel data. Or use an already existing image struct to avoid the concept of NIH.

Transfering a dynamically allocated matrix in a method of a class in C++

I'm trying to make a dynamically allocated bidimensional array with variable size but I don't know why if I create my own constant value it won't compile:
const int oConstanta=N+1;
int (*m)[oConstanta]=new int[oConstanta][oConstanta];
But when I use a normal constant such as 1000 between the brackets it compiles successfully.
const int oConstanta=N+1;
int (*m)[1000]=new int[1000][1000];
Does anyone know the reason for this?
PS: I know that:
int **m=new int*[oConstanta];
for(i=1;i<=N;i++)
{
m[i]=new int[oConstanta];
init(m[i]);
}
will solve my problems but I want to learn why my former method was a bad idea.
Unless N is a compile-time constant expression, oConstanta is not a compile-time constant either.
The best way of making a two-dimensional array in C++ is using std::vector of std::vectors, for example, like this:
#include <vector>
std::vector<std::vector<int> > m(N+1, std::vector<int>(N+1, 0));
Ultimately the reason is that you can't create static arrays of variable length.
In your code you are trying to create a static array of dynamic arrays, both of variable length.
Now, static arrays live in the stack, while dynamic arrays live in the heap. While the memory management of the heap is "flexible", the stack is different: the compiler needs to be able to determine the size of each frame in the stack. This is clearly not possible if you use an array of variable length.
On the other hand, if you use a pointer the size of the stack frame is known (a pointer has a known size) and everything is fine.
If you want to try, this should compile fine
int (*m)[1000]=new int[oConstanta][1000]
since it's a fixed-size static array, whose entries are dynamically allocated arrays of variable length (allowed).
In short: whenever the size of an object is not known at compile time, that object cannot be in the stack, it has to be dynamically allocated.
To make a dynamically sized, 2D matrix with contiguous elements and a single allocation:
std::vector<int> matrix(Rows*Columns);
Access an element in the i th row and j th column:
matrix[Columns*i + j] = 1;
You can wrap this all up in a class. Here's a very basic example:
struct Matrix {
std::vector<int> m;
size_t rows,columns;
Matrix(size_t rows,size_t columns)
: rows(rows)
, columns(columns)
, m(rows*columns)
{}
int &at(size_t i,size_t j) {
return m.at(i*columns + j);
}
};

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