Understanding the finer aspects of string variables

i am trying to use variables for filenames instead of hardcoded ones to be used like dataFile = SD.open(filename);
i understand that the filename variable can be declared as a string (type char) or as a String object (type String)
i think i can understand the String object usage as i have had experience with string manipulation in BASIC with $A = $B + "C" and the like.
however, if the filenames are fixed (eg. choosing from a menu of a limited set) then one should use the char type since this uses less memory, right ?

my problem now is getting the pairing of the variable and its usage in the function.

working from the examples on the Arduino Reference page;

IF

char* myStrings[]={"This is string 1", "This is string 2", "This is string 3",
"This is string 4", "This is string 5","This is string 6"};

THEN

for (int i = 0; i < 6; i++)  { Serial.println(myStrings[i]); }

results in each sentence being listed.

but

IF

char myStrings[]={"This is string 1 This is string 2 This is string 3 This is string 4 This is string 5 his is string 6"};

THEN

for (int i = 0; i < 6; i++)  { Serial.println(myStrings[i]); }

only results in This i

ie. each letter in the single string is viewed as a member of that array.

so far so good - but when i try to start using them in a function like so;

declaration and usage:

char file2use[13]="what2prn.txt";

readFile(file2use[13]);

with the function:

void readFile(char filename)  {
  dataFile = SD.open(filename);
...
}

then i get the error message; invalid conversion from 'char' to 'const char*'
(i'm probably still not quite grasping the usage of the '*' as an array pointer(?))

i tried changing the function to

void readFile(char filename[13])  {
  dataFile = SD.open(filename[13]);
...
}

but then get the error; invalid conversion from 'char' to 'char*'

:fearful:

could you please point out where i am going wrong with this ?

char myStrings[]={"This is string 1 This is string 2 This is string 3 This is string 4 This is string 5 his is string 6"};

This variable should be called myString, because there is only one string here.

for (int i = 0; i < 6; i++)  { Serial.println(myStrings); }
only results in This i

I'm assuming that you actually have [ i ] at the end of myStrings, so you are only printing 6 characters.

readFile(file2use[13]);

Create an array with 13 elements, then pass the 14th element (character) in the array to a function. Nope.

then i get the error message; invalid conversion from 'char' to 'const char*'

Of course you do. Lose the [13]. The function KNOWS how big the array is, because the array is NULL terminated.

i tried changing the function to

The function needs to be defined taking an array. You need to call the function with an array, not a single, out of bounds, element.

hi PaulS, thanks for your continuing help !

PaulS:

char myStrings[]={"This is string 1 This is string 2 This is string 3 This is string 4 This is string 5 his is string 6"};

This variable should be called myString, because there is only one string here.

just to be clear, that was a matter of semantics and it should be myString[] with the square brackets still, right ?

PaulS:

for (int i = 0; i < 6; i++)  { Serial.println(myStrings); }

only results in This i



I'm assuming that you actually have [ i ] at the end of myStrings, so you are only printing 6 characters.

yes, i think i copied that wrongly - as it is above, it would print the whole string 6 times, irrelevant to int i.

PaulS:

readFile(file2use[13]);

Create an array with 13 elements, then pass the 14th element (character) in the array to a function. Nope.

okay, so that's misuse of correct syntax ?
so i do want readFile(file2use); in this case, provided the function is expecting the correct data type, which is... not char but... ??

PaulS:

then i get the error message; invalid conversion from 'char' to 'const char*'

Of course you do. Lose the [13]. The function KNOWS how big the array is, because the array is NULL terminated.

right, i think i'm getting when to use file2use[13] and when just file2use

PaulS:

i tried changing the function to

The function needs to be defined taking an array. You need to call the function with an array, not a single, out of bounds, element.

okaaay.... i think i'm getting there - not a char, but an array of chars.
so it should be ;

void readFile(char filename[])  {
  dataFile = SD.open(filename);
...
}

<>

BINGO !! :smiley:
thanks a big bunch !

okay, just to confirm my understanding of using the '*', if i were to make a function that accepted an array of strings (ie. an array of an array of chars), then i'd declare it like so;

void showFilelist(char* filenames[])  {
 for (int i=0; i<4; i++)  {
  Serial.print ("File #");
  Serial.print (i);
  Serial.print (" is : ");
  Serial.println (filenames[i]);
...
}

where the variable is declared;

char filenames[4]={"Menu item 1", "Menu item 2", "Menu item 3", "Menu item 4"};

(almost misused round brackets for the curly ones there...)

just to be clear, that was a matter of semantics and it should be myString[] with the square brackets still, right ?

That depends. Did you really intend to remove the double quotes and commas from the original array of strings, to make one string?

okay, so that's misuse of correct syntax ?

It is syntactically correct, but logically wrong.

so i do want readFile(file2use); in this case, provided the function is expecting the correct data type, which is... not char but... ??

Either array of char or pointer to char.

void readFile(char file2Use[13]);

or

void readFile(char *file2Use);

then i'd declare it like so

That's one way. The other would be:

void showFilelist(char **filenames)

where the variable is declared;

Well, I hardly think that "Menu Item 1" is a file name, but the syntax is correct.

(almost misused round brackets for the curly ones there...)

The compiler would have bitch-slapped you.

PaulS:

just to be clear, that was a matter of semantics and it should be myString[] with the square brackets still, right ?

That depends. Did you really intend to remove the double quotes and commas from the original array of strings, to make one string?

yes, one string - it was just changing the original sketch around to see what happened when i did various stuff.
what i meant was that the square brackets are still necessary, whether or not it's called mystring or mystrings.
(we're dealing with an absolute n00b here you know !)

PaulS:

okay, so that's misuse of correct syntax ?

It is syntactically correct, but logically wrong.

right, got it.

PaulS:

so i do want readFile(file2use); in this case, provided the function is expecting the correct data type, which is... not char but... ??

Either array of char or pointer to char.

void readFile(char file2Use[13]);

or

void readFile(char *file2Use);

that asterisk should be next to 'char' instead of 'file2Use', right ?

PaulS:

then i'd declare it like so

That's one way. The other would be:

void showFilelist(char **filenames)

woah - TWO asterisks now ?! :cold_sweat:

PaulS:

where the variable is declared;

Well, I hardly think that "Menu Item 1" is a file name, but the syntax is correct.

yeah, bad example - i was thinking a menu item which would then launch (or read from) a specific file.
i guess i don't need to be "wasting too much time" on this 'menu thing' since it's not exactly what an Arduino needs to be using up its resources for - saw there was already a library for Menu handling for LCDisplays.
bottom line here is i'm learning about datatypes and how to handle them.

PaulS:

(almost misused round brackets for the curly ones there...)

The compiler would have bitch-slapped you.

heh-heh. just wait 'til i can grab the board by the handles...
it doesn't help that the font isn't very distinctive in showing the two - i actually already have Notepad++ for my php dabbling, didn't realise i could also use it for writing Arduino sketches.

that asterisk should be next to 'char' instead of 'file2Use', right ?

The asterisk indicates that the variable is a pointer. The placement doesn't matter to the compiler, but it does to me.

A statement like:

int *a, b;

defines to variables - a as a pointer to int and b as an int. Putting the asterisk next to the variable makes that clearer (to me) than:

int* a,b;

which seams to imply that a and b are of type pointer to int.

Not that I recommend either approach.

int *a;
int b;

makes it far clearer that a and b are NOT the same type.

woah - TWO asterisks now ?!

Yep. You can have more than that.

bottom line here is i'm learning about datatypes and how to handle them.

That's a good thing, whether its realistic for the Arduino or not.