1

I would like to pass a character array micPointsChar[] to a function initMicPoints() and parse it into a multi-dimensional array micPoints. I am able to successfully do this using a one dimensional array:

char micPointsChar[30 + 1] = {};
float *initMicPoints(char micPointsChar[], float micPoints[3]);

int main()
{
  // Read in mic points from file
    char micPointsChar[40] = "2,3.343,4.432\n";
    float micPoints[3] = {};
    float *newMicPoints = initMicPoints(micPointsChar, micPoints);
    for (int i = 1; i <= 3; i++)
    {
      Serial.print(newMicPoints[i]);
      Serial.print("\n");
    }
    return 0;
}


float *initMicPoints(char micPointsChar[], float micPoints[3])
{
  static int i = 1;
  static int micNum = 1;
  static int numMics = 1;
  float coordinateDec = 0;

  char *coordinate = strtok(micPointsChar, ",\n");
  coordinateDec = atof(coordinate);
  while (micNum <= numMics)
  {
    while (i <= ((micNum * 3)) && (coordinate != NULL))
    {
      if (i == ((micNum * 3) - 2))
      {
        micPoints[1] = coordinateDec;
      }
      else if (i == ((micNum * 3) - 1))
      {
        micPoints[2] = coordinateDec;
      }
      else if (i == ((micNum * 3) - 0))
      {
        micPoints[3] = coordinateDec;
      }
      coordinate = strtok(NULL, ",\n");
      coordinateDec = atof(coordinate);
      i++;
    }
    micNum++;
  }
  return micPoints;
}

This outputs the expected:

2.00
3.34
4.43

However, when I change my code to handle a multidimensional array, micPoints[360][3]:

char micPointsChar[30 + 1] = {};
float *initMicPoints(char micPointsChar[], float micPoints[360][3]);

int main()
{
  // Read in mic points from file
    char micPointsChar[40] = "2,3.343,4.432\n";
    float micPoints[360][3] = {};
    float *newMicPoints = initMicPoints(micPointsChar, micPoints);
    static int i = 0;
    for (i = 1; i <= 3; i++)
    {
      Serial.print(*newMicPoints[i][0]);
      Serial.print("\n");
      Serial.print(*newMicPoints[i][1]);
      Serial.print("\n");
      Serial.print(*newMicPoints[i][2]);
      Serial.print("\n");
    }
    return 0;
}


float *initMicPoints(char micPointsChar[], float micPoints[360][3])
{
  static int i = 1;
  static int micNum = 1;
  static int numMics = 1;
  float coordinateDec = 0;

  char *coordinate = strtok(micPointsChar, ",\n");
  coordinateDec = atof(coordinate);
  while (micNum <= numMics)
  {
    while (i <= ((micNum * 3)) && (coordinate != NULL))
    {
      if (i == ((micNum * 3) - 2))
      {
        micPoints[i][0] = coordinateDec;
      }
      else if (i == ((micNum * 3) - 1))
      {
        micPoints[i][1] = coordinateDec;
      }
      else if (i == ((micNum * 3) - 0))
      {
        micPoints[i][2] = coordinateDec;
      }
      coordinate = strtok(NULL, ",\n");
      coordinateDec = atof(coordinate);
      i++;
    }
    micNum++;
  }
  return micPoints;
}

I receive a compile time error of:

cannot convert 'float (*)[3]' to 'float*' in return

Am I making this too complicated? What is the best way to return a multidimensional array?

sccrthlt
  • 2,544
  • 4
  • 16
  • 23
  • 3
    Possible duplicate of [conversion of 2D array to pointer-to-pointer](http://stackoverflow.com/questions/8203700/conversion-of-2d-array-to-pointer-to-pointer) – LogicStuff Dec 17 '15 at 22:12
  • Not a duplicate of that, there's no call for a pointer-to-pointer here – M.M Dec 18 '15 at 00:40
  • Multidimensional array syntax is evil. Just calculate the offset yourself. `offset = y * width + height`, `offset = z * (width * height) + y * width + x`, etc. – 3Dave Dec 18 '15 at 00:43

3 Answers3

2

Firstly, unfortunately

float *initMicPoints(char micPointsChar[], float micPoints[360][3])

is seen as

float *initMicPoints(char* micPointsChar, float (*micPoints)[3])

you may pass by reference to keep the size:

float *initMicPoints(char* micPointsChar, float (&micPoints)[360][3])

Then as you return micPoints

return type should be float (&)[360][3] or float (&)[360][3]

which give an ugly

float (&initMicPoints(char* micPointsChar, float (&micPoints)[360][3]))[360][3]

and at the call site:

float (&newMicPoints)[360][3] = initMicPoints(micPointsChar, micPoints);

Prefer std::array or std::vector with cleaner syntax.

Jarod42
  • 173,454
  • 13
  • 146
  • 250
0

In both cases you are just returning the parameter. So this return value is redundant. Instead, avoid the problem by returning void:

void initMicPoints(char micPointsChar[], float micPoints[360][3])

The calling code would look like:

float micPoints[360][3] = {};
initMicPoints(micPointsChar, micPoints);
for (int i = 1; i <= 3; i++)
{
  Serial.print(micPoints[i][0]);
  Serial.print("\n");

etc. You could make another variable float (*newMicPoints)[3] = micPoints; if you want but this would also be redundant.

M.M
  • 130,300
  • 18
  • 171
  • 314
0

There is little point in returning the array, because your function hasn't constructed it. You're just giving the caller a copy of the argument value.

A few traditional functions in the standard C library do this, like strcpy. I can't remember the last time I saw a piece of code which used the return value of strcpy, which is just the destination pointer that was passed in.

// redeclare and redefine to return nothing!
void initMicPoints(char micPointsChar[], float micPoints[3]);

int main()
{
  // Read in mic points from file
    char micPointsChar[40] = "2,3.343,4.432\n";
    float micPoints[3] = {};

    initMicPoints(micPointsChar, micPoints);
    for (int i = 1; i <= 3; i++)
    {
      Serial.print(micPoints[i]); // refer to original array, now initialized
      Serial.print("\n");
    }
    return 0;
}

Fact is that initMicPoints clobbers the array that is passed in, which is why you called it init. There is little use in capturing a pointer, and then ignoring the original array that you have in scope. That just dresses up imperative code to look functional, without the underlying semantics.

In the above code we can turn the array two dimensional, without the return value type issue cropping up; we eliminated it.

Kaz
  • 48,579
  • 8
  • 85
  • 132