You have to pass both a pointer to the list, and the length of the list
as an extra argument. The signature of the function may be something
like:
void processFiles(const char *fileList[], int fileCount);
Note that const char *fileList[] is just a fancy way of writing
const char **fileList. I find the former more readable, but that is
completely subjective.
Here is a small test code showing this in action:
void processFiles(const char *fileList[], int fileCount)
{
for (int i = 0; i < fileCount; ++i) {
Serial.print("Processing file ");
Serial.println(fileList[i]);
}
}
const char *parameterFiles[3] = {
"/myIOT_param.json",
"/myIOT2_topics.json",
"/sketch_param.json"
};
void setup() {
Serial.begin(9600);
processFiles(parameterFiles, 3);
}
void loop() {}
Alternatively, you may put a “sentinel” at the end of the list: a null
pointer that signifies that the list ends there:
void processFiles(const char *fileList[])
{
for (const char **p = fileList; *p; ++p) {
Serial.print("Processing file ");
Serial.println(*p);
}
}
const char *parameterFiles[] = {
"/myIOT_param.json",
"/myIOT2_topics.json",
"/sketch_param.json",
nullptr
};
void setup() {
Serial.begin(9600);
processFiles(parameterFiles);
}
void loop() {}
Edit: Answering to EDIT_1.
[My library's] class holds an array that contains a list of all
filenames
First of all, you have to decide who is responsible for storing those
file names: the library or its client. When you write:
const char *parameterFiles[3] = {
"/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"
};
you are creating 4 arrays: an array of 3 pointers named
parameterFiles, and three arrays of characters holding the file names.
Note that those 3 arrays are anonymous: they are not array
variables. If the client code tries to pass this parameterFiles to
your library, the array identifier will decay to a pointer, and your
library will receive that pointer. What should it do with it?
The library could just keep a copy of the pointer. The client is then
responsible for ensuring that it remains valid for as long as the
library may need it. This practically implies that parameterFiles
should be a global variable, and should not be modified once given to
the library.
The library could make a copy of the array. Then the client is freed
from this responsibility. However, it is still responsible for
ensuring that the pointers that were copied from the array remain
valid, i.e. that the file names stay in the same place in memory.
The library could copy the file names themselves. Then the client
doesn't have any responsibility about keeping pointers valid.
If you choose option 2 or 3, the library will have to hold one or more
arrays. You will then have to choose whether you allocate them
statically, or dynamically with new. Dynamic allocation is more
efficient when the arrays can vary greatly in length, but it can raise
issues of memory fragmentation in RAM-constrained devices.
I cannot tell you which option is best: it depends on your use case. In
any case, whatever you choose, you should document it: the user of the
library should know whether they are responsible for keeping any
pointers valid.
In the following, I will assume option 2 with static allocation. This is
consistent with the code snippets in your question. Also, if the client
provides the file names as string literals, then pointers to these
strings remain always valid.
Here is a toy implementation of the myIOT2 class, where the list of
file names is copied by the constructor into the class:
class myIOT2 : public Printable
{
public:
static const int maxFileCount = 4;
myIOT2(const char *fileList[], int count) {
if (count > maxFileCount)
count = maxFileCount; // discard extra files
fileCount = count;
for (int i = 0; i < fileCount; i++)
filenames[i] = fileList[i];
}
size_t printTo(Print& p) const {
size_t count = p.print(F("myIOT2["));
for (int i = 0; i < fileCount; i++) {
count += p.print('"');
count += p.print(filenames[i]);
count += p.print('"');
if (i < fileCount - 1)
count += p.print(", ");
}
count += p.print(']');
return count;
}
private:
const char *filenames[maxFileCount];
int fileCount;
};
Note that, the array of file names being statically allocated, there is
a hard maximum on the number of files that can be stored. I made the
class Printable only for debugging convenience.
And here is an example of this class in use:
const int fileCount = 3;
const char *parameterFiles[fileCount] = {
"/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"
};
myIOT2 iot(parameterFiles, fileCount);
void setup() {
Serial.begin(9600);
Serial.println(iot);
}
void loop() {}
This test sketch prints:
myIOT2["/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"]