Return one dimension of an array? - c++

How would I only return one dimension of an array, while ignoring the other?
Such as:
int map[4][8];
int MapManager::getMapX(int x)
{
return map[x];
}

The return type should be int* or int[], not int:
int* MapManager::getMapX(int x) {
return map[x];
}
Other than that, you are fine.

With a 2 dimensional array you will only be able to directly return a one dimensional array for the inner array by converting to a pointer, such as
int map[4][8];
int* MapManager::getMapX(int x)
{
return map[x];
}
For the other 'dimension', you will need to have another external array to copy to:
int* MapManager::getMapY(int y, int *outArray, int numElements)
{
for(int i = 0; i < numElements; i++) {
outArray[i] = map[i][y];
}
}
This array needs to be allocated with the correct size. (8 in this case).
The reason for this is that the array elements for the y 'column' are not contiguous in memory, but spread across several arrays (which are the 'x' rows). C arrays rely on this contiguous concept for accessing the elements.

Since none of the other answers here return an actual array (pointers are not arrays), I thought I might show how to really return an array. Or the closest thing possible, which is a reference to an array.
typedef int row_type[8];
row_type& MapManager::getMapX(int x) {
return map[x];
}
What's the point of this? The pointer works the same!
No, it doesn't. The pointer loses type information, namely, the size. You can make begin() and end() functions work with arrays, but you can't with pointers:
// pointer version
int* MapManager::getMapX_ptr(int x) {
return map[x];
}
row_type& row = getMapX(0);
// row is of type int(&)[8]
// notice the size is not lost in the type!
std::sort(begin(row), end(row));
// compiles fine! end() correctly finds the end of the row
int* ptr = getMapX_ptr(0);
// notice how ptr has no size information at all
std::sort(begin(ptr), end(ptr));
// can't possible be made to work!
You can't write end for int*.
template <typename T, std::size_t N>
T* end(T(&arr)[N]) {
return &arr[0] + N;
}
template <typename T>
T* end(T* ptr) {
// what here?
// guess?
// pick a random number?
}

You could create a special class that provides a strided view of an array. That is to say, it skips over values. Here's the beginnings of something like that:
template<typename T>
class StridedView
{
public:
StridedView(T * b, int stride, int count)
:begin_(b), stride_(stride), count_(count)
{}
template<int N>
StridedView(T (&arr)[N])
:begin_(arr), stride_(1), count_(N)
{}
T & operator[](int index)
{
return *(begin_ + index * stride_);
}
const T & operator[](int index) const
{
return *(begin_ + index * stride_);
}
int size() const { return count_; }
private:
T * begin_;
int stride_;
int count_;
};
Then you could have functions that can get you a row or a column as appropriate:
template<typename T, int R, int C>
StridedView<T> GetRow(T (&arr)[R][C], int row)
{
T * begin = (*arr) + (row * C);
return StridedView<T>(begin, 1, C);
}
template<typename T, int R, int C>
StridedView<T> GetColumn(T (&arr)[R][C], int column)
{
T * begin = (*arr) + column;
return StridedView<T>(begin, C, R);
}
Demo

Related

Operator overloading for built in types in C++ to access elements in a 2D array

I am looking for overloading [] operator for a two dimensional array pointer
to access cell element.
Two dimensional array is passed to my function as int *arr.
We can access cell element by *(arr+i*N+j) where N is the column count
and i is row index and j is column index.
But can we write this like arr[i,j] or arr(i,j) for better readability
using some macro or operator overloading?
Any suggestion?
You cannot do that directly.
I would suggest to write a little class/struct that would wrap your 2D array conveniently. Here I use std::vector instead of int *arr and you do not have to care about memory management. The following code presents 3 possibles methods :
Method 1 (recommended) : accessing via mat(i,j)
The operator()(size_t i, size_t j) is called function call operator.
template<typename T>
struct Matrix
{
Matrix(const std::vector<T>& d, size_t s) : Matrix(d, s, s) {}
Matrix(const std::vector<T>& d, size_t c, size_t r) : data_(d), cols_(c), rows_(r) {}
std::vector<T> data_;
size_t cols_;
size_t rows_;
const T& operator()(size_t i, size_t j) const { return data_[i * cols_ + j]; }
T& operator()(size_t i, size_t j) { return data_[i * cols_ + j]; }
// and you can add other convenient methods
};
Use it like this :
Matrix<int> mat({1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 3); // a 3x3 matrix
std::cout << mat(1,2) << std::endl;
Live code
If you know the size at compile time then you can use std::array and change your struct accordingly :
template<typename T, size_t Cols, size_t Rows> struct Matrix
{
std::array<T, Cols * Rows> data_;
// etc...
Method 2 : accessing via mat[{i,j}]
Using the array subscript operator only takes one argument so you can change/add the following operators to your class :
const T& operator[](const std::array<size_t,2>& a) const { return data_[a[0] * cols_ + a[1]]; }
T& operator[](const std::array<size_t,2>& a) { return data_[a[0] * cols_ + a[1]]; }
which can be called like this :
std::cout << mat[{1,2}] << std::endl;
Note that this method is useful when you work on several dimensions (you do not have to write several operator()(size_t i, size_t j, size_t k, etc...)
Method 3 (not recommended) : accessing via mat[Idx(i),Idx(j)]
You can take two arguments using the array subscript operator but you have to overload the comma operator which is not possible between two built in types... So accessing directly via mat[i,j] is not possible (Thanks leemes' comment for pointing that out).
However you can create your own type and overload it. Here an example (put it before your Matrix class definition) :
struct Idx
{
Idx(size_t ii) : i(ii) {}
size_t i;
operator size_t() const { return i; } // implicit user-defined conversion
};
std::array<size_t, 2> operator , (Idx i1, Idx i2)
{
return { i1, i2 };
}
// etc...
// and we do not have to add Matrix operators since we reused the one from Method 2
Use it like this :
std::cout << mat[Idx(1),Idx(2)] << std::endl;
which is not that elegant...
Complete and final live code
You can write an index function to hide the formula.
If your N is defined globally, write
int index(int i, int j) {
return i * N + j;
}
and use it with
arr[index(i, j)]
Alternatively, write a wrapper class around your pointer. This class can be written with absolutely no runtime overhead. It can have an operator to allow the syntax
arr[i][j]
where arr is an instance of the wrapper class. Such a wrapper can be defined like this:
class Array2DWrapper {
int *ptr;
public:
Array2DWrapper(int *ptr) : ptr(ptr) {}
int * operator[](int i) {
return ptr + i*N;
}
};
// USAGE:
void exampleFunction(int *arrPtr) {
Array2DWrapper arr { arrPtr };
...
arr[i][j];
...
}
As you can see, the idea is to overload operator[] for the outer dimension, which returns a pointer to the inner dimension. When the user of this class writes arr[i], it calls the custom operator overload, which returns an int*, then the next [j] accesses the element using the builtin operator[] for pointers.
Note that the above class can be used as a function parameter, but the caller can call it with a raw pointer to some 2D array. This will call the constructor of this class automatically ("implicit conversion").
// USAGE with implicit conversion on the call site:
void exampleFunction(Array2DWrapper arr) {
...
arr[i][j];
...
}
// Note how the caller doesn't need to wrap it explicitly:
int * myArrPtr = ...;
exampleFunction(myArrPtr);
If N is not defined globally, you should add it as a member to the class, as well as to the constructor.
class Array2DWrapperDynamicN {
int *ptr;
int N;
public:
Array2DWrapper(int *ptr, int N) : ptr(ptr), N(N) {}
int * operator[](int i) {
return ptr + i*N;
}
};
But now, the implicit conversion doesn't work anymore.
// USAGE:
void exampleFunction(int *arrPtr, int N) {
Array2DWrapperDynamicN arr { arrPtr, N };
...
arr[i][j];
...
}
No.
Operator overloading requires at least one of the argument types to be a class/struct/union. And macros can't do that.
The closest you can get is to pass the array by reference, if possible. E.g.:
template<std::size_t width, std::size_t height>
void doThings(int(& array)[width][height])
{
// access array[i][j];
}
Or if that's not possible, a helper non-operator function, to hide the ugly part:
int& access(int* array, std::size_t i, std::size_t j)
{
return *(arr + i*N + j);
}
Or maybe you need to tackle the underlying problem here. Why is a 2D array passed by int* in the first place?
The important thing to remember here is to not over-complicate things.
One cannot change the behavior of operators for built types. If you want to overload an operator, at least one of the operands must a user-defined type.

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.

Multidimensional array: operator overloading

I have a class with a multidimensional array:
it is possible to create a one, two, ..., n dimensional array with this class
if the array has n dimensions, i want to use n operator[] to get an object:
example:
A a({2,2,2,2}];
a[0][1][1][0] = 5;
but array is not a vector of pointer which lead to other vectors etc...
so i want the operator[] to return a class object until the last dimension, then return a integer
This is a strongly simplified code, but it shows my problem:
The error i receive: "[Error] cannot convert 'A::B' to 'int' in initialization"
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <iostream> // cin, cout...
class A {
private:
static int* a;
public:
static int dimensions;
A(int i=0) {
dimensions = i;
a = new int[5];
for(int j=0; j<5; j++) a[j]=j;
};
class B{
public:
B operator[](std::ptrdiff_t);
};
class C: public B{
public:
int& operator[](std::ptrdiff_t);
};
B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
B res;
if (dimensions <= 1){
res = C();
}
else{
res = B();
}
dimensions--;
return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
B res;
if (dimensions <=1){
res = B();
}
else{
res = C();
}
dimensions--;
return res;
}
int& A::C::operator[](std::ptrdiff_t i){
return *(a+i);
}
int main(){
A* obj = new A(5);
int res = obj[1][1][1][1][1];
std::cout<< res << std::endl;
}
The operator[] is evaluated from left to right in obj[1][1]...[1], so obj[1] returns a B object. Suppose now you just have int res = obj[1], then you'll assign to a B object (or C object in the case of multiple invocations of []) an int, but there is no conversion from B or C to int. You probably need to write a conversion operator, like
operator int()
{
// convert to int here
}
for A, B and C, as overloaded operators are not inherited.
I got rid of your compiling error just by writing such operators for A and B (of course I have linking errors since there are un-defined functions).
Also, note that if you want to write something like obj[1][1]...[1] = 10, you need to overload operator=, as again there is no implicit conversion from int to A or your proxy objects.
Hope this makes sense.
PS: see also #Oncaphillis' comment!
vsoftco is totally right, you need to implement an overload operator if you want to actually access your elements. This is necessary if you want it to be dynamic, which is how you describe it. I actually thought this was an interesting problem, so I implemented what you described as a template. I think it works, but a few things might be slightly off. Here's the code:
template<typename T>
class nDimArray {
using thisT = nDimArray<T>;
T m_value;
std::vector<thisT*> m_children;
public:
nDimArray(std::vector<T> sizes) {
assert(sizes.size() != 0);
int thisSize = sizes[sizes.size() - 1];
sizes.pop_back();
m_children.resize(thisSize);
if(sizes.size() == 0) {
//initialize elements
for(auto &c : m_children) {
c = new nDimArray(T(0));
}
} else {
//initialize children
for(auto &c : m_children) {
c = new nDimArray(sizes);
}
}
}
~nDimArray() {
for(auto &c : m_children) {
delete c;
}
}
nDimArray<T> &operator[](const unsigned int index) {
assert(!isElement());
assert(index < m_children.size());
return *m_children[index];
}
//icky dynamic cast operators
operator T() {
assert(isElement());
return m_value;
}
T &operator=(T value) {
assert(isElement());
m_value = value;
return m_value;
}
private:
nDimArray(T value) {
m_value = value;
}
bool isElement() const {
return m_children.size() == 0;
}
//no implementation yet
nDimArray(const nDimArray&);
nDimArray&operator=(const nDimArray&);
};
The basic idea is that this class can either act as an array of arrays, or an element. That means that in fact an array of arrays COULD be an array of elements! When you want to get a value, it tries to cast it to an element, and if that doesn't work, it just throws an assertion error.
Hopefully it makes sense, and of course if you have any questions ask away! In fact, I hope you do ask because the scope of the problem you describe is greater than you probably think it is.
It could be fun to use a Russian-doll style template class for this.
// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
foo<d-1, n> data[n];
public:
foo<d-1, n>& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
int data[n];
public:
int& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
int main(int argc, char** argv)
{
foo<3, 10> myFoo;
for(int i=0; i<10; ++i)
for(int j=0; j<10; ++j)
for(int k=0; k<10; ++k)
myFoo[i][j][k] = i*10000 + j*100 + k;
return myFoo[9][9][9]; // would be 090909 in this case
}
Each dimension keeps an array of previous-dimension elements. Dimension 1 uses the base specialization that tracks a 1D int array. Dimension 2 would then keep an array of one-dimentional arrays, D3 would have an array of two-dimensional arrays, etc. Then access looks the same as native multi-dimensional arrays. I'm using arrays inside the class in my example. This makes all the memory contiguous for the n-dimensional arrays, and doesn't require dynamic allocations inside the class. However, you could provide the same functionality with dynamic allocation as well.

c++ array[var][2] as a class member

I would like to have an array of unsigned integers within a class, and its size should be [var][2], so the user will be able to choose var in runtime.
Is there a better way than allocating a two dimensional array (an allocated array of pointers to allocated arrays)?
In the class I have:
unsigned int *(*hashFunc);
And in the initializing function:
hashFunc = new unsigned int*[var];
for(unsigned int i = 0; i<var; ++i)
hashFunc[i] = new unsigned int[2];
I want to only allocate once, and I think it should somehow be possible because I only have one unknown dimension (var is unknown but 2 I know from the beginning).
Thanks!
If the sizes are known at compilation time, you should use std::array. If one of the dimensions are not known until runtime, you should use std::vector.
You can of course combine them:
std::vector<std::array<unsigned int, 2>> hashFunc;
The above declares hashFunc to be a vector of arrays, and the arrays is of size two and of type unsigned int, just like specified in the question.
Then to add a new inner array just use push_back of the vector:
hashFunc.push_back({{ 1, 2 }});
(And yes, double braces are needed. The outer to construct the std::array object, and the inner for the actual array data.)
Or if you want to set the size of the outer vector at once (for example if you (runtime) know the size beforehand) you could do e.g.
hashFunc = std::vector<std::array<unsigned int, 2>>(var);
Where var above is the size of the "first dimension". Now you can directly access hashFunc[x][y] where x is in range of var and y is zero or one.
(To answer the direct question.) You can declare the pointer as
int (*hashFunc)[2];
and allocate it in one shot as
hashFunc = new int[var][2];
There's two ways you can go about this. Either have a class with a bare pointer or encapsulate it with std::vector and std::array. Below is a sample of two possible implementations which do exactly the same.
#include <iostream>
#include <vector>
#include <array>
#include <stdexcept>
class TheClass {
public:
typedef int TwoInts[2];
TheClass(const std::size_t size) : m_size(size)
{
m_hashFunc = new TwoInts[m_size];
if (m_hashFunc == NULL) throw std::runtime_error("Ran out of memory.");
}
virtual ~TheClass()
{
delete [] m_hashFunc;
}
inline std::size_t size() const { return m_size; }
inline int& operator()(const std::size_t i, const std::size_t j) { return m_hashFunc[i][j]; }
inline const int& operator()(const std::size_t i, const std::size_t j) const { return m_hashFunc[i][j]; }
private:
std::size_t m_size;
TwoInts* m_hashFunc;
};
class AnotherClass {
public:
AnotherClass(const std::size_t size) : m_hashFunc(size)
{
// Nothing to do here.
}
// No destructor required.
inline std::size_t size() const { return m_hashFunc.size(); }
inline int& operator()(const std::size_t i, const std::size_t j) { return m_hashFunc[i][j]; }
inline const int& operator()(const std::size_t i, const std::size_t j) const { return m_hashFunc[i][j]; }
private:
std::vector<std::array<int, 2>> m_hashFunc;
};
int main(int argc, char *argv[]) {
if (argc < 2) return -1;
const std::size_t runtimesize = static_cast<std::size_t>(atoll(argv[1]));
const std::size_t i1 = rand() % runtimesize;
const std::size_t i2 = rand() % runtimesize;
TheClass instance1(runtimesize);
AnotherClass instance2(runtimesize);
instance1(i1,0) = instance2(i1,0) = 4;
instance1(i2,1) = instance2(i2,1) = 2;
std::cout << instance1(i1,0) << ' ' << instance2(i1,0) << std::endl;
std::cout << instance1(i2,1) << ' ' << instance2(i2,1) << std::endl;
std::cout << instance1.size() << std::endl;
std::cout << instance2.size() << std::endl;
// ... etc
return 0;
}

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.