I'm attempting to make a maze-solving program, and while the algorithm is sound (at least in my head), I've been running into a roadblock with 2D arrays. I'm coming from C# and Java, so the syntax is giving me grief.
Here's an SSCCE:
//Main.cpp
#include "MazeSolver.h"
int main()
{
MazeSolver mazeSolver;
char maze[51][51] = { }; // Not bothering to show code for populating the array
mazeSolver.setMaze(maze);
}
//MazeSolver.cpp
#include "MazeSolver.h"
MazeSolver::MazeSolver() { }
void MazeSolver::setMaze(char maze[51][51])
{
this->maze = maze;
}
//MazeSolver.h
#ifndef _MAZESOLVER_H
#define _MAZESOLVER_H
class MazeSolver
{
private:
char **maze; // This is likely the problem, I'm at wits end in regards to
// what notation is needed here. I do not want to hard-copy
// the entire array, I just need to access it (via pointer)
// I've also tried just using char maze[51][51] here, char *maze, etc...
public:
MazeSolver();
void setMaze(char maze[51][51]);
}
You cant assign (Or convert) 2d arrays (array[ROWS][COLUMNS]) to pointers to pointers (aka **) because the memory layout of a 2d array is (could be) very different to the memory layout the pointer of pointers could point to.
Check this thread for more info about this topic.
If suggest you to use the de facto C++ standard container, std::vector, instead of a plain array:
class MazeSolver
{
std::vector<std::vector<char>> maze;
void setMaze( const std::vector<std::vector<char>>& new_maze )
{
maze = new_maze;
}
};
Note that a vector has size 0 by default (At the point of its initialization), so you should fill it with elements:
for( std::size_t i = 0 i < ROWS ; ++i )
{
maze.push_back( std::vector<char>() );
for( std::size_t j = 0 ; j < COLUMNS ; ++j )
maze[i].push_back( ' ' );
}
However, C++11 (The current iteration of the language) has a std::array container which is like a C array but with the interface of other Standard Library Containers:
std::array<char,ROWS*COLUMNS> maze;
<rant>
This is one of the weird quirks of C++.
C++ 2D arrays are NOT jagged arrays. When you declare char maze[51][51], it actually allocates 1 contiguous array 51*51 members long. sizeof(maze) == 51*51. When you dereference a value, maze[a][b], what it actually does is *(maze+51*a+b). All this is under the hood.
A Jagged Array is an array of arrays, a char**. In this case, you have an array of 51 pointers size == (51*sizeof(void*)). In each position, the pointer points to a completely different memory location, allocated to 51 members long.
This is ANNOYING because you can't just convert the two, even by casting. You have to deal with weird syntax, such as char (*maze)[51] to get a pointer to the 2D array.
Whats even more annoying is the following happens:
int foo(int maze[51][51])
{
return sizeof(maze);
}
int maze[51][51];
int main(int argc, char** argv)
{
std::cout << sizeof(maze) << std::endl;//return 51*51*sizeof(int);
std::cout << foo(maze) << std::endl;//return 8, sizeof(void*);
}
So it implicitly passes by reference, not by value, which is opposite all the rest of C++.
</rant>
tl;dr;
The correct syntax for a pointer to a 2D array is char (*maze)[51];. Your syntax is for a jagged array (arrays of arrays) which is NOT the same thing in C++.
Related
#include<iomanip>
using namespace std;
void displaySeats(bool taken[][]){
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 30;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
int main()
{
bool taken[15][30];
int rows, clm;
rows = 15;
clm = 30;
displaySeats(taken);
system("PAUSE");
}
it is giving me errors like
an array may not have elements of this type line 6
'void displaySeats(bool [][])': cannot convert argument 1 from 'bool [15][30]' to 'bool [][]' line 25
'taken': missing subscript line 6
but if i move the code from the function to the main it works perfectly fine.
I can have a array of type bool.
there is subscript.
i've tried passing through a pointer to the array (which arrays are anyway)
i've tried passing through an array of pointers
a 2d array of pointers
a pointer of an array of pointers.
scoured stack exchange and looks at other peoples code and i am doing it almost line for line.
does it not work with bools? because it doesn't work with ints either.
When expecting an array argument on a function you don't need to know how many elements it has, since you can index it freely. However, you need to know how big each element is, to know how many bytes to skip for each index, when indexing.
In this case your element is a bool[30] with size 30 bytes. You need to signify this on your function signature.
void displaySeats(bool taken[15][30]){ // array 15*30 bool
// OR
void displaySeats(bool taken[][30]){ // array with elements bool[30]
// OR
void displaySeats(bool (*taken)[30]){ // pointer to element(s) bool[30]
See below on how 2d arrays are structured in memory and this will make sense.
This is a big topic. You need to research how arrays really work in C++. But the short (and surprising) answer is that you cannot have an array as a parameter to a function in C++. This code void func(int a[]) is actually an alternative for the pointer code void func(int* a).
But this simple rule only works for one dimension. With two dimensions only the first dimension is turned into a pointer. So the equivalent for your case would be
void displaySeats(bool (*taken)[30]){
or
void displaySeats(bool taken[][30]){
or
void displaySeats(bool taken[15][30]){
But the important part is that in all cases taken is a pointer not an array.
Because arrays are so useless in C++ we prefer to use std::vector, which doesn't have the same limitations (and has many other advantages besides).
The taken array must have some size defined like so taken[15][30].
Also, you have to include <iostream> in order to use cout.
try specifying size of array, or use reference see here
#include<iomanip>
#include <iostream>
using namespace std;
// template <typename t>
void displaySeats(bool taken[][30]){
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 30;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
int main()
{
bool taken[15][30];
int rows, clm;
rows = 15;
clm = 30;
displaySeats(taken);
system("PAUSE");
}
As mentioned, bool taken[][] isn't valid. Only the left-most (outer) array extent may be left unspecified.
I prefer the longest form to be explicit and to take the argument by reference. Motivation: Taking it as a pointer would lead to a runtime problem if you happen to pass in a nullptr by mistake (unless you check if(taken==nullptr) return; in the function). With a reference, you'd get a compilation error instead so there's no need to check if it's a nullptr.
Also, make the function argument const since you're not making changes to the array in the display function.
constexpr size_t ROWS = 15;
constexpr size_t COLS = 30;
void displaySeats(const bool (&taken)[ROWS][COLS]) {
using std::cout;
for (size_t i = 0; i < ROWS; i++) {
for (size_t j = 0; j < COLS;j++)
if (taken[i][j])
cout << '*';
else
cout << '#';
cout << '\n';
}
}
You can then easily turn this into a function template to accept arbitrary 2D arrays of bool:
template<size_t ROWS, size_t COLS>
void displaySeats(const bool (&taken)[ROWS][COLS]) {
// same as above
}
If you start to study language rules, not their interpretation, you'll come to realization that neither C nor C++ document doesn't mention an array with multiple dimensions at all, not like FORTRAN or flavors of Basic. It speaks about just an array as a form of object.
Array is an object which has a continuous storage containing multiple objects of same type. Array is an object. Thus we may have an array of arrays. That's what bool taken[15][30] is. It can be read this way
bool (taken[15])[30]; //Array of 15 arrays of 30 bools each
While this line is correct
void foo(bool arg[]) // same as void foo(bool *arg) for all purposes
And this one gives compiler some information:
void foo(bool arg[30]) // sizeof(arg) would return size of array,
// not size of pointer type
This line is ill-formed.
void boo(bool arg[][]) //
It would suggest an unknown type of array elements (how big is the element of array?), which contradicts ideology of strongly-typed language.
Two correct styles can be mixed:
void foo(bool arg[][30]) // same as void foo(bool (*arg)[30])
Here the parameter of function is a pointer to an array of bools.
Functions in C or C++ never could take an array or return an array. The reason to that is that C (and subsequently, C++) by default can pass parameters and return results by value, which means loading those values into stack. Doing that to array would be ineffective because of stack possible limitations. There were also logical conundrums in syntax, where name of array decays to a pointer. Thus arrays supposed to be passed by their address, by a pointer and can be returned only by pointer as well.
But you can pass structures by value and you can return them as result, even if they contain arrays. C++ classes expands functionality of original aggregate type struct and std::array is an example of template for such aggregate.
In order to understand how void pointer works, I wrote a piece of code to test it. However I got the segmentation fault during the runtime and had not clue how to deal with it. The key point here is that, the data are generated inside that function call. You don't know the datatype and how large is that void pointer should be allocated.
#include <iostream>
#include <vector>
int valueAssignment(void *ptr1, void *ptr2){
std::vector<int> vi;
std::vector<double> vb;
int num = 10;
for (size_t i = 0; i < num; i++) {
vi.push_back((int)rand());
vb.push_back((double)rand());
std::cerr <<i<<": "<< vi[i] <<'\t'<<vb[i]<<'\n';
}
for (size_t i = 0; i < num; i++) ((int*)ptr1)[i] = vi[i];
for (size_t i = 0; i < num; i++) ((double*) ptr2)[i] = vb[i];
return num;
}
int main(int argc, char const *argv[]) {
void * intPtr, *doublePtr;
int size;
size = valueAssignment(intPtr,doublePtr);
std::cerr << "/* ------------------- */" << '\n';
for (size_t i = 0; i < size; i++) {
std::cout <<i<<": "<< ((int*)intPtr)[i]<<"," <<((double *)doublePtr)[i]<<std::endl;
}
return 0;
}
We should simply follow the many many recommendations given by experts.
Do not use raw pointers in C++
Do not use raw pointers in C++
Do not use raw pointers in C++
WIth that we woulld already make a huge progress. But then, you want to learn about a void* pointer. The void pointer is a somehow generic pointer that can point to anything. You can also assign other pointer types to a void pointer. Vice versa this is not possible and you need an explicit type cast.
With classes and espcially derived classes you may even lose information by doing such casts.
Legacy C codes often uses void pointers, but that is basically no problem.
In modern C++, void pointers are rarely needed. Maybe mainly to interface with legacy code.
So, now to your special case:
The problem has been mentioned already in many comments. And this has nothing to do with void pointers, but pointers in general. Your pointers are not initialized. They point to somewhere, randomly at some point in memory. And in your subfunction, you are assigning values to those none initalized pointers, writing values to somewhere randomly in memory. Your program will chrash.
So, a pointer needs to point to somewhere defined. To a defined memory region.
You could have written:
int intArray10[10]; // You should not use C-Style plain arrays
double doubleArray10[10]; // You should not use C-Style plain arrays
void* intPtr = intArray10;
void* doublePtr = doubleArray10;
Then your pointer would point to a defined region. And you program would work.
But then you want to define or use somehow the pointer within your function. If the size is known, then you can allocate data with new and assign it to the pointer. The pointer must then be passed as "reference to pointer" or "pointer to pointer". If the size is unknown, it will be more difficult, you need to inform the calling program on the size.
All this is very error prone and should be avoided.
So again: Do not use raw pointer. If you really need them for some ressource management, then use std::unique_ptr or std::shared_ptr.
Or better use STL container in the first place.
There are tons of similar questions, but still I could not find any answer relevant for the feature of variable length arrays in C99/C11.
How to pass multidimensional variable length array to a function in C99/C11?
For example:
void foo(int n, int arr[][]) // <-- error here, how to fix?
{
}
void bar(int n)
{
int arr[n][n];
foo(n, arr);
}
Compiler (g++-4.7 -std=gnu++11) says:
error: declaration of ‘arr’ as multidimensional array must have bounds for all dimensions except the first
If I change it to int *arr[], compiler still complains:
error: cannot convert ‘int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]’ to ‘int**’ for argument ‘2’ to ‘void foo(int, int**)’
Next question, how to pass it by value and how to pass it by reference? Apparently, usually you don't want the entire array to be copied when you pass it to a function.
With constant length arrays it's simple, since, as the "constant" implies, you should know the length when you declare the function:
void foo2(int n, int arr[][10]) // <-- ok
{
}
void bar2()
{
int arr[10][10];
foo2(10, arr);
}
I know, passing arrays to functions like this is not a best practice, and I don't like it at all. It is probably better to do with flat pointers, or objects (like std:vector) or somehow else. But still, I'm a bit curios what is the answer here from a theoretical standpoint.
Passing arrays to functions is a bit funny in C and C++. There are no rvalues of array types, so you're actually passing a pointer.
To address a 2D array (a real one, not array of arrays), you'll need to pass 2 chunks of data:
the pointer to where it starts
how wide one row is
And these are two separate values, be it C or C++ or with VLA or without or whatnot.
Some ways to write that:
Simplest, works everywhere but needs more manual work
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA, standard C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
VLA w/ reversed arguments, forward parameter declaration (GNU C extension)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
C++ w/ VLA (GNU C++ extension, terribly ugly)
void foo(int width, int* ptr) {
typedef int arrtype[][width];
arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
arr[x][y]=5;
}
Big remark:
The [x][y] notation with a 2D array works because the array's type contains the width. No VLA = array types must be fixed at compile-time.
Hence: If you can't use VLA, then...
there's no way to handle it in C,
there's no way to handle it without a proxy class w/ overloaded operator overloading in C++.
If you can use VLA (C99 or GNU C++ extensions), then...
you're in the green in C,
you still need a mess in C++, use classes instead.
For C++, boost::multi_array is a solid choice.
A workaround
For 2D arrays, you can make two separate allocations:
a 1D array of pointers to T (A)
a 2D array of T (B)
Then set the pointers in (A) to point into respective rows of (B).
With this setup, you can just pass (A) around as a simple T** and it will behave well with [x][y] indexing.
This solution is nice for 2D, but needs more and more boilerplate for higher dimensions. It's also slower than the VLA solution because of the extra layer of indirection.
You may also run into a similar solution with a separate allocation for every B's row. In C this looks like a malloc-in-a-loop, and is analogous of C++'s vector-of-vectors. However this takes away the benefit of having the whole array in one block.
There is no clear cut way for doing this but you can use a workaround to treat a 2 dimensional array as a one dimensional array and then reconvert it to a two dimensional array inside the function.
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}
string** flowFile() {
string line;
string word[8];
int i=0;
static string flow[23][2];
ifstream myfile ("test.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
strSplit(line,word);
flow[i][0]=word[1];
flow[i++][1]=word[2];
}
myfile.close();
}
else cout << "Unable to open file";
return flow;
}
int main()
{
string **fl=flowFile();
}
I'm getting this error:
error: cannot convert ‘std::string (*)[2] {aka std::basic_string<char> (*)[2]}’
to ‘std::string** {aka std::basic_string<char>**}’
in return
What is wrong with my code?
string flow[23][2] and string ** are two different incompatible types. One cannot convert to another implicitly. Thats all. The solution is to make them compatible, by making the later string [23][2], return reference and accept reference, but that would still be a bad solution, because you're still working with raw arrays.
A good solution is to use std::vector and std::string. Maybe, you need std::pair also, or std::array.
Here is one possible solution:
#include <vector>
#include <array>
#include <string>
//C++11 style typedef
using flow_data_t = std::vector<std::array<std::string,2>>;
//reimplementation of your function
flow_data_t flowFile()
{
std::string line;
std::string word[8];
int i=0;
flow_data_t flow;
std::ifstream myfile ("test.txt");
if ( !myfile )
cout << "Unable to open file";
while ( std::getline (myfile,line) )
{
strSplit(line,word);
flow.push_back({word[0], word[1]});
}
return flow;
}
int main()
{
flow_data_t data=flowFile();
for(auto const & row : data)
for(auto const & col : row)
//work!
}
Hope that helps.
You cannot return array from a function even though you can return a pointer and let your array decay to a pointer: Array Decay
However 2D array can decay to neither T* nor T** because of the memory layout of the array is different from "2D pointer array" (it is actually more like flattened), and you cannot return array from function. However in C++ you can return array reference Full Code:
//This does not work
//typedef string * string2d[2];
//typedef string *(&string2d)[2];
typedef string (&string2d)[23][2];
string2d flowFile() {
static string flow[23][2];
return flow;
}
Array reference would even preserve the information of how big each row and columns are and no array decaying happen.
Of course, a more suggested "C++ way" to do this is using std::vector (as always).
In C++, arrays have type std::vector. You should use these, not low-level builtin arrays declared with [].
In C++, string [23] is sometimes interchangeable with string*, but string[23][2] is never interchangeable with string**. That's one reason you should not use builtin arrays.
In C++, you cannot return a local builtin array variable. It will compile but then your program will probably crash. This is another reason you should not use builtin arrays. (Returning a static array should be OK though).
There are many more reasons.
There is nothing wrong with returning a pointer to a static variable. It's just that the return type must be declared properly. It kind of makes sense if you try to reproduce what the declarations mean, and what the compiler accordingly tries to do. Consider the declaration static string flow[23][2];. It declares 23 rows of strings, each with 2 elements. It helps if you look at it as a one-dimensional array. It just so happens that the array elements are arrays, but that's not so important right now (but we'll come back to it). From this perspective the array has just 23 elements, and each element has the size of 2 strings. Like with all arrays, the elements (here: arrys of 2 strings) are simply lined up in memory.
Like any array, flow will in most contexts decay to a pointer to its first element. Incrementing that pointer will point to the next element, i.e the second row. Numerically the compiler must add 2*sizeof(string) to the address of flow in order to compute the address of flow's next element, which would be flow[1]. (It comes directly behind flow[0]. No magic here.)
Now if you declare string **flowpp, flowpp is a pointer already, no need to decay. If we think it is pointing to the first element in an array, what type would the elements have? Sure enough: plain pointers. Incrementing flowpp would let it point to the next element. My pointers are 4 bytes large, so that numerically adding just 4 to flowpp would be enough to access flowpp's next element. Compared to what needs to be added to flow (remember, 2*sizeof(string)), that's completely different. The compiler computes the offsets of elements depending of what the pointers point to! Which is very different in the two cases.
So what can your function return? What does flow decay to when you return it? It decays to a pointer to its first element. The elements are arrays of two strings. It must be string xxx[2], with xxx being a pointer: hence string (*p)[2]. If the pointer is actually returned by a function, we have a function call instead of plain p, so it's (*f())[2].
Here is a complete example:
#include<iostream>
using namespace std;
const int numFlowElems = 3, numArrElems = 2;
/** #return a pointer to the first element of a static array
of string[numArrElems]s.
*/
string (*flowFile())[numArrElems]
{ // init so that we see something below.
static string flow[numFlowElems][numArrElems]
= {{"1","2"},
{"3","4"},
{"5","6"}
};
// your function code ...
return flow;
}
int main()
{
// array decays to ptr, like usual. Ptr elems are string[numArrElems].
// ptrToArr is a pointer to arrays of two strings.
string (*ptrToArr)[numArrElems] = flowFile();
for( int flowInd= 0; flowInd<numFlowElems; ++flowInd )
{
for(int strInd = 0; strInd<numArrElems; ++strInd)
{
cout << ptrToArr[flowInd][strInd] << ' ';
}
cout << endl;
}
return 0;
}
How do you parse string (*flowFile())[numArrElems]? I needed two attempts to get the declaration right, if that's any consolation. The key is that in C and C++ (not in C#, mind you!) a declaration has the shape of an expression.
You can do it from the inside to the outside: flowFile() is a function. The result is dereferenced because the function call has higher precedence than the star: *flowFile() is the dereferenced result. Apparently that result is an array of size numArrElems, with elements which are strings.
You can do it outside in: The result of (*flowFile())[numArrElems] is declared as a string. (*flowFile()) is an array of strings with numArrElems elements. Apparently flowFile() must be dereferenced to obtain that array so that flowfile is a function which returns a pointer to an array of numArrElems strings. That's true! It returns the first element of flow, which is exactly an array of strings.
Vectors of vectors might indeed be easier; if you want to retain the semantics you should pass references, as others mentioned: After all, all functions in your original program will operate on the same static array. If you pass vectors by value that will not be the case any longer. But then, that may actually be beneficial.
I have an object which has a 2d char array as a property.
I'd like to create an accessor method which is able to return a pointer to this 2d array.
I have declaired the 2d array like this:
#define PRESET_LEN 15
#define NO_PRESETS 8
char camPresets[NO_PRESETS][PRESET_LEN];
Being new to C++ I'm having a bit of bother trying to fiigure out the method declairation.
So far I have this in the header :
char** getPresetsForCamera(int cam);
and this in the cpp
char** DataManager::getPresetsForCamera(int cam)
{
if(currentCam != cam)
load(cam);
return camPresets;
}
But it does not compile. I obviousely havn't understood how to use pointers properly, at least for 2d arrays, I thought I could just write 'return &camPresets;' to return the address of the array but I'm wrong. Please could someone show me where I'm going wrong. Thanks, Rick.
The correct ugly syntax is :
char (&DataManager::getPresetsForCamera())[NO_PRESETS][PRESET_LEN]
{
if (currentCam != cam)
load(cam);
return camPresets;
}
which may be simplified with a typedef:
typedef char camPresetsType[NO_PRESETS][PRESET_LEN];
camPresetsType& getPresetsForCamera();
But I really suggest to use std::array or custom class.
Here you go:
char* DataManager::getPresetsForCamera(int cam)
{
if(currentCam != cam)
load(cam);
return camPresets[cam];
}
Note that you should also check the bounds of that array before using it. Here's a safer version:
char* DataManager::getPresetsForCamera(unsigned int cam)
{
assert(cam < NO_PRESETS);
if(currentCam != cam)
load(cam);
return camPresets[cam];
}
You can dynamically allocate array for camPresets by declaring it as double pointer and return it in function
See an example
char **camPresets;
char** getPresetsForCamera(int cam);
char** getPresetsForCamera(int cam)
{
//your validation
return camPresets;
}
//Code to dynamically allocate memory
camPresets = (char**)malloc(NO_PRESETS* sizeof(char*));
// for each row allocate Cols ints
for (int row = 0; row < NO_PRESETS; row++) {
camPresets[row] = (char*)malloc(PRESET_LEN* sizeof(char));
}
Well, you need to think that a pointer and array are semantically similar, but they have different syntax.
By defining a 2d array:
char arr[W][H];
you allow the compiler to calculate the location of the element in the original block of data. Remember that the element [0][0] is basically a pointer to the begining of assigned memory block. So for example, if you defined an array and accessed:
char arr[10][20];
char arr[5][5];
You'd tell the compiler to "move 5 rows, and 5 columns from the begining", which would be simply: 5*H+5 = 5*20+5 = 105.
Now, this bracket notation is additional information for the compiler. But as you know, the array is just a block of memory. You may consider to have the same meaning:
&arr[0][0] == arr; // true, arr is "char*"
What this means, is that the pointer notation no longer provides the compiler the widths of array dimensions, and so it cannot use the index operator. The array is considered a simple continuous block of data.
In your case you should simply return a char*. You cannot return an array from the function, but you may assign it to a pointer variable.
char* newArr = fun(); // char* fun() { char* test = new char[10*20]; return test; }
To avoid possible out of range errors, use std::vector instead.
If you are concerned with using std::vector, then use std::array.
#include <array>
#define PRESET_LEN 15
#define NO_PRESETS 8
typedef std::array<char, PRESET_LEN> InnerArray;
typedef std::array<InnerArray, NO_PRESETS> Array2D;
Array2D camPresets;
Array2D getPresetsForCamera(int cam)
{
return camPresets;
}
You have a number of options for returning a 2D array. One is to use a jagged array like are sort of trying to do. If you are truly using char ** as a 2D array, though, you should just stick with using it as a char ** jagged array, and not a 2D array as you are doing and why you see the compiler error.
Another option, if you insist on using true 2D arrays (they are, after all, more efficient than jagged arrays), is to just wrap the array in a struct and return the struct, like this:
struct camPresetsArray
{
char values[NO_PRESETS][PRESET_LEN];
};
camPresetsArray DataManager::getPresetsForCamera(int cam)
{
...
}
Another option is to pass the return value as a function argument.
typedef char camPresetsArray[NO_PRESETS][PRESET_LEN];
void DataManager::getPresetsForCamera(camPresetsArray& outp, int cam)
{
...
}
camPresetsArray x;
myDataManager.getPresetsForCamera(x, y);
Well, in the end after reading through the answers left here, I didn't want to import any libraries into my code so I stayed with a 2d array. I ended up using this code :
typedef char (*pointer_to_arrays)[PRESET_LEN];
pointer_to_arrays getPresetsForCamera(int cam);
then in the cpp
DataManager::pointer_to_arrays DataManager::getPresetsForCamera(int cam)
{
if(currentCam != cam)
load(cam);
return camPresets;
}
Thanks for the pointers :P