using DynamicArayHelper

Hi,
I searched a solution to read string into a dynamic array and I found "DynamicArrayHelper" for easier malloc-usage in the playground.
http://www.arduino.cc/playground/Code/DynamicArrayHelper

But I have to admit that I neither understand its usage nor understand the usage of the string-converter atoi().
Could anyone possibly help?

This is the code of what I wanted to do. Nothing works here...

#include <DynamicArrayHelper.h>
// #include <wiring.h>

struct sColor
{
  unsigned int  *& steps_value;
  int              cnt_steps;
};
typedef struct sColor tColor;


DynamicArrayHelper DAH;

tColor colors[3];
String input[3] = {"101 102 103 104 105 106 # #",
                  "201 202 203 204 # #",
                  "301 302 303 304 305 306 307 # #"};
                  
int nextSpace(String str, int actPos)
{
  int pos = actPos;
  while (str.substring(pos,pos+1) != " ") {pos++;};
  return pos;
}
                  
void read_array()
{
  for (byte col = 0; col < 3; col++)
  {
    int index = 0;
    int startpos = 0;
    int value;
    
    int nxtSpace = nextSpace(input[col],startpos);      
    String item = input[col].substring(startpos, nxtSpace);
    while (item != "#")
    {      
      value = atoi(item);
      DAH.SetElementInArray((void *&)colors[col].steps_value, &value, index, 1, sizeof(int));
      index++;      
      startpos = nxtSpace + 1;
      nxtSpace = nextSpace(input[col],startpos);      
      item = input[col].substring(startpos; findSpace(input[col],index));
    }
    colors[col].cnt_steps = index;
  }
}


void setup()
{
  Serial.begin(9600);  
  read_array();
  Serial.println(colors[2].steps_value[2]); // 303
}

void loop()
{
}

Nothing works here...

I'm sure some stuff works. Perhaps not the way you expect, or the parts you want. You need to tell us what you expect to have happen, what actually happens, and how that differs from what you expected. Then, we can help you make the code match your expectations.

Or, you can learn to debug the code yourself. You are opening a connection to the serial port, with the Serial.begin() statement. Open the Serial Monitor from the IDE. That forms the other end of the serial port connection. You can now see what the program is doing. Still not enough? Add more Serial.print() and Serial.println() statements, at various points in the code.

Print out the value of nxtSpace in read_array(). The function steps through the array of strings, processing one string at a time. It looks for the next space in the string, and creates a substring up to that space. The first value of nxtSpace should be 3 and the first substring (in item) should be "101". Print out the value in item.

It keeps extracting substrings until it encounters a substring of "#".

      item = input[col].substring(startpos; findSpace(input[col],index));

This does not look right. That first ; should be a comma.

But I have to admit that I neither understand its usage nor understand the usage of the string-converter atoi().

The function SetElementInArray dynamically allocates space for a value, storing a pointer to that space in the array that is the first argument. The value to store in that space is in the second argument. In this case, it is the value of the substring converted to an int ("101" --> 101). The location in the array is defined by the third argument, and the final two arguments define the number of values to allocate space for (1) and the number of bytes in each value (sizeof(int)).

The atoi() function expects a NULL terminated array of characters, and converts the characters in that array to a number, presuming the array of characters represents a number ("123" rather than "Bob" or "Two").

Your code is not calling atoi() correctly, since atoi() expects a string (note the lower case s, which is the general term for a NULL terminated array of characters), and you are passing it a String (note the upper case S).

You can extract the NULL terminated array of characters (the string) from the String, using the String function toCharArray(). I'll leave it to you to figure out how.

Hi,
Thanks for the atoi-hint. I wrote some new code, but I cant try/debug it, because I still do not get it past the compiler.

The problem is the SetElementInArray-line. Here the compiler sais no matching function for call to 'DynamicArrayHelper::SetElementInArray(void*&, int*, int&, int, unsigned int)'. Most likely some of the parameters have the wrong type, but I dont know how to correct that

The function SetElementInArray dynamically allocates space for a value, storing a pointer to that space in the array that is the first argument. The value to store in that space is in the second argument. In this case, it is the value of the substring converted to an int ("101" --> 101). The location in the array is defined by the third argument, and the final two arguments define the number of values to allocate space for (1) and the number of bytes in each value (sizeof(int)).

okay - that is like I understood it, but I still do not know what I did wrong.
It must have something to do with the right pointer-usage, because this is something really confusing for me. I still do not get the difference between int* var and int *var and I do not know what *& could mean - or even (void *&) - I copied that from the documentation...

OK. Looking back at the page you first linked to, the arguments are:

  • the array to add the objects to ((void *)colors[col].steps_value)
  • the object(s) to add to the array (&value)
  • where to add the element (index)
  • the numbers of elements in the existing array (index, too)
  • the size of the element to add to the array (sizeof(int)).

Since you are always adding at the end, use the same variable for the position to add and the length of the array. When the function ends, index will have been updated to reflect the new size of the array, so you shouldn't increment it again.

Pretty crappy documentation, if you ask me. Names should reflect their purpose. The name elements is used to define how many elements are in the existing array. I'd normally use size or count in the name of an argument that contained a count.

I still do not get the difference between int* var and int *var

Perhaps because there is none. Some people like to put the * next to the type, to make it clear that the variable being defined is a pointer. The problem with this approach is that:

int* a, b;

is perfectly valid, and defines a as a pointer to int and b as an int.

Other people, like me, like to point the * next to the variable, so when you see the name, you know it is a pointer to something. Then, seeing:

int *a, b;

you'd know that a was a pointer and b was not (no *). The pointer to what is not as obvious, especially in a long string of variables.

I do not know what *& could mean - or even (void *&)

The *& means that the variable is a reference for a pointer, of type void in this case. Variables in C are passed by value, meaning that a copy of the value is made, and passed to the function. The function can then only manipulate the copy.

Using the reference operator, the value is passed by reference (that is, the address where the data lives is passed, not the data). This way, the function can manipulate the value that the caller knows about, not just the copy it knows about.

Normally, pointers don't have to be passed by reference, since it is the values in that array that are to be manipulated. In this case, though, even WHERE the array is needs to be changeable by the function, so the need to pass the address of the pointer, not the address that the pointer points to.

Thanks for the explanation. All clear to me now except why the array is of void-type. I always thought, that void would not give any information by itself...

the numbers of elements in the existing array (index, too)

okay - thought this would be the numbers of elements to add. changed it to index.

But the compiler still gives the same error: 'no matching function for call to 'DynamicArrayHelper::SetElementInArray(void*&, int*, int&, int, unsigned int)'

For the objects: Should it be &value or value?

All clear to me now except why the array is of void-type. I always thought, that void would not give any information by itself...

That depends on whether the type is the type of a variable or the type of a function.

In the declaration of a function that can operate on arrays of any type (you might want to add an element to an array of floats or chars or ints or bytes or structs), the type void is used. That's why you have to use the (void *) in front of your array's name - to cast your array that is not a void type to the first type for the function to accept.

As for the rest of the questions, it's time to post the modified code.

#include <DynamicArrayHelper.h>

struct sColor
{
  unsigned int  *& steps_value;
  int                   cnt_steps;
};
typedef struct sColor tColor;


DynamicArrayHelper DAH;

tColor colors[3];
String input[3] = {"101 102 103 104 105 106 # #",
                  "201 202 203 204 # #",
                  "301 302 303 304 305 306 307 # #"};
                  
int nextSpace(String str, int actPos)
{
  int pos = actPos;
  while (str.substring(pos,pos+1) != " ") {pos++;};
  return pos;
}

int Str2int (String Str_value)
{
  char buffer[5];
  Str_value.toCharArray(buffer, 5);
  int int_value = atoi(buffer)
  return int_value;
}

void read_array()
{
  for (byte col = 0; col < 3; col++)
  {
    int index = 0;
    int startpos = 0;
    int value;
    
    int nxtSpace = nextSpace(input[col],startpos);      
    String item = input[col].substring(startpos, nxtSpace);
    while (item != "#")
    {      
      value = Str2int(item);
      DAH.SetElementInArray((void *&)colors[col].steps_value, &value, index, 1, sizeof(int));
      index++;      
      startpos = nxtSpace + 1;
      nxtSpace = nextSpace(input[col],startpos);      
      item = input[col].substring(startpos; findSpace(input[col],index));
    }
    colors[col].cnt_steps = index;
  }
}


void setup()
{
  Serial.begin(9600);  
  read_array();
  Serial.println(colors[2].steps_value[2]); // 303
}

void loop()
{
}
      DAH.SetElementInArray((void *&)colors[col].steps_value, &value, index, 1, sizeof(int));

Two (or more) problems here. In the call to the function, you don't need (and can't have) the & in the cast. The compiler knows that the function needs the value as a reference.

The 4th argument is an input/output argument. It is where the function tells you the new size of the array. You can't use a constant as an output argument.

      DAH.SetElementInArray((void *)colors[col].steps_value, &value, index, index, sizeof(int));

stands a better chance of working.

you don't need (and can't have) the & in the cast

copied that from the documentation without knowing better...

The 4th argument is an input/output argument.

changed that already, but on a PC without internet, so I missed it in the posted code.

My line now is exactly

DAH.SetElementInArray((void *)colors[col].steps_value, value, index, index, sizeof(int));

but the error is still the same.

In the detailed error-message there is some error with .../avr/include/math.h:439 error: expected unqualified-id before 'double'
Does that help in any way?

I fixed a few errors (that I pointed out earlier) and changed the type of index to byte. This now compiles. Whether it does what you want, or not, I don't know.

#include "DynamicArrayHelper.h"

struct sColor
{
  unsigned int  *& steps_value;
  int                   cnt_steps;
};
typedef struct sColor tColor;


DynamicArrayHelper DAH;

tColor colors[3];
String input[3] = {"101 102 103 104 105 106 # #",
                  "201 202 203 204 # #",
                  "301 302 303 304 305 306 307 # #"};
                  
int nextSpace(String str, int actPos)
{
  int pos = actPos;
  while (str.substring(pos,pos+1) != " ") {pos++;};
  return pos;
}

int Str2int (String Str_value)
{
  char buffer[5];
  Str_value.toCharArray(buffer, 5);
  int int_value = atoi(buffer);
  return int_value;
}

void read_array()
{
  for (byte col = 0; col < 3; col++)
  {
    byte index = 0;
    byte startpos = 0;
    int value;
    
    int nxtSpace = nextSpace(input[col],startpos);      
    String item = input[col].substring(startpos, nxtSpace);
    while (item != "#")
    {      
      value = Str2int(item);
      DAH.SetElementInArray((void *&)colors[col].steps_value, (void *)&value, index, index, (byte)sizeof(int));
      index++;      
      startpos = nxtSpace + 1;
      nxtSpace = nextSpace(input[col],startpos);      
      item = input[col].substring(startpos, nextSpace(input[col],index));
    }
    colors[col].cnt_steps = index;
  }
}

void setup()
{
  Serial.begin(9600);  
  read_array();
  Serial.println(colors[2].steps_value[2]); // 303
}

void loop()
{
}

thanks a lot. I will play a little.

Trying to play, but got an error.

The arduino restarts in the second loop.?

#include "DynamicArrayHelper.h"

struct sColor
{
  unsigned int  *& steps_value;
  int                   cnt_steps;
};
typedef struct sColor tColor;


DynamicArrayHelper DAH;

tColor colors[3];
String input[3] = {"101 102 103 104 105 106 # #",
                  "201 202 203 204 # #",
                  "301 302 303 304 305 306 307 # #"};
                  
int nextSpace(String str, int actPos)
{
  int pos = actPos+1;
  while (str.substring(pos,pos+1) != " ") {pos++;};
  return pos;
}

int Str2int (String Str_value)
{
  char buffer[5];
  Str_value.toCharArray(buffer, 5);
  int int_value = atoi(buffer);
  return int_value;
}

void read_array()
{
  for (byte col = 0; col < 3; col++)
  {
    byte index = 0;
    int startpos = 0;
    int value;
    
    int nxtSpace = nextSpace(input[col],startpos);      
    String item = input[col].substring(startpos, nxtSpace);
    Serial.println("FOR");
    while (item != "#")
    {      
      Serial.print("# <");
      Serial.print(item);
      Serial.println(">");
      value = Str2int(item);
//      Serial.println(value);
      DAH.SetElementInArray((void *&)colors[col].steps_value, (void *)&value, index, index, (byte)sizeof(int));
      index++;      
      
      startpos = nxtSpace + 1;
      nxtSpace = nextSpace(input[col],startpos);
      Serial.print(startpos);
      Serial.print(" / ");
      Serial.println(nxtSpace);
      item = input[col].substring(startpos, nxtSpace); //this line causes the trouble
      Serial.println(item); //this would not be displayed anymore
    }
    Serial.println("/FOR");
    colors[col].cnt_steps = index;
  }
}

void setup()
{
  Serial.begin(9600);  
  Serial.println("-------------------");
  delay(2000);
  Serial.println("starting");
  read_array();
  Serial.println(colors[2].steps_value[2]); // 303
}

void loop()
{
}