How to declare 2D dynamic array in C++ - c++

How to declare a 2D array in which the rows are dynamic but the rows length are fixed? Is there any way to do it without both row and rows length are dynamic?
P.S. I can't use STL containers or class string.

You can use std::vector and std::array for this.
std::vector is a dynamic-length array.
std::array is a fixed-length array, used as
array<int, 20> arr;
arr[10] = 42;
array<int, 20> anotherArr = arr; // copied here, as opposed to C arrays
int oldStyleArr[20];
oldStyleArr[10] = 42;
// int newStyleArr[20] = oldStyleArr; // error here
It is a convenient wrapper over the C-style array, and it provides value semantics and various conveniece methods like size().
So you can create array<vector<int>, 20> for an array of 20 dynamic vectors of ints or vector<array<int, 20>> for a dynamic vector of fixed-length arrays.
UPD: std::array works only with array bounds known at compile-time. If your array bounds are known only at runtime, you still can use std::vector's constructor from size and (optional) element:
int rowCount, columnCount;
cin >> rowCount >> columnCount;
using Row = vector<int>;
// create `vector` of `rowCount` rows,
// where each row is `vector` of `columnCount` ints
vector<Row> arr2d(rowCount, Row(columnCount));
However, that's not the most efficient solution because each row is allocated separately. You can solve this with a little wrapper over one-dimensional vector:
template<class T>
class Vector2D {
public:
Vector2D(int rows, int cols)
: data(rows*cols)
, rows(rows)
, cols(cols) {}
int rowCount() const { return rows; }
int columnCount() const { return cols; }
T& get(int r, int c) { return data[r*cols + c]; }
T const& get(int r, int c) const { return data[r*cols + c]; }
void addRow() {
data.resize(cols*(rows + 1));
}
// ...
private:
vector<T> data;
int rows;
int cols;
};

You can use std::vector for dynamic range arrays. You would want to instantiate a vector of arrays to achieve this.

What you are looking for is probably: std::vector<std::array<int, 20>> arr;
However, if STL containers are not an option you might need to implement the container yourself. A linked list is probably the easiest to implement.

Just declare a 1D array and calculate the index yourself like how compilers generate accesses to a multidimensional array. Each row has width items, so the [x][y] element will have the index x*width + y
template<typename T>
class twoD
{
const int width;
const int height;
T* data;
twoD(int w, int h) : width(w), height(h)
{
data = new T[width*height];
}
~twoD()
{
delete[] data;
}
T& at(int x, int y)
{
return data[x*width + y];
}
T const& at(int x, int y) const
{
return data[x*width + y];
}
}
twoD myArray(4, 8);
myArray.at(2, 3) = 5;
myArray.at(4, 5) = 6 - myArray.at(2, 3);
The same method can be used to access multidimensional arrays in any degree

Related

Array of a specific size used out of the function it was initialized in

I'm a high school student learning programming and I have a problem that I can't figure out how to solve.
I have an integer "x", and I want a matrix "mat" to have the size of "x":
int mat[x][x];
But that works only in main() where I've read x;
For example if x == 5, the equivalent would be
int mat[5][5];
#include <iostream>
using namespace std;
int x;
int mat[x][x];
void f(int mat2[x][x])
{
}
int main()
{
cin >> x;
int m[x][x];
f(m);
}
I've wrote this short program to show where it works and it doesn't work.
error: array bound is not an integer constant before ']' token
I've the error at the global declaration, at the declaration in function void f. It only compiles without errors in main();
What can I do to create a matrix with the size of x outside of the main function?
Variable length arrays aren't spported in standard c++. Besides you don't want the global definition.
What you can use portably in that case is std::vector:
void f(std::vector<std::vector<int>>& mat)
{
}
int main()
{
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
f(m);
}
If you pass that vector around to functions or being allocated within functions, the size information will be kept at any time.
What can I do to create a matrix with the size of x outside of the main function?
Something like this:
std::vector<std::vector<int>> foo() {
cin >> x;
std::vector<std::vector<int>> m(x,std::vector<int>(x));
return m;
}
int main()
{
std::vector<std::vector<int>> mat = foo();
}
Handling of multi-dimension arrays in C++ is not easy. The best way to go is often to map a multi-dimensionnal indexing with a linear memory chunk.
For instance, for a 2 by 2 matrix, one can create an array of 2*2=4 elements and map it this way:
+-----------+-----------+-----------+-----------+
| map[0][0] | map[0][1] | map[1][0] | map[1][1] |
+-----------+-----------+-----------+-----------+
This seems overly complicated at first glance, but it simplifies greatly the memory allocation.
For an arbitrary sized matrix of width by height, map[i][j] is at index i*height + j. This can be translated in C++, encapsulated in a template class Matrix:
#include <array>
template <typename T, size_t WIDTH, size_t HEIGHT>
class Matrix {
std::array<T, WIDTH*HEIGHT> data;
public:
T& operator()(size_t i, size_t j) {
return data[i*HEIGHT + j];
}
const T& operator()(size_t i, size_t j) const {
return data[i*HEIGHT + j];
}
};
This has the disadvantage that the Matrix' dimensions must be known at compile time (and can be mitigated, see note (ii) at end of answer). But it makes its use so easy:
void fill(Matrix<int, 2, 2>& m) {
m(0,0) = 0;
m(0,1) = 1;
m(1,0) = 2;
m(1,1) = 3;
}
int main() {
Matrix<int, 2, 2> m;
fill(m);
std::cout << m(1,0) << "\n";
}
Note (i): Elements are indexed by (line, column) rather than [line][column] because we can't create an operator[] accepting multiple values.
Live on coliru
Note (ii): This basic idea can be enriched (demo) to handle resizable matrixes, with use of a std::vector instead of std::array and a proxy to std::vector::resize().
Variable-length array is supported by some compiler as an extension. The manual of the compiler provides more information.Gnu VLR
The storage duration of a variable-length array(if supported) generally can't be static, which is why you get the error message (global variables have static storage duration).
Unrelated: The major array bound of the parameter mat2 isn't necessary, i.e. void f(int mat2[x][x]) is equivalent to void f(int mat2[][x]).
C++ has no provision for dynamic 2D matrix but provides all you need to create complex classes. A (static) 2D array is a contiguously allocated array of height arrays of width elements. Just mimic that and:
allocate a linear array of width * height
provide an operator[](int) that returns a pointer to the first element of ith row
do necessary housekeeping in destructor and in a copy (and move if C++11 or above) constructor.
Example of code:
template <typename T>
class Matrix {
T *data;
int width;
int height;
public:
// direct ctor
Matrix(int h, int w): width(w), height(h) {
data = new T[w * h];
}
//copy ctor
Matrix(const Matrix& src): width(src.width), height(src.height) {
data = new T[width * height]; // allocate and copy data array
for (int i=0; i<width * height; i++) data[i] = src.data[i];
}
// move ctor
Matrix(Matrix&& src): width(src.width), height(src.height) {
data = src.data; // steal original array in a move
src.data = NULL; // ensure no deletion will occur at src destruction
}
~Matrix() {
delete data;
data = NULL;
}
// explicitely delete assignement operators
Matrix& operator = (const Matrix&) = delete;
Matrix& operator = (Matrix&&) = delete;
T* operator[](int i) {
//optionaly test 0 <= i < width
return &data[i * width];
}
};
int main()
{
int w;
std::cin >> x;
Matrix<int> m(x, x);
// you can then use m[i][j] as you would for a static 2D array
...
}
This class does not support any resizing by design. If you need that, you really should use a vector<vector<T> >. The downside is that it has no default ctor either, because the dimension must be given at definition time (even if we could easily imagine a 2 phases initialization...).
You can dynamic allocate memory to use, in the c/c++, it does not support dynamic size of static memory allocation, so, you just modify your code like this.
int x;
cin >>x;
int** mat = new int[x][x];

C++11 dynamically allocated variable length multidimensional array

I've been trying to create a variable length multidimensional array. As I understand, you can't create variable length arrays on the stack, but you can create 1D variable length arrays in C++ using dynamic allocation. Correct me if this is a compiler extension, but it seems to work fine on clang and gcc with --pedantic set.
int size = 10;
int *ary = new int[size]();
I tried to extend the concept to multidimensional arrays. Here are my results. The problem with possiblity 1 and 2 is that they require a constexpr and do not work with variable sizes. Is it possible to make either of them accept a variable as its size? I put possibility 3 as I am aware of it, but it lacks [][] access, which is what I'm looking for.
constexpr int constSize = 10;
//Possibility 1: Only works in C++11
//Creates CONTIGUOUS 2D array equivalent to array[n*n], but with [][] access
int (*ary1)[constSize] = new int[constSize][constSize]();
delete [] ary1;
//Possibility 2:
//Really horrible as it does NOT create a contiguous 2D array
//Instead creates n seperate arrays that are each themselves contiguous
//Also requires a lot of deletes, quite messy
int **ary2 = new int*[constSize];
for (int i = 0; i < n; ++i)
ary2[i] = new int[constSize];
for (int i = 0; i < n; ++i)
delete [] ary2;
delete [] ary2;
//Possibility 3:
//This DOES work with non-constexpr variable
//However it does not offer [][] access, need to access element using ary[i*n+j]
int *ary3 = new int[size*size];
delete [] ary3;
This will create a dynamically allocated 2D variable-length array, with dimensions w and h:
std::vector<std::vector<int>> ary4(w, std::vector<int>(h));
It can be accessed with [][]:
ary4[x][y] = 0;
However, it's not contiguously allocated. To get a contiguous array, here's one solution:
template<typename E>
class Contiguous2DArray
{
public:
Contiguous2DArray(std::size_t width, std::size_t height)
: array(width * height), width(width) {}
E& operator()(std::size_t x, std::size_t y)
{ return array[x + width * y]; }
private:
std::vector<E> array;
std::size_t width;
}
It can be used like this:
Contiguous2DArray<int> ary5(w, h);
ary5(x, y) = 0;
The number of dimensions is fixed, because the type of what [] returns changes based on the number of dimensions. Access is through both repeated [] and (...). The first mimics C-style array lookup. The (...) syntax must be complete (it must pass N args to an N dimensional array). There is a modest efficiency cost to support both.
Uses C++14 features to save on verbosity. None are essential.
Using an an n_dim_array with 0 dimensions will give bad results.
template<class T, size_t N>
struct array_index {
size_t const* dimensions;
size_t offset;
T* buffer;
array_index<T,N-1> operator[](size_t i)&&{
return {dimensions+1, (offset+i)* *dimensions, buffer};
}
template<class...Is, std::enable_if_t<sizeof...(Is) == N>>
T& operator()(size_t i, Is...is)&&{
return std::move(*this)[i](is...);
}
};
template<class T>
struct array_index<T,0> {
size_t const* dimension;
size_t offset;
T* buffer;
T& operator[](size_t i)&&{
return buffer[i+offset];
}
T& operator()(size_t i)&&{
return std::move(*this)[i];
}
};
template<class T, size_t N>
struct n_dim_array {
template<class...Szs, class=std::enable_if_t<sizeof...(Szs)==N>>
explicit n_dim_array( Szs... sizes ):
szs{ { static_cast<size_t>(sizes)... } }
{
size_t sz = 1;
for( size_t s : szs )
sz *= s;
buffer.resize(sz);
}
n_dim_array( n_dim_array const& o ) = default;
n_dim_array& operator=( n_dim_array const& o ) = default;
using top_level_index = array_index<T,N-1>;
top_level_index index(){return {szs.data(),0,buffer.data()};}
auto operator[]( size_t i ) {
return index()[i];
}
using const_top_level_index = array_index<const T,N-1>;
const_top_level_index index()const{return {szs.data(),0,buffer.data()};}
auto operator[]( size_t i ) const {
return index()[i];
}
template<class...Is,class=std::enable_if_t<sizeof...(Is)==N>>
T& operator()(Is...is){
return index()(is...);
}
template<class...Is,class=std::enable_if_t<sizeof...(Is)==N>>
T const& operator()(Is...is) const {
return index()(is...);
}
private:
n_dim_array() = delete;
std::array<size_t,N> szs;
std::vector<T> buffer;
};
live example
Does not support for(:) loop iteration. Writing an iterator isn't that hard: I'd do it in array_index.

Reference Arrays/Matrices in C++

I am new to C++ which is the reason why I'm currently kind of stuck.
Now here's the Problem: I have a couple of float matrices like this:
static const float matr1[4][8] = {0.0, 0.0, ...};
static const float matr2[7][8] = {0.0, 0.5, ...};
etc.
I have a struct like to this one:
struct structy{
float matr[][];
int index;
float somevalue;
};
I have a vector of this structy which is created dynamically dependent on other information.
How can I reference a certain of these declared matrices in my struct variable, given that the first parameter of the struct (rows) varies?
I need a row of the matrices as a float array later on.
Thanks for your help!
You should also store the number of columns and the number of rows in structy, so that you know the dimensions of matr at a later point in time. There is no way to check the length of the 2D array otherwise.
As for your main question: Are you having troubles accessing individual matrix entries in one of your 2D float arrays (matr)?
The only way I have ever seen this done is dynamically:
struct structy{
float ** matr;
// Need to add these 2 variables
int dimensionRow;
int dimensionCol;
int index;
float somevalue;
};
When you place the data into matr, you need to also set dimensionRow, and dimensionCol, as well as dynamically allocate matr prior to filling it, IFF you plan to copy. If not you can simply set matr to the pointer of one of your pre-defined matrices. Either way you will need to also set dimensionRow and dimensionCol.
If you need varying sized matrices, I'd suggest using a vector of vectors. This will save you from the trouble of manually allocating a 2D array and managing its memory. One possible implementation:
struct structy {
std::vector< std::vector<float> > matr;
int index;
float somevalue;
};
structy s;
...
s.matr[0][1] = 42.0f;
...
And either grow the vectors on demand using push_back() or grow them beforehand with resize().
Now if you just want a reference to an external matrix (pointer to static memory) then you can just declare a pointer to pointer (double pointer):
struct structy {
const float ** matr;
int index;
float somevalue;
};
You cannot create a reference (not in the traditional sense) that will refer to different types, and arrays with different lengths are different types. However, you can take advantage of the fact that arrays are contiguous, (and so arrays of arrays are contiguous arrays), and create a class that acts as a reference using pointers.
template<typename T>
class matrix_reference
{
public:
template<size_t R, size_t C>
void set_reference(T (&arr)[R][C])
{
m_start = &arr[0][0];
m_rows = R;
m_columns = C;
}
T& operator()(size_t r, size_t c)
{
return m_start[r * m_columns + c];
}
size_t rows() const { return m_rows; }
size_t columns() const { return m_columns; }
private:
T* m_start;
size_t m_rows;
size_t m_columns;
};
int main()
{
matrix_reference<const float> mref;
mref.set_reference(matr1);
for (size_t r=0; r<mref.rows(); ++r)
{
for (size_t c=0; c<mref.columns; ++c)
std::cout << mref(r,c) << ' ';
std::cout << '\n';
}
mref.set_reference(matr2);
for (size_t r=0; r<mref.rows(); ++r)
{
for (size_t c=0; c<mref.columns; ++c)
std::cout << mref(r,c) << ' ';
std::cout << '\n';
}
}

declaration of a list (or vector) of 2d arrays of sizes known at runtime

I have many 2D arrays for which I will only know the size at runtime.
int arr1[i][k];
int arr2[i][k];
...
Actually they get created in a for loop. I need them all in memory at the end of the loop:
list<????> mylist;
mylist.push_back(arr1);
mylist.push_back(arr2);
How can I push them into a std::vector or std::list ? All the examples I have seen require knowing the size of the array in advance.
Use something copyable and assignable, such as an std::vector. You can either write your own 2D class wrapping a single vector, which would be the preferred option, or use a vector of vectors. For example (untested):
class Array2D
{
public:
Array2D(int rows, int cols) : cols_(cols), data(rows*cols) {}
int& operator()(int i, int j) { return data_[i*cols_ + j]; }
const int& operator()(int i, int j) const { return data_[i*cols_ + j]; }
// to-do: add an efficient, exception safe swap method.
private:
unsigned int cols_;
std::vector<int> data_;
};
Array2D arr1(i, j);
Array2D arr2(i, j);
std::list<Array2D> mylist;
or
std::vector<std::vector<int>> arr1(i, std::vector<int>(k));
std::list<std::vector<std::vector<int>>> mylist;
For 2d array declaration you can use maps
std::maps<int,int> Array2D;
loop{
scanf("%d %d",&a,&b);
Array2D[a]=b;
}

sort one array and other array following?

here is the C++ sample
int a[1000] = {3,1,5,4}
int b[1000] = {7,9,11,3}
how do i make it so if i sort array a, array b also following array a
example
a[1000] = {1,3,4,5}
b[1000] = {9,7,3,11}
is it possible using sort function
sort(a,a+4)
but also sort array b aswell ?
edit: what if there are 3 arrays ?
Instead of using two arrays, can you use an array of pairs and then sort THAT using a special comparison functor rather than the default less-than operator?
The simplest way is to rearrange your data into an array-of-structs instead of a pair of arrays so that each datum is contiguous; then, you can use an appropriate comparator. For example:
struct CompareFirst
{
bool operator() (const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
{
return lhs.first < rhs.first;
}
};
// c[i].first contains a[i], c[i].second contains b[i] for all i
std::pair<int, int> c[1000];
std::sort(c, c+1000, CompareFirst());
If you can't refactor your data like that, then you need to define a custom class that acts as a RandomAccessIterator:
struct ParallalArraySortHelper
{
ParallelArraySortHelper(int *first, int *second)
: a(first), b(second)
{
}
int& operator[] (int index) { return a[index]; }
int operator[] const (int index) { return a[index]; }
ParallelArraySortHelper operator += (int distance)
{
a += distance;
b += distance;
return *this;
}
// etc.
// Rest of the RandomAccessIterator requirements left as an exercise
int *a;
int *b;
};
...
int a[1000] = {...};
int b[1000] = {...};
std::sort(ParallalArraySortHelper(a, b), ParallelArraySortHelper(a+1000, b+1000));
Generate an array the same size as the original, containing the indexes into the array: {0, 1, 2, 3}. Now use a custom comparator functor that compares the elements in an associated array rather than the indexes themselves.
template<typename T>
class CompareIndices
{
public:
CompareIndices(const T * array) : m_AssociatedArray(array) {}
bool operator() (int left, int right) const
{
return std::less(m_AssociatedArray[left], m_AssociatedArray[right]);
}
private:
const T * m_AssociatedArray;
};
std::sort(i, i+4, CompareIndices(a));
Once you have a sorted list of indices, you can apply it to the original array a, or any other b array you want.