Return bidimensional array

Hello everyone, I have a problem with two-dimensional arrays.

i have this function:

String allLoco()
{
  File locoFile = SD.open("loco.txt");
  String allMyLoco[numLoco][3];
  
  ............
  
  return allMyLoco;
}

The error is this: LocoDatabase.h:64: error: conversion from 'String (*)[3]' to non-scalar type 'String' requested

how can I fix it?

TNK

you better pass a pointer/reference to the read function which fills the String[][] from disk.

Now the 2dim array is a local var in the function which will be overwritten when the next function is called google for scope in C / C++ for the details

Thanks for the reply. My purpose is read a CSV file. the problem is that the length of the array may vary (may vary the number of rows in the CSV).

There is no way to pass an array initialized inside a function?

zampi91: There is no way to pass an array initialized inside a function?

You can declare an array as static within the function and pass it. Example:

char* foo() {
  static char myArray[10];
  // Do something with myArray
  return myArray;
}

...but that is because using static is functionally the same as declaring it global. Example:

char myArray[10];

void foo() {
  // do stuff with myArray
}

Using static just helps with scope so that you can only modify it within that function.

There is no way to pass an array initialized inside a function?

If you mean "Is there no way to return an array CREATED inside a function", then the answer is no, if the array is statically defined.

However, in your case, the size of the array must be known in advance of the call, since it is used as soon as the function starts, to create the array.

The 2D array of strings is going to kill you, anyway. A 2D array of strings (or 3D array of chars) would be a lot smaller.

You need to tell us more about how many rows in the table, and if there are 3 values per row (as appears from your declaration). If you are not using a Mega, you have less than 1500 bytes of SRAM in which to hold you 2D array of Strings or strings.

For simplicity in situations like this I usually make myself a struct so I'm not messing with multidimentional arrays:

struct csv_struct {
  String foo;
  String bar;
  String meep;
};

struct csv_struct myArray[50];

Then you can access the data as

myArray[4].foo

or

myArray[43].bar

Thank you all for your help ...

PaulS: If you mean "Is there no way to return an array CREATED inside a function", then the answer is no, if the array is statically defined.

I'd say that strictly speaking that 'no' should be 'not without exploiting non-intuitive quirks of the language'; it's best not to get into those situations in the first place but technically it is possible to return a local array if it is returned within a struct.

Dynamic resizing of arrays is something which is tricky even on a full-blown PC with a proper memory management layer.

On a small microcontroller with limited RAM and no real memory management it's just not really practical.

You're much better off dealing with the CSV file in chunks - be that in single lines, or blocks of a specific size.

Personally I'd write a function which opens the file and returns a "handle" to it, plus another function which returns successive lines. A third function which allows you to "seek" to a specific line is also useful, but not essential.

Finally, a "close" function to clean it all up and release any memory allocated is a must.

That way, instead of dealing with messy multi-dimentional arrays, you're just dealing with simple function calls. Something like:

int myFile = csv_open("myfile.csv");
while(csv_getline(myFile,(struct myStruct *)&data))
{
  doSomethingWithData(data.xcoord,data.ycoord);
  doSomethingElse(data.name,data.speed);
}
csv_close(myFile);

as an example - of course, there is 9,000,000,000 more lines of code to be written in the csv_* functions etc ;)

Hello!

Did anyone solve this without using struct?

Like in how can I give a 2D array to a function which then returns a (changed) 2D array as a return value?

Thank you very much!

Ronwl

Like in how can I give a 2D array to a function which then returns a (changed) 2D array as a return value?

A function can not return an array. A function can return a single value. That single value need not be a simple type. It can be a pointer, a class instance, or a struct. But, it can not be an array.

A function CAN take two arguments that are arrays and read from one and write to the other.

What have you tried? What were the results?

The concept of returning an array implies that you have enough memory space for at least 2 copies of the array. On an Arduino that is unlikely and creating a single global array may make more sense as well as simplifying the programming.

…R

Ronwl:
Did anyone solve this without using struct?
Like in how can I give a 2D array to a function which then returns a (changed) 2D array as a return value?

I’m sure many people are curious how to do this, so if you are willing to go through some details, I can show you how.

First off, lets cover a few points.

A function can not return an array. A function can return a single value. That single value need not be a simple type. It can be a pointer, a class instance, or a struct. But, it can not be an array.

This is a way to sum it up, however its not quite right.

A function by definition can return any complete type. An array is a type, so why can’t we return one?..

typedef int arr_t[ 10 ];
arr_t allLoco();

This results in: “error: ‘allLoco’ declared as function returning an array

What is happening here is the array type arr_t is being returned “by value”, similar to int allLoco();. And the standard forbids array assignments. This is no different to passing arrays to functions, they cannot be passed by value.

So how is it fixed: Use a reference or pointer.

To declare allLoco() as a “function returning a reference to a two dimensional array of Strings” the syntax becomes a little strange.

However this is how to return a static array from a function, without using a struct.

String (&allLoco())[ numLoco ][ 3 ]{
  static String localVar[ numLoco ][ 3 ] = { { "StrA", "StrB", "StrC" }, {}, {} };
  return localVar;
}

If you want pass the array to the function then return it, the declaration looks like this:

String (&allLoco(String (&param)[numLoco][3]))[numLoco][3]{
  return param;
}

You can use the returned reference:

  allLoco()[ 0 ][ 1 ] = 1;

  //...
  String allMyLoco[numLoco][3];
  allLoco( allMyLoco )[ 0 ][ 1 ] = 2;

You can reference the result somewhere else:

String (&ref)[numLoco][3] = allLoco();

You can also use the result with sizeof to make more flexible code ( this example uses the reference declared above ):

#define ARRAY_SIZE( x ) ( sizeof( x ) / sizeof( x[ 0 ] ) )

  for( int inner = 0 ; inner < ARRAY_SIZE( ref ) ; ++inner ){  
    for( int outer = 0 ; outer < ARRAY_SIZE( ref[ inner ] ) ; ++outer ){
      Serial.println( ref[ inner ][ outer ] );
    }
  }

And as it is a real array, not a decayed pointer, you can use it in C++11 for each statements:

  for( auto &inner : allLoco() ){
    for( auto &outer : inner ){
      Serial.println( outer );
    }
  }

Hope you learn something. BTW there is more to this solution for the Arduino environment. If someone encounters the error referring to ‘atexit’ I can show you how to fix it.