I'd like to return a pointer to a char array and then be able to access the data from another function. When searching, I've seen a few places that mentioned returning a pointer however I can't seem to be able to make that work. I'd like to be able to iterate through the returned pointer and possibly copy those values into local variables using memcpy, as seen in this post Splitting a char array by a delimiter and converting to integers and floats - #3 by groundFungus so that I can assign the returned values via a for loop.
This is the output I see from the code at the bottom, what am I doing wrong?
16:55:55.022 -> ***** Start *****
16:55:55.022 ->
16:55:55.022 -> The pieces, separated by strtok()
16:55:55.022 -> 0 12
16:55:55.022 -> 1 14
16:55:55.022 -> 2 16
16:55:55.022 -> 3 4
16:55:55.022 -> 4 14
16:55:55.057 -> 5 22
16:55:55.057 -> The pieces returned from the function
16:55:55.095 -> 23
16:55:55.095 -> 0 W
16:55:55.095 -> 1 W
16:55:55.095 -> 2 W
16:55:55.095 -> 3 W
16:55:55.095 -> 4 W
16:55:55.095 -> 5 W
16:55:55.095 -> 6 W
16:55:55.095 -> 7 W
16:55:55.095 -> 8 W
16:55:55.095 -> 9 W
16:55:55.095 -> 10 W
16:55:55.095 -> 11 W
16:55:55.095 -> 12 W
16:55:55.095 -> 13 W
16:55:55.095 -> 14 W
16:55:55.095 -> 15 W
16:55:55.095 -> 16 W
16:55:55.095 -> 17 W
16:55:55.095 -> 18 W
16:55:55.095 -> 19 W
16:55:55.095 -> 20 W
16:55:55.095 -> 21 W
16:55:55.095 -> 22 �
char *returnArr[20]; // an array of pointers to the pieces of the above array after strtok()
char *ptr = NULL;
char splitByDelimiter(char *array, const char *delim)
{
byte index = 0;
ptr = strtok(array, delim);
while (ptr != NULL)
{
returnArr[index] = ptr;
index++;
ptr = strtok(NULL, delim);
}
Serial.println("The pieces, separated by strtok()");
for (int n = 0; n < index; n++)
{
Serial.print(n); Serial.print(" "); Serial.println(returnArr[n]);
}
return *returnArr;
}
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
char array[] = "12:14:16:4:14:22";
char* returnValue;
returnValue = splitByDelimiter(array, ":");
Serial.println("The pieces returned from the function");
Serial.println(strlen(returnValue));
for (int i = 0; i < strlen(returnValue); i++)
{
Serial.print(i); Serial.print(" "); Serial.println(returnValue[i]);
}
}
void loop()
{
}
Thanks for pointing that out. It was a char pointer, when trying to figure out what was going on I made it a char. It should be char *splitByDelimiter(char *array, const char *delim) which returns the below and exposes another issue. How do I split the value into 6 pointers to read in the original function? So that returnValue[i] (0 through 5) would print each substring of:
12
14
16
4
14
22
Serial.println(strlen(returnValue));
for (int i = 0; i < (strlen(returnValue)); i++)
18:11:59.235 -> ***** Start *****
18:11:59.235 ->
18:11:59.235 -> The pieces, separated by strtok()
18:11:59.235 -> 0 12
18:11:59.235 -> 1 14
18:11:59.235 -> 2 16
18:11:59.235 -> 3 4
18:11:59.235 -> 4 14
18:11:59.235 -> 5 22
18:11:59.235 -> The pieces returned from the function
18:11:59.235 -> 2
18:11:59.235 -> 0 1
18:11:59.235 -> 1 2
I'm not opposed to using a global variable, however I would like to get it working with the pointer so that I learn how to do that and make it a local variable. I made it global trying to figure out why I couldn't get the function to work.
I can't find a syntax combination that works for this. I'm expecting the sizeof to be 6, which it is not and is 2 instead. I'm also expecting for it to be an array of 6 pointers that is separated each time the delimiter is encountered, so
pointer 1 would point to 12
pointer 2 would point to 14
pointer 3 would point to 16
pointer 4 would point to 4
pointer 5 would point to 14
pointer 6 would point to 22
Instead I am seeing the below. I'm not sure if the 6 pointers are there, nor how to iterate through them. Are you willing to modify my code so I can see a working example and not continue to confuse myself with attempts that do not work?
20:34:12.976 -> ***** Start *****
20:34:12.976 ->
20:34:12.976 -> The pieces, separated by strtok()
20:34:12.976 -> 0 12
20:34:12.976 -> 1 14
20:34:12.976 -> 2 16
20:34:12.976 -> 3 4
20:34:12.976 -> 4 14
20:34:12.976 -> 5 22
20:34:12.976 -> The pieces returned from the function
20:34:12.976 -> strlen: 2
20:34:12.976 -> 0 1
20:34:12.976 -> 1 2
char *splitByDelimiter(char *array, const char *delim)
{
byte index = 0;
char *ptr = NULL;
ptr = strtok(array, delim);
static char *returnArr[20]; // an array of pointers to the pieces of the above array after strtok()
while (ptr != NULL)
{
returnArr[index] = ptr;
index++;
ptr = strtok(NULL, delim);
}
Serial.println("The pieces, separated by strtok()");
for (int n = 0; n < index; n++)
{
Serial.print(n); Serial.print(" "); Serial.println(returnArr[n]);
}
return *returnArr;
}
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
char array[] = "12:14:16:4:14:22";
char* returnValue = splitByDelimiter(array, ":");
Serial.println("The pieces returned from the function");
Serial.print("strlen: "); Serial.println(strlen(returnValue));
for (int i = 0; i < (sizeof(returnValue)); i++)
{
Serial.print(i); Serial.print(" "); Serial.println(returnValue[i]);
}
}
void loop()
{
}
In the last iteration I changed the function to char *splitByDelimiter(char *array, const char *delim) which I believe is why I can set char *returnValue = splitByDelimiter(array, ":"); correct?
I followed what you advised let me know how this looks.
char *returnArr[20]; // an array of pointers to the pieces of the above array after strtok()
int returnArrCount = 0;
int maxReturnArrCharArrSize = 0;
void splitByDelimiter(char *array, const char *delim)
{
//byte index = 0;
returnArrCount = 0;
char *ptr = NULL;
ptr = strtok(array, delim);
//static char *returnArr[20]; // an array of pointers to the pieces of the above array after strtok()
while (ptr != NULL)
{
//returnArr[index] = ptr;
//index++;
returnArr[returnArrCount] = ptr;
returnArrCount++;
ptr = strtok(NULL, delim);
}
Serial.println("The pieces, separated by strtok()");
//for (int n = 0; n < index; n++)
for (int n = 0; n < returnArrCount; n++)
{
Serial.print(n); Serial.print(" "); Serial.println(returnArr[n]);
//Serial.println(strlen((char*) returnArr[n]));
int maxReturnArrCharArrSizeTemp = strlen((char*) returnArr[n]);
if (maxReturnArrCharArrSizeTemp > maxReturnArrCharArrSize)
{
maxReturnArrCharArrSize = maxReturnArrCharArrSizeTemp;
Serial.println(maxReturnArrCharArrSize);
}
}
//return *returnArr;
}
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
//char array[] = "12:14:16:4:14:22";
//char* returnValue;
//char *returnValue = splitByDelimiter(array, ":");
char array[] = "12:14:16:4:14:22";
splitByDelimiter(array, ":");
char returnValueArr[returnArrCount][maxReturnArrCharArrSize + 1];
Serial.println("The pieces returned from the function");
for (int i = 0; i < returnArrCount; i++)
{
Serial.print(i); Serial.print(" "); Serial.println(returnArr[i]);
memcpy(returnValueArr[i], returnArr[i], strlen(returnArr[i]) + 1);
}
for (int i = 0; i < returnArrCount; i++)
{
//Serial.print(i); Serial.print(".) "); Serial.println((int)returnValueArr[i]);
Serial.print(i); Serial.print(".) "); Serial.println(returnValueArr[i]);
}
}
void loop()
{
}
Hello, I added returnArrCount into your example in 3 places, else it printed out as shown below. Is that the way you would approach it, or rather a different way?
int returnArrCount = 0;
char **splitByDelimiter(char *array, const char *delim)
{
byte index = 0;
char *ptr = NULL;
ptr = strtok(array, delim);
char **returnArr; // an array of pointers to the pieces of the above array after strtok()
returnArr = (char **)malloc(sizeof(char *)*20);
while (ptr != NULL)
{
returnArr[index] = ptr;
index++;
returnArrCount++;
ptr = strtok(NULL, delim);
}
Serial.println("The pieces, separated by strtok()");
for (int n = 0; n < index; n++)
{
Serial.print(n); Serial.print(" "); Serial.println(returnArr[n]);
}
return returnArr;
}
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
char array[] = "12:14:16:4:14:22";
char** returnValue = splitByDelimiter(array, ":");
Serial.println("The pieces returned from the function");
//Serial.print("strlen: "); Serial.println(strlen(returnValue));
for (int i = 0; i < returnArrCount; i++)
{
Serial.print(i); Serial.print(" "); Serial.println(returnValue[i]);
}
free(returnValue);
}
void loop()
{
}
no, it's a bit crazy..
dynamic memory allocations is not a good path for smaller mcu's..
using a fixed global buffer would be better..
really thinking you should be allocating each pointer and strcpy the data into..
it all gets confusingly complicated when it need not be..
just my 2 pennies..
i'm crazy.. ~q
or "ref" or "out" (I'm not sure of the syntax, but I believe I have seen this in C# with PinInvoke unsafe/unmanaged code examples) and then define it in the function such as
so that I could do the memcpy in the function after I've established the int values of the 2d array inside of the function, and pass by reference the out variable or whatever the correct terminology would be for it?
And call it something like this?
char array[] = "12:14:16:4:14:22";
char returnValueArr[1][1]; // I used 1 arbitrarily to instantiate the 2d array, I don't know if that's correct
splitByDelimiter(array, ":", returnValueArr);
If that doesn't make sense, the psuedo code would be to pass the char array[], the delimiter and an already instantiated ref/out variable into the splitByDelimiter function, have the function split the character array by the delimiter and then reinstantiate the ref/out variable to the correct column count and row count, based on counting code in the splitByDelimiter function and finally memcpy the delimited values into the ref/out variable for the calling function to use?
Parent function passes char array[], delimiter and ref/out variable to child function named splitByDelimiter
Child function splits values into a local 2d char array variable
Child function counts number of rows and max columns in 2d array
Child function redefines/reinstantiates ref/out variable to have the correct number of rows and columns for the 2d array based on counts
Child function memcpy's each value set into the ref/out variable and now parent function has a copy of the parsed data inside of its local variable
did you try char **returnValueArr??
it's not marked constant like delim so you should be able to modify it, you will not be able to determine size inside function need to know or pass size in too..
The memcpy portion doesn't appear to be working. Here is the code and the serial output. I'm not sure where those strange characters are coming from under maxReturnArrCharArrSize either?
was going to say, doesn't compile extra ) in the memcpy but I see you noticed that already..
I'd make the returnValueArr global and not pass it at all..
something like this..
char *returnArr[20]; // an array of pointers to the pieces of the above array after strtok()
char returnValueArr[20][4];
int returnArrCount = 0;
int maxReturnArrCharArrSize = 0;
void splitByDelimiter(char *array, const char *delim)
{
//byte index = 0;
returnArrCount = 0;
char *ptr = NULL;
ptr = strtok(array, delim);
while (ptr != NULL)
{
returnArr[returnArrCount] = ptr;
returnArrCount++;
ptr = strtok(NULL, delim);
}
Serial.println("The pieces, separated by strtok()");
for (int n = 0; n < returnArrCount; n++)
{
Serial.print(n); Serial.print(" "); Serial.println(returnArr[n]);
int maxReturnArrCharArrSizeTemp = strlen((char*) returnArr[n]);
if (maxReturnArrCharArrSizeTemp > maxReturnArrCharArrSize)
{
maxReturnArrCharArrSize = maxReturnArrCharArrSizeTemp;
}
}
Serial.print("returnArrCount: "); Serial.println(returnArrCount);
Serial.print("maxReturnArrCharArrSize + 1: "); Serial.println(maxReturnArrCharArrSize + 1);
returnValueArr[returnArrCount][maxReturnArrCharArrSize + 1];
for (int i = 0; i < returnArrCount; i++)
{
Serial.print(i); Serial.print(" "); Serial.print(returnArr[i]); Serial.println(" memcpy");
memcpy(returnValueArr[i], returnArr[i], strlen(returnArr[i]) + 1);
}
}
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
char array[] = "12:14:16:4:14:22";
splitByDelimiter(array, ":");
Serial.println("The pieces returned from the function");
for (int i = 0; i < returnArrCount; i++)
{
Serial.print(i); Serial.print(".) "); Serial.println(returnValueArr[i]);
}
}
void loop()
{
}
That line is supposed to reinstantiate returnValueArr with the integer values that are now defined with the function code that has ran above it. It may not work that way, but that's what I was after.
This step of my psuedo code
4. Child function redefines/reinstantiates ref/out variable to have the correct number of rows and columns for the 2d array based on counts
With this version, am I still able to have the below scenario? I believe it would overwrite the returnValueArr and I would only have the last set of data to work with, is that correct?
void setup()
{
Serial.begin(38400);
Serial.println("");
Serial.println(" ***** Start ***** ");
Serial.println("");
char array[] = "12:14:16:4:14:22";
splitByDelimiter(array, ":");
Serial.println("The pieces returned from the function");
for (int i = 0; i < returnArrCount; i++)
{
Serial.print(i); Serial.print(".) "); Serial.println(returnValueArr[i]);
}
char array[] = "11:21:10:6:11:20";
splitByDelimiter(array, ":");
char array[] = "8:24:08:5:06:05";
splitByDelimiter(array, ":");
// code to do something now with all 3 delimited values
}
I'm fine with starting from scratch because I feel like I am banging my head on my desk lol, can we start with my psuedo code?
I'd like to pass a variable name into a function (I think this is called indirection?) as one of the parameters. The other 2 parameters are the char array that needs split by a delimiter and the delimiter itself.
I'd like the called function splitByDelimiter to split the char array and then memcpy the split value 2d char array into the variable name that was passed as a parameter, all within the called function. That way the calling function can repeatedly use the splitByDelimiter function with 2 lines of code and it is resuable infinitely, the indirection variable name instantiation and the call to the splitByDelimiter function itself and I can use those 2 lines 10 times within the same calling function if I want, without a global return value variable being overwritten. I hope that makes sense.
Parent function passes char array[], delimiter and ref/out variable to child function named splitByDelimiter
Child function splits values into a local 2d char array variable
Child function counts number of rows and max columns in 2d array
Child function redefines/reinstantiates ref/out variable to have the correct number of rows and columns for the 2d array based on counts
Child function memcpy's each value set into the ref/out variable and now parent function has a copy of the parsed data inside of its local variable
Is there any way to not have to hard code the 6 in this line? char* returnPointers[6] = {NULL};
I think I could write a separate function to do so, is there an elegant way or a way for it not to be defined until it is inside of the called function?