how to return 2d array?

Know how to return 1d array, can not find solution for 2d array
Cant use vector
Know how to return 1d array
You probably just know how to return the pointer, if you can't return a higher dimension array.

The trick is to return an object. So define your 2D array as an object; you can use std::array<std::array<T, NCOLS>, NROWS>, or a vector equivalent or a struct/class. Then just return that.

If you stick with pointers, you'll loose dimension sizes.

e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <vector>
#include <iostream>

using int_d2array_t = std::vector<std::vector<int>>;

int_d2array_t create_2darray(size_t nrows, size_t ncols, int val = -1) {
    return int_d2array_t( nrows, std::vector<int>(ncols, val) );
}

int main() {
    constexpr size_t nrows{12};
    constexpr size_t ncols{6};
    auto int2d = create_2darray(nrows, ncols);

    std::cout << "nrows=" << int2d.size()
        << " ncols=" << int2d[0].size()
        << '\n';
}


EDIT: Just saw this bit,
Cant use vector
Is this homework?
Last edited on
don't return 2D array, instead pass it as a reference to function parameter.
if you know the dimensions (compile time constant 2d array?) you can return it as 1d and cast it back with some ugly tricks. But that is so very C and weird code.
There are a lot of reasons why 1d mapped to 2d is easier to work with (you manually index the 1d to make it '2d' exactly the same way C does it).

if you need to see the casting junk I can figure it out again, but its not a good idea.
Last edited on
Know how to return 1d array, can not find solution for 2d array
Cant use vector


You can't return a c-style array of any dimensions. All you can do is return a pointer to the first element.

You can wrap an array inside of a struct and return that. But the C++ way is to either use std::vector or std:::array. Why can't you use these?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

struct MyArray {
	int arr[2][3] { };
};

MyArray func1() {
	MyArray myarr;

	for (auto r : { 0, 1 })
		for (auto c : { 0, 1, 2 })
			myarr.arr[r][c] = r + c;

	return myarr;
}

int main() {
	const auto arr1 { func1() };

	for (auto r : { 0, 1 }) {
		for (auto c : { 0, 1, 2 })
			std::cout << arr1.arr[r][c] << ' ';

		std::cout << '\n';
	}
}

To return a 2D array from a function in C++, you need to declare the function with the return type as a pointer to an array


That doesn't return a 2D array. It returns a pointer and the memory to which it refers must still be valid after the function returns (eg using static as above). But this isn't 'returning an array' - just a pointer. As has been mentioned above, in c/C++ you can't directly return a c-style array from a function.

maxim2511 wrote:
The array itself is declared as a static variable, so it persists between function calls.

I've seen some functions that return a pointer to a static local object like this but there are reasons why this is not more common. If the object can be modified (by the caller or by the function itself) then it's not thread-safe and could be surprising if you don't know or forget about this and call the function to get two different objects when in fact they are one and the same.

Surprise, surprise!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <iomanip>
#include <ctime>
 
int main()
{
	std::time_t now = std::time(nullptr);
	std::time_t later = now + 8640000;
	
	std::tm* n = std::localtime(&now);
	std::tm* l = std::localtime(&later);

	std::cout << "Now:   " << std::put_time(n, "%Y-%m-%d") << "\n";
	std::cout << "Later: " << std::put_time(l, "%Y-%m-%d") << "\n";
}
Now:   2023-07-06
Later: 2023-07-06

Just reordering the lines a bit makes it output correctly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <iomanip>
#include <ctime>
 
int main()
{
	std::time_t now = std::time(nullptr);
	std::tm* n = std::localtime(&now);
	std::cout << "Now:   " << std::put_time(n, "%Y-%m-%d") << "\n";
	
	std::time_t later = now + 8640000;
	std::tm* l = std::localtime(&later);
	std::cout << "Later: " << std::put_time(l, "%Y-%m-%d") << "\n";
}
Now:   2023-03-28
Later: 2023-07-06
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
using namespace std;

//===================================================================

template<typename T>
T** allocate( int rows, int cols )
{
   T **a = new T*[rows];
   a[0] = new T[rows * cols];
   for ( int r = 1; r < rows; r++ ) a[r] = a[r-1] + cols;
   return a;
}

//===================================================================

template<typename T>
void deallocate( T **a )
{
   delete [] a[0];
   delete [] a;
}

//===================================================================

template<typename T>
void print( T **a, int rows, int cols )
{
   for ( int r = 0; r < rows; r++ )
   {
      for ( int c = 0; c < cols; c++ ) cout << a[r][c] << '\t';
      cout << '\n';
   }
}

//===================================================================

int main()
{
   const int ROWS = 3, COLS = 5;
   double **a = allocate<double>( ROWS, COLS );

   for ( int r = 0; r < ROWS; r++ )
      for ( int c = 0; c < COLS; c++ ) a[r][c] = 10 * r + c;

   print( a, ROWS, COLS );
   deallocate( a );
}


0	1	2	3	4	
10	11	12	13	14	
20	21	22	23	24	

Last edited on
localtime() et al are notorious for their use of an internal single buffer per thread!
1
2
3
template<typename T>
T** allocate( int rows, int cols )
...


Yes - but why in C++? This is very c-ish. I know the OP said no vector - but why? In C++ you'd either use a std::vector or a std::array - which can be returned from a function. And if you did require a 2d array of contiguous memory, you'd have a class that supported that which could be returned from a function...
Sorry, @seeplus, I just created that function so that I could call it roughly the way I would in Fortran. (Except that Fortran very kindly deallocates for you when it goes out of scope). For example,
https://onlinegdb.com/k8zAxfY2u

There are a lot of advantages - particularly when working in MPI or other parallel paradigm - from having multidimensional arrays with contiguous storage. vector<<vector>> just doesn't do that, and why create a new class when you don't need to?

Maybe we'd better ask the ChatBot ...
Last edited on
That's modern Fortran? - I'd never recognise it! It's vastly changed since I last used Fortran IV and 77 ...
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <algorithm>

template<typename T>
class R2D2 {
public:
	R2D2(size_t r, size_t c) : rws(r), cls(c), a(new T* [r]) {
		a[0] = new T[r * c];

		for (size_t rw { 1 }; rw < r; ++rw)
			a[rw] = a[rw - 1] + c;
	}

	~R2D2() {
		delete[] a[0];
		delete[] a;
	}

	R2D2(const R2D2& rhs) : R2D2(rhs.rows(), rhs.cols()) {
		std::copy_n(rhs.a[0], rws * cls, a[0]);
	}

	R2D2& operator=(R2D2) = delete;

	T* operator[](size_t r) {
		return a[r];
	}

	const T* operator[](size_t r) const {
		return a[r];
	}

	auto rows() const {
		return rws;
	}

	auto cols() const {
		return cls;
	}

	friend std::ostream& operator<<(std::ostream& os, const R2D2& a) {
		for (size_t r {}; r < a.rows(); ++r) {
			for (size_t c {}; c < a.cols(); ++c)
				std::cout << a[r][c] << '\t';

			std::cout << '\n';
		}

		return os;
	}

private:
	size_t rws {};
	size_t cls {};
	T** a {};
};

auto myfunc() {
	constexpr size_t ROWS { 3 }, COLS { 5 };

	R2D2<double> a(ROWS, COLS);

	for (size_t r {}; r < ROWS; ++r)
		for (int c {}; c < COLS; ++c)
			a[r][c] = 10.0 * r + c;

	return a;
}

int main() {
	const auto a { myfunc() };

	std::cout << a;
}



0       1       2       3       4
10      11      12      13      14
20      21      22      23      24


Last edited on
Topic archived. No new replies allowed.