Storing an array pointer in an array!

I understand how to pass an array to a function, the following code shows how:

String test1[10];
String test2[10];

void setup() {
  // put your setup code here, to run once:
 test1[0]="1";
 test1[1]="2";
 test1[2]="3";
 test2[0]="one";
 test2[1]="two";
 test2[2]="three";
 Serial.begin(115200);
  
}

void loop() {
  // put your main code here, to run repeatedly: 
  
  testpassarray(test1);
  testpassarray(test2);
  
  
}

void testpassarray(String *elements){
 
 Serial.println(elements[0]);
 Serial.println(elements[1]);
 Serial.println(elements[2]); 
  
}

What I need to do is STORE the pointer in an array so:

(I know the program is pointless but I need to understand the concept!

String test1[10];
String test2[10];
unsigned long int stored[100];
int numarrays=0;

void setup() {
  // put your setup code here, to run once:
 test1[0]="1";
 test1[1]="2";
 test1[2]="3";
 test2[0]="one";
 test2[1]="two";
 test2[2]="three";
 Serial.begin(115200);
  
}

void loop() {
  // put your main code here, to run repeatedly: 
  
  testpassarray(test1);
  testpassarray(test2);
  
  
}

void testpassarray(String *elements){
  
 stored[numarrays]=elements;
 numarrays+=1;
 
 Serial.println(elements[0]);
 Serial.println(elements[1]);
 Serial.println(elements[2]); 
  
}

The code does not work. I'm not at all new to programming just haven't got a big history of this language!

Also how can I tell how many elements inside the passed array?

Is the type "uint16_t" the correct one? If so how do I store the address of the passed array so that I can use it in another function later?

Thanks all.

ADDED:

The following code shows what I am trying to do (JUST FOR THIS EXAMPLE) but clearly several lines are just rubbish

The lines which start "//////" are the ones I probably need help with.

I know I could call the original function again BUT this is not what I am trying to do. I need to understand HOW to do what this program is doing in order to add to an existing very large program. So I have created this example just as a learning tool.

String test1[10];
String test2[10];
////// uint16_t stored[100];     // HOW ????
int numarrays=0;

void setup() {
  // put your setup code here, to run once:
 test1[0]="1";
 test1[1]="2";
 test1[2]="3";
 test2[0]="one";
 test2[1]="two";
 test2[2]="three";
 Serial.begin(115200);

  testpassarray(test1);
  testpassarray(test2);

  reprint(0);
  reprint(1);
  
}

void loop() {
  // put your main code here, to run repeatedly: 
  
  
  
}

void testpassarray(String *elements){
  
///// stored[numarrays]=elements;   // HOW ????
 numarrays+=1;
 
 Serial.println(elements[0]);
 Serial.println(elements[1]);
 Serial.println(elements[2]); 
  
}

void reprint(unsigned long int whicharray){
 
///// setup variable "elements"         //  HOW ????
  
///// elements= address of which array  //  HOW ????
 
 
 Serial.println(elements[0]);
 Serial.println(elements[1]);
 Serial.println(elements[2]); 
  
}

The code does not work.

Of course not. You are passing a pointer to an array of Strings to testpassarray. Then, in that function, you are creating, on the stack, an array of ints. Then, you are trying to set the first element beyond the end of the array to the value that is the address of the array of Strings.

Once the function ends, the array of ints goes away. The invalid assignment is lost.

You need to properly allocate space for the array, statically as a global array, or dynamically, using malloc() or new. The array MUST be of the right type to hold the pointers. You must assign the pointer to a valid element in the array.

There are just too many things you are doing wrong in that code.

PaulS:

The code does not work.

Of course not. You are passing a pointer to an array of Strings to testpassarray. Then, in that function, you are creating, on the stack, an array of ints. Then, you are trying to set the first element beyond the end of the array to the value that is the address of the array of Strings.

Once the function ends, the array of ints goes away. The invalid assignment is lost.

You need to properly allocate space for the array, statically as a global array, or dynamically, using malloc() or new. The array MUST be of the right type to hold the pointers. You must assign the pointer to a valid element in the array.

There are just too many things you are doing wrong in that code.

Thanks, I never expected the code to work but just that it could be followed.

The array "stored" needs to be an array of pointers to the arrays in the main program but I don't know what type the pointer is. This array is global (as are the String arrays) so once the address of the array is stored it should stay where it is till I clear everything later.

In the other function "reprint" I need to get this pointer address back from the global array and then access the array based on that pointer.

The String arrays will not change between their pointers being placed into the global array and being used. Certain events will completely clear all the arrays and we start again.

but I don't know what type the pointer is.

Then, you are screwed. You can't store an array of pointers without knowing the type of the pointer.

Well, that is not technically accurate, since you could cast the pointer to type void *, but I really do NOT recommend that. There is a reason that C (and C++) is a strongly typed language.

This array is global

Not in the code you posted.

In the other function "reprint" I need to get this pointer address back from the global array and then access the array based on that pointer.

One assumption that you are making, that is incorrect, is that you can determine the size of the array that a pointer points to from just the pointer. You can't. So, somewhere, you also need to store the size of the array pointed to.

The String arrays will not change between their pointers being placed into the global array and being used. Certain events will completely clear all the arrays and we start again.

You REALLY ought to consider not using Strings at all.

No I mean I don't know what type A pointer is. The arrays are all String arrays.

In the code I posted, the actual arrays are all global unless I am misunderstanding the scope, it's defined before the setup function in the main body not inside a function. Then the code sends the address of the array to the first function so I need to store that address whilst I am in the function. Then in the other function I need to recall the address from that array and then use the Strings. I can soon find the number of elements by looking for the first empty String.

So what type is a pointer? I assumed that it was a memory location hence my first guess at unsigned long int.
Once these addresses are stored in the global array how do I then use the address to refer to the String array?

Thanks

I have an array of 100 Strings for the main storage and these can be any length from empty to 200 characters but mainly empty or 1-10 characters so storing as a string array would take more space wouldn't it?

Storing as fixed size strings will probably not work well for you, then. You might be able to pack them or make the space less if you know some information about how they are used. Are you going to do a lot of text manipulation? Is there a lot of inserting and deleting of strings? Do they change a lot?

I keep revisiting your post but no matter how many times I read it I'm not understanding what it is you wish to accomplish.

lloyddean:
I keep revisiting your post but no matter how many times I read it I'm not understanding what it is you wish to accomplish.

The progrmastere is just a small program that uses the processes I am trying to accomplish rather than complicating matters by posting the entire program.

Basically I have about 20 different functions that all add gui objects to a master list then the interrupt driven routine creates the objects on screen. I need to be able to pass a list of Strings for certain objects but the master storage shouldn't duplicate the objects, I just want the add routine to store the array pointer. Once the array pointer is stored the draw routine for that type of object will recall the Strings and display them as necessary.

The boss of that that I can't work out how to do are store the array pointer in a cell of an array and then later recall that pointer using it to recall the Strings.

No I mean I don't know what type A pointer is. The arrays are all String arrays.

An array of Strings is pointed to be a String pointer (String *).

Do you really need to use an array of 'String', or 'String' pointer, objects or can it be an array of 'C' 'char*' (zero terminated string pointers)?

PaulS:

No I mean I don't know what type A pointer is. The arrays are all String arrays.

An array of Strings is pointed to be a String pointer (String *).

Thanks, How do I assign that as a type for an array and once the values are in the array how do I then access element[1] etc from the array?

Sorry to be a pain but I know what I need to do but just don't have the experience with this language.

Cheers....

lloyddean:
Do you really need to use an array of 'String', or 'String' pointer, objects or can it be an array of 'C' 'char*' (zero terminated string pointers)?

Yes I do, I've mentioned it before I have an array of maybe 100 items which contain mainly "" or 5-10 chars BUT they could contain 200 characters. If I used arrays of strings it would take 201x100 or nearly 20K but as Strings with most of them empty it uses probably 1-1.5K

How do I assign that as a type for an array

String *lotsOfCarp[100];

will create an array of pointers to Strings.

PaulS:

How do I assign that as a type for an array

String *lotsOfCarp[100];

will create an array of pointers to Strings.

Many thanks.

To start with, I would question your grounds for wanting to use the String class. Perhaps it's necessary to achieve what you're trying to achieve, but perhaps it isn't. The String class is IMO quite dangerous and not wise to use at all if it can possibly be avoided - and I would take quite a lot of convincing that it can't be avoided here. That said, ...

If you want to hold a pointer-to-thing in an array, then the array needs to be declared as an array of pointer-to-thing.

int one;
int two;
int *myArray[] = { &one, &two };

It's not clear that you actually need to use an array of pointers. Are you trying to pass in a set of String objects? If the set of Strings in the set is fixed (although the content of each String may vary) can't you just define an array of String? Maybe what you're trying is sensible and it's just that you've simplified your example so far that the sense is no longer apparent, but it may also be that the solution you're trying to force to work is not actually necessary.

If you're going to pass this array to a function and expect the function to process each element in the array then you will also need to provide some way for the function to know how many elements are in the array. That could be via you knowing and hard-coding the length, or the calling code passing in another argument giving the length, or having some way to determine the length of the array being passed in (sometimes it's appropriate to pass in a null-terminated array of pointers) but one way or another there needs to be some way to know the length.

Here's an example of syntax for one way to do arrays of C type strings.

char cStringEmpty[] = "";
char cStringOne[] = "one";
char cStringTwo[] = "two";
char cStringThree[] = "three";
char cStringFourScoreAndSevenYearsAgo[] = "Four score and seven years ago,";

char *arrayOne[] = {cStringOne, cStringThree, cStringTwo};
char *arrayTwo[4];

void setup()
{
  arrayTwo[0] = cStringFourScoreAndSevenYearsAgo;
  arrayTwo[1] = cStringEmpty;
  arrayTwo[2] = cStringOne;
  arrayTwo[3] = "Testing, Testing, 1..2..3..";
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Printing arrayOne");
  PrintArray(arrayOne, 3);
  Serial.println("Printing arrayTwo");
  PrintArray(arrayTwo, 4);
  for(;;);
}

void PrintArray(char **stringArray, int arraySize)
{
  int i;

  for (i = 0; i < arraySize; ++i)
  {
    Serial.print("stringArray[");
    Serial.print(i);
    Serial.print("] = ");
    Serial.println(stringArray[i]);
  }
}

Output:

Printing arrayOne
stringArray[0] = one
stringArray[1] = three
stringArray[2] = two
Printing arrayTwo
stringArray[0] = Four score and seven years ago,
stringArray[1] = 
stringArray[2] = one
stringArray[3] = Testing, Testing, 1..2..3..

Really, your C strings are quite flexible. You can use hard coded strings, or strings read in or generated. Your string array is just an array of character pointers. But they have to point to valid places in memory where there are characters (or not), followed by a null terminator. The null terminator is mandatory. The empty string simply points to a null terminator. The strings don't have to be of uniform size, and you can allocate them or move them around if you need to. Also, as you can see, you can have multiple string arrays that have elements that point to some of the same strings. The strings are not duplicated in memory, but the pointers are.

I do appreciate the help but the thread does go off in the direction of whether I need to do what I am doing. The demo program has nothing to do with the final code which needs to use Strings and cannot be hard coded.

The application in question is the DueGUI I am writing and basically the programmer will add objects like this:

progressbar=DueGUI.addProgressBar(375,100,40,30,60,50,ss,1,clrBlue,clrWhite,clrBlack,clrRed,2,optVisible,URNProgressbar); 
progressbar2=DueGUI.addProgressBar(20,100,40,350,60,30,ss,0,clrGreen,clrWhite,clrBlack,clrYellow,2,optVisible,URNProgressbar2); 
DueGUI.addButton(100,425,200,50,clrBlue,clrWhite,clrWhite,clrRed,clrWhite,2,"Refresh",posCentre,posCentre,BVS_28,optVisible ,URNRefresh); 
btnAdd=DueGUI.addButton(100,250,200,50,clrCyan,clrWhite,clrBlack,clrRed,clrWhite,2,"Bring back 1&2",posCentre,posCentre,BVS_28,optInvisible,URNAdd); 
btnRemove=DueGUI.addButton(100 ,350,200,50,clrGreen,clrWhite ,clrBlack,clrRed,clrWhite,2,"Remove  1&2",posCentre,posCentre,BVS_28,optVisible,URNRemove); 
DueGUI.addButton(350,350,199,50,clrBlue ,clrWhite ,clrWhite,clrRed,clrWhite,2,"Fan Screen",posCentre,posCentre,BVS_28,optVisible,URNFanScreen); 
DueGUI.addButton(600,350,199,50,clrBlue ,clrWhite ,clrWhite,clrRed,clrWhite,2,"Clock Screen",posCentre,posCentre,BVS_28,optVisible,URNClockScreen);

The library then stores the added objects which can be buttons, images, graphical shapes, text, input boxes, analogue clocks etc etc in a master block of arrays but the arrays are general purpose so as to save memory.

What I am trying to do is allow the user to pass a function:

addCycleStringButton(word x,word y,word xs,word ys,long colour,long borcolour,long textcolour,long presscolour,long presstextcolour,byte borwidth,String top,word xo,word yo,int font,int initialstate,String* elements,int cyclexo,int options,bool visible,int URN);

Where the variable passed in red is an array of elements for a drop down list.

The addCycleStringButton function will then store the address of the array in an array and later the draw/redraw/update functions will recall this address and access the array to find the relevant Strings in order to draw the object on the screen.

The test program simplifies this to the extreme that it makes no sense as to WHY I am doing it but I just wanted to make it simple so that I wasn't having to post massive amounts of code.

As it stands at the moment the test program does exactly what I need up to the point of USING that stored address....

String test1[10];
String test2[10];
String *stored[100];
int numarrays=0;

void setup() {
 test1[0]="1"; test1[1]="2"; test1[2]="3";
 test2[0]="one"; test2[1]="two"; test2[2]="three";
 Serial.begin(115200);

  testpassarray(test1);
  testpassarray(test2);

  reprint(0);
  
}

void loop() {
}

void testpassarray(String *elements){
 stored[numarrays]=elements;   
 numarrays+=1;
 Serial.println(elements[0]);
 Serial.println(elements[1]);
 Serial.println(elements[2]); 
}

void reprint(int whicharray){
 
 
// setup variable "elements"         //  HOW ????
  
// elements= address of which array  //  HOW ????
 
  int objectNumber=0;
  while (element[objectNumber]!=""){
    Serial.println(element[objectNumber]);
    objectNumber+=1;    
  } 
 

}

So now the whole program works other than the final function....

on entry to the final function we have the following:

int whicharray - this contains the location in the store[] array of the address of the String array
stored[] - this contains the stored pointers
the number of elements is specified by an empty element so I'm using a while loop

SO....

How do I make "element[]" point to the correct array now that I can recall it's address from the store[] array?

as I said I do appreciate the help but it has to be done using Strings and if there is a way to do what I am wanting to do it will actually make it much simpler.

void setup() {
 test1[0]="1"; test1[1]="2"; test1[2]="3";
 test2[0]="one"; test2[1]="two"; test2[2]="three";
 Serial.begin(115200);

  testpassarray(test1);
  testpassarray(test2);

  reprint(0);
  
}

You are passing local variables to a function, which immediately go out of scope when loop ends. Thus your desire to store a pointer to them is misguided. I suggest you look up "variable scope". Also look up "malloc" and "free", or "new" and "delete".

You don't have to use the String class, you can malloc an amount of memory to hold a string of the exact size you need.

If the array is being passed purely temporarily you might want to look into passing by reference.

The array is setup outside of the function setup ie in the main code. Does that not make it global !

I am writing a library, I do not know how big the Strings will be before hand. They can be 0-200 characters and there can be up to 100 sets mainly empty. Strings are what I am using.

This is as far as I've got:

// Global variables

String test1[10] = {"1","2","3"};
String test2[10] = {"one","two","three"};
String *stored[100];
int numarrays=0;

void setup() {
  Serial.begin(115200);
  testpassarray(test1);
  testpassarray(test2);
  reprint(0);
  reprint(1);
}

void loop() {
}

void testpassarray(String *elements){
  stored[numarrays]=elements;   
  numarrays+=1;
  Serial.println("");
  Serial.println((unsigned long int)elements,HEX);
  Serial.println(elements[0]);
  Serial.println(elements[1]);
  Serial.println(elements[2]); 
}

void reprint(int whicharray){
   
  String elements[10]; ////  This line needs to setup "elements" to point to the String array referenced by stored[whicharray]

  Serial.println("");
  Serial.println("");
  Serial.println((unsigned long int)stored[whicharray],HEX);
  
  int objectNumber=0;
  while (elements[objectNumber]!=""){
    Serial.print(objectNumber);
    Serial.print(" = <");
    Serial.println(elements[objectNumber]);
    Serial.println(">");
    objectNumber+=1;    
  } 
 
  // release any variables etc
 
}