passing String as a parm into a Function

I can't figure out how to take a String input into a function? In the code below,

line 34

positionInside = message.indexOf(inputString); //passing in "parm1="

is interpreted as only getting the first character "p" (thus returning value of 3).

The answer I am looking for is a value of 8.

What am I doing wrong?

//                01234567890
String message = "/y?parm1=98";    //

int positionOutside = 0;
int positionInside = 0;

void setup () {
  Serial.begin(9600);
  positionOutside = message.indexOf('parm1=');
  // CASE #1)  returns 8
  Serial.println(positionOutside);
  
  String parmDoubleQuote = "parm1=";
  Function_Pass_String (parmDoubleQuote);

// String  parmSingleQuote = 'parm1='; //Error compiliing conversion from 'int to 'String is ambiguous
//  Function_Pass_String (parmSingleQuote);

}

void loop() {
} 

void  Function_Pass_String (String  inputString ) {

  positionInside = message.indexOf("parm1=");  
  // CASE #2)   returns 3   with double quote 
  Serial.println(positionInside);

  positionInside = message.indexOf('parm1=');  
  // CASE #3)    returns 8   with single quote 
  Serial.println(positionInside);

  positionInside = message.indexOf(inputString);  
  //  CASE #4)    returns 3   with String parm passed, stops on the first character, not the entire string 
  Serial.println(positionInside);
}

Hi, I always find confusing the use of the String type, and given it takes quite a bit of memory I usually use only char arrays.

The concept you are looking for are "pointers" that's the way to pass strings or any array as function parameter. A pointer is basically the address in the memory of the first element of the array. Then you can access the rest of the elements by adding to the pointer.

Here a very simple example of how pointers works:

char command[]="time"; // defined this way command will have 5 elements "t", "i", "m", "e" and "/0" which is the end of string indicator

function printCharN(*char text, int N){
//this function prints the Nth character of the string text

//To make sure N is not longer than the string, we go trough it looking for a '/0'
int i=0;
int textTooShort=1;
while(*text!='/0){
if(i==N){
Serial.println(*text+N);
textTooShort=0;//we record that we found the charecter
break;
}
text++;//this advance the pointer to the next character of the string
i++;
}
if(textTooShort==1){
Serial.println("Text too short");
}
}

Make sense?

In setup() and elsewhere in code like

positionOutside = message.indexOf('parm1=');

Watch the use of single ' versus "

You use single quote for a char, a double quote for a string.

'A' and "A" are not the same thing

First Thanks for the quick reply.

What is confusing is indexOf seams to behave the opposite based on the rules of single and double quotes.
https://www.arduino.cc/en/Reference/String

Double quotes should treat like a string and return a value of 8, but returns 3 (like a solo character search)

  positionInside = message.indexOf("parm1=");  
  // CASE #2)   returns 3   with double quote treats like looking for just a character 'p'
  Serial.println(positionInside);

and

Single quotes should treat the argument like a solo character but in fact returns 8 like a string (which is what I want).

  positionInside = message.indexOf('parm1=');  
  // CASE #3)    returns 8   with single quote index of treats like a string "parm=1'
  Serial.println(positionInside);

Here is my unsuccessful attempt to pass in a character array

//                01234567890
String message = "/y?parm1=98";    //

int positionOutside = 0;
int positionInside = 0;

void setup () {
  Serial.begin(9600);
  positionOutside = message.indexOf('parm1=');
  // CASE #1)  returns 8
  Serial.println(positionOutside);
  
  char parmDoubleQuote[7] = "parm1="; 
  Function_Pass_String (parmDoubleQuote);
}

void loop() {
} 

void  Function_Pass_String (*char  inputString ) {
  positionInside = message.indexOf(inputString);  
  // I want the value of 8
  //  CASE #4)    returns 3   with String parm passed, stops on the first character, not the entire string 
  Serial.println(positionInside);
}

which is having a problem with *char as the input


How do I set up the function to return a value of 8 for .indexOf?

Any help would be greatly appreciated. . .

String message = "/y?parm1=98";

The string "parm1" DOES start at position 3 (the / is in 0, the y is in 1, the ? is in 2, and the p is in 3).

If you expect the function to return 8, it is your expectations that are WRONG!

Agreed, but after research there appears to be a bug in the String function. As I said ,the indexOf() treats single quotes as doubles and doubles as singles.

Please show me an example of this

positionInside = message.indexOf('parm1='); // returns 8, the ending of the string

by passing a variable instead of an explicit single quoted value. I can't figure it out.

Perhaps it can't be done.

something like this

positionInside = message.indexOf(aStringVarible); // returns 8, not 3!


The solution I am going with is just to add 5 to the result. It works.

Single quote denotes a character literal which is composed of a constant character. It is represented by the character surrounded by single quotation marks.

--> Single-quotes denote a character literal. Double-quotes denote a string literal.

'parm1=' is not a legit C++ expression for a string. What do you expect?

The solution I am going with is just to add 5 to the result. It works.

Utter nonsense.

come on...

consider this code

String message = "/y?parm1=98";

void setup() {
  Serial.begin(115200);
  int positionSingleQuote = message.indexOf('parm1=');
  int positionDoubleQuote = message.indexOf("parm1=");
  Serial.println(positionSingleQuote);
  Serial.println(positionDoubleQuote);

  Serial.println((char) 'parm1=');
}

void loop() {}

when you try to compile you get:

[color=orange]/var/folders/xk/mwl4yt3j5rsgdmgmgjlqsk7w0000gn/T/arduino_modified_sketch_875666/sketch_nov17a.ino:5:45: warning: [b][color=red]character constant too long for its type[/color][/b]
   int positionSingleQuote = message.indexOf('parm1=');
                                             ^
/var/folders/xk/mwl4yt3j5rsgdmgmgjlqsk7w0000gn/T/arduino_modified_sketch_875666/sketch_nov17a.ino:10:25: warning: [color=red][b]character constant too long for its type[/b][/color]
   Serial.println((char) 'parm1=');
                         ^
/var/folders/xk/mwl4yt3j5rsgdmgmgjlqsk7w0000gn/T/arduino_modified_sketch_875666/sketch_nov17a.ino: In function 'void setup()':
/var/folders/xk/mwl4yt3j5rsgdmgmgjlqsk7w0000gn/T/arduino_modified_sketch_875666/sketch_nov17a.ino:5:53: [color=red][b]warning: overflow in implicit constant conversion[/b][/color] [-Woverflow]
   int positionSingleQuote = message.indexOf('parm1=');[/color]

That should be enough to tell you to start thinking at what you do. why are you ignoring the compiler warnings?

But as it's just a warning so it lets you compile et run the code. indeed you get

8
3
=

and then it all starts to makes sense

with the single quote you get the position 8 because the compiler (as evidence with the last print which shows '=') has transformed your illegal string 'parm1=' into just '=' --> so you are asking what is the index of the character '=' into "/y?parm1=98" which is indeed at index 8

if you use the correct notation, then you get 3 - because indeed 3 is the index in "/y?parm1=98" where "parm1=" starts.

don't try to mess around with adding or subtracting stuff to fix your programing mistakes or claim "after research there appears to be a bug in the String function"... that's total nonsense.

As often said - the bug had its hands on the keyboard and was staring at the screen... :slight_smile: (gentle joke)

Just program the right way.

if you want to look for "parm1=" and then point at the starting position of "98" then the right way to do this to meet the general case is

String message = "/y?parm1=98";
const char param1_string[] = "parm1=";

void setup() {
  Serial.begin(115200);
  int position = message.indexOf(param1_string) + strlen(param1_string);
  Serial.print("Number will start at position "); Serial.println(position);
  Serial.print("Number is "); Serial.println(message.c_str() + position); // message.c_str() = pointer to the array that contains a null-terminated sequence of characters
}

void loop() {}

and obviously if you could drop the String class altogether that would be even better for your memory footprint: the code above uses 3506 bytes and 262 of RAM.

this does the same thing:

char message[] = "/y?parm1=98";
const char param1_string[] = "parm1=";

void setup() {
  Serial.begin(115200);
  int position = strstr(message, param1_string)-message+strlen(param1_string);
  Serial.print("Number will start at position "); Serial.println(position);
  Serial.print("Number is "); Serial.println(message + position);
}

void loop() {}

and uses 2150 bytes of flash (you save 1356 bytes) and 246 bytes of RAM. (as tested on a MEGA)

of course in real life you would just do:

char message[] = "/y?parm1=98";
const char param1_string[] = "parm1=";

void setup() {
  Serial.begin(115200);
  int value = atoi(strstr(message, param1_string)+strlen(param1_string));
  Serial.print("Number is "); Serial.println(value);
}

void loop() {}

and have the value of your param1 in an integer.

Makes sense ?