How to access a pointer using 2 dimensional syntax?

Viewed 115

I need to store n * 2 values in some array.

I can easily do that like this

int n=5; //in real world this is calculated at runtime
int* arr;
arr = new int[n*2]
//fill arr with values

It's not a coincidence that I need arr to have n X 2 value and not simply n, arr stores pairs of values. I could simply know what's stored and how, and access these pairs by offsetting the index by n,

cout<<"first  pair is"<<arr[0]<<","<<arr[n];
cout<<"second pair is"<<arr[1]<<","<<arr[n+1]
cout<<"last   pair is"<<arr[n-1]<<","<<arr[n+n-1]

But it would be so cool, if I could access these values as if they are in a 2 dimensional array, e.g.

cout<<"first  pair is"<<arr[0][0]<<","<<arr[0][1];
cout<<"second pair is"<<arr[1][0]<<","<<arr[1][1];
cout<<"last   pair is"<<arr[n][0]<<","<<arr[n][1]

The reason I'm not just declaring arr as a bidimensional array is that n is only known at runtime.

Can this be done in some way in C++?

Edit: I strongly prefer arrays over any other object structures for performance reasons. I know the performance differences is practically non-existent on modern computers, but this is my constraint. It has to still be just some integers stored in a contiguous piece of memory.

Edit about duplicate: The question that has been suggested as duplicate hits very close to home, although not exactly, but the answer to that question is just a workaround and not a direct answer. I would be happier to simply have an authoritative answer that it is not possible, rather than having alternative solutions. I am not looking for solutions, since I already have a solution in the question itself. I am looking for an answer to my question.

7 Answers

As long as 2 is a compile time constant, you can easily do this in C++:

const int n = 7;
int (*arr)[2] = new int[n][2];
arr[2][1] = 42;

This declares arr as a pointer *arr to an array of two elements (*arr)[2] which are integers int (*arr)[2]. This new pointer is initialized with a suitable pointer allocated with new.

The parentheses around (*arr) are necessary because the array subscript operator [] has higher precedence than the indirection operator *, and the parentheses force the correct order of operators.

Usage of the resulting pointer is exactly as you want, the memory is allocated in one piece, and you get rid of it with a simple

delete[] arr;

The compile-time-constant restriction is only present in C++, C is more lenient, allowing you to write stuff like

void foo(int width, int height) {
    int (*image)[width] = malloc(height*sizeof(*image));
    image[height-1][width-1] = 42;
    ...

where both dimensions of the 2D array are dynamic. C++ forbids this, forcing you to use compile-time sizes for all but the outermost dimension.

You could just declare arr as a 2D array:

int n=5; //in real world this is calculated at runtime
int** arr;
arr = new int*[n]
for(int i = 0; i < n; i++) { arr[i] = new int[2]; } //each has two items

// ...

std::cout << "first  pair is" << arr[0][0] << "," << arr[0][1];

Or even better, you could use an std::vector:

int n=5; //in real world this is calculated at runtime
std::vector<std::vector<int>> arr(n, std::vector<int>(2));

// ...

std::cout << "first  pair is" << arr[0][0] << "," << arr[0][1];

Or even better better, you could use an std::vector of std::pair:

int n=5; //in real world this is calculated at runtime
std::vector<std::pair<int, int>> arr(n);

// ...

std::cout << "first  pair is" << arr[0].first << "," << arr[0].second;

A simplest way is to declare a vector of the type std::vector<std::pair<int, int>>.

For example

#include <utility>
#include <vector>

//...

std::vector<std::pair<int, int>> v( n );

Otherwise you can dynamically allocate an array like

#include <utility>

//...

std::pair<int, int> *a = new std::pair<int, int>[n];

To access data members you can use expressions like a[i].first and a[i].second.

Or what about std::pair, you mentioned that you have pair of values what you can do is the following :

std::pair<int, int>* arr = new int[N];
// initialize your array :
// arr[i].first = x; arr[i].second = y; // or
// arr[i] = std::make_pair(x, y);
cout<<"first  pair is ("<<arr[0].first<<","<<arr[0].second<<")";

first and second fields are the first and second element respectively in your pair.
This solution will save you the time doing the O(N) loop for double pointers.

Alternative better solution :

std::vector<std::pair<int, int>> arr(N);

and then you can use the operator[] to access and set your elements. This solution is better because it will manage the heap for you which will avoid leaks.

I think you should settle with a std::vector<std::pair<int, int>> but here's another alternative that is safer than using raw new/deletes.

#include <iostream>
#include <memory>

struct mypair {
    int values[2];
    int& operator[](size_t idx) { return values[idx]; }
    int operator[](size_t idx) const { return values[idx]; }
};

int main() {
    size_t N = 10;
    std::unique_ptr<mypair[]> arr = std::make_unique<mypair[]>(N);

    arr[9][1] = 5;

    // arr is automatically deleted when it goes out of scope
}

A simple solution is to use a class as the element of the array:

struct meaningfully_named_class {
    int meaningfully_named_member_first;
    int meaningfully_named_member_second;
};
// practical example
struct point {
    int x;
    int y;
};

std::vector<point> arr(n);
cout<<"first  pair is"<<arr[0  ].x<<","<<arr[0  ].y;
cout<<"second pair is"<<arr[1  ].x<<","<<arr[1  ].y;
cout<<"last   pair is"<<arr[n-1].x<<","<<arr[n-1].y;

The advantage of using a custom class over using the std::pair template is the possibility of giving a meaningful name (as demonstrated) to the type as well as its members.

I strongly prefer arrays over any other object structures

Just to clarify, std::vector is a container for a dynamically allocated array, and the integers in this case will all be contiguous.

To create an n×2 array of int, use:

int (*array)[2] = new int [n][2];
Related