2

I have an Arduino that controls timers. The settings for timers are stored in byte arrays. I need to convert the arrays to strings to SET a string on an external Redis server.

So, I have many arrays of bytes of different lengths that I need to convert to strings to pass as arguments to a function expecting char[]. I need the values to be separated by commas and terminated with '\0'.

byte timer[4] {1,5,23,120};
byte timer2[6] {0,0,0,0,0,0}

I have succeeded to do it manually for each array using sprintf() like this

char buf[30];
for (int i=0;i<5;i++){ buf[i] = (int) timer[i];  }
   sprintf(buf, "%d,%d,%d,%d,%d",timer[0],timer[1],timer[2],timer[3],timer[4]);

That gives me an output string buf: 1,5,23,120 But I have to use a fixed number of 'placeholders' in sprintf().

I would like to come up with a function to which I could pass the name of the array (e.g. timer[]) and that would build a string, probably using a for loop of 'variable lengths' (depending of the particular array to to 'process') and many strcat() functions. I have tried a few ways to do this, none of them making sense to the compiler, nor to me!

Which way should I go looking?

gre_gor
  • 6,669
  • 9
  • 47
  • 52
zedragon
  • 39
  • 6
  • 2
    `timer[4]` is out of bounds. – Jean-François Fabre Jan 17 '18 at 22:03
  • Possible duplicate of [How to pass variable number of arguments to printf/sprintf](https://stackoverflow.com/questions/1056411/how-to-pass-variable-number-of-arguments-to-printf-sprintf) – frslm Jan 17 '18 at 22:03
  • sprintf returns character count. You can move the pointer to buf accordingly and do the next value and so on. As long as you make sure the buffer is large enough. And add commas manually before second etc – Sami Kuhmonen Jan 17 '18 at 22:08
  • 1
    the arduino language is C++ – M.M Jan 17 '18 at 22:51
  • The question is tagged `c++`, but the code (and answers) are all in `c` instead. A `c++` solution would be to use a `std::ostringstream` to format the bytes in a loop. – Remy Lebeau Jan 18 '18 at 04:26

2 Answers2

3

Here is the low tech way you could do it in normal C.

char* toString(byte* bytes, int nbytes)
{
    // Has to be static so it doesn't go out of scope at the end of the call.
    // You could dynamically allocate memory based on nbytes.
    // Size of 128 is arbitrary - pick something you know is big enough.
    static char buffer[128];
    char*       bp = buffer;
    *bp = 0;  // means return will be valid even if nbytes is 0.
    for(int i = 0; i < nbytes; i++)
    {
        if (i > 0) {
            *bp = ','; bp++;
        }
        // sprintf can have errors, so probably want to check for a +ve
        // result.
        bp += sprintf(bp, "%d", bytes[i])
    }
    return buffer;
} 
John3136
  • 28,809
  • 4
  • 51
  • 69
  • Nice - avoiding `strcat()` which re-walks the string. I also like to handle case when `nbytes == 0`, so recommend `char* bp = buffer; *bp = '\0';` – chux - Reinstate Monica Jan 17 '18 at 22:32
  • @chux Perfect example of how bugs creep in. All looks good, comments mention getting the size right etc, but if you passes `nbytes = 0` the first time through **boom**. I guess the other obvious fix (left as an exercise to the reader) is null pointer check on the params. – John3136 Jan 17 '18 at 22:40
1

an implementation, assuming that timer is an array (else, size would have to be passed as a parameter) with the special handling of the comma.

Basically, print the integer in a temp buffer, then concatenate to the final buffer. Pepper with commas where needed.

The size of the output buffer isn't tested, mind.

#include <stdio.h>
#include <strings.h>

typedef unsigned char byte;

int main()
{
   byte timer[4] = {1,5,23,120};
   int i;

   char buf[30] = "";
   int first_item = 1;

   for (i=0;i<sizeof(timer)/sizeof(timer[0]);i++)
   {
      char t[10];
      if (!first_item)
      {
         strcat(buf,",");   
      }
      first_item = 0;

      sprintf(t,"%d",timer[i]);
      strcat(buf,t);
    }

   printf(buf);

}
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219