[SOLVED] char[] version of String.indexOf()

Hello again,

The Subject says it all:
You can find below an example code that gets a char substring from a char string - without using String (with capital S).

  1. What’s the difference between & and *? They both seem to give a variable’s position in memory.
  2. I can’t get sizeof() to return the proper size when I’m passing variables as pointers to a function. How to overcome that? (for buffer overrun prevention)
  3. I’m hoping that any of you know a built-in method that can perform this task in 3 or 4 steps :slight_smile:

This is the output:

-sketch started-
ATBuff size: 200
result size: 24
ATBuff position in memory: 978

String:
this is my string “and this is what i want”, ignore the rest

start (memory position | array position): 997 | 19
end (memory position | array position): 1020 | 42
length: 23
and this is what i want

String:
this is my string “and this is what i want to get”, ignore the rest

start (memory position | array position): 997 | 19
end (memory position | array position): 1027 | 49
length: 30
result: can’t store result string (too long)

String:
200-byte long with trailing double-quote12345678901234567(…)"

start (memory position | array position): 1177 | 199
result: can’t find leading delimiter, or is last char

And this is the code:

char ATBuff[200];
char result[24];

void setup()
{
  Serial.begin(9600);
  Serial.println("");
  Serial.println("-sketch started-");
  Serial.print("ATBuff[] size: ");
  Serial.println(sizeof(ATBuff)/sizeof(*ATBuff));
  Serial.print("result[] size: ");
  Serial.println(sizeof(result)/sizeof(*result));
  Serial.print("ATBuff position in memory: ");
  Serial.println(int(&ATBuff[0]));
}

void loop()
{
  Serial.println("------------------------------");
  strcpy(ATBuff, "this is my string \"and this is what i want\", ignore the rest");
  Serial.println("String:");
  Serial.println(ATBuff);
  Serial.println("");
  get_substring(ATBuff, '"', result);
  Serial.println("------------------------------");
  delay(1000);
  
  strcpy(ATBuff, "this is my string \"and this is what i want to get\", ignore the rest");
  Serial.println("String:");
  Serial.println(ATBuff);
  Serial.println("");
  get_substring(ATBuff, '"', result);
  Serial.println("------------------------------");
  delay(1000);
  
  strcpy(ATBuff, "200-byte long with trailing double-quote" // 40 chars
    "12345678901234567890123456789012345678901234567890" // 50 chars
    "12345678901234567890123456789012345678901234567890" 
    "1234567890123456789012345678901234567890123456789012345678\"");
  Serial.println("String:");
  Serial.println(ATBuff);
  Serial.println("");
  get_substring(ATBuff, '"', result);
  Serial.println("------------------------------");
  
  // stop sketch
  while (true){
    delay(100);
  }
}


void get_substring(char* input_string, char delimiter, char* result_string)
{ 
  // get the leading delimiter
  int sender_start = strchr(input_string, delimiter) - input_string + 1;
  Serial.print("start (memory position | array position): ");
  Serial.print(int(&input_string[0]) + sender_start);
  Serial.print(" | ");
  Serial.println(sender_start);
  
  if (sender_start > -1  && sender_start < 199)
    // i wanted to use < sizeof(input_string)/sizeof(*input_string)-1 instead
  { // >= 0 --> the delimiter was found and we have its position within the array
    // if > arraylength-2, then it's the last char, so we have no possible result.
      // (also works as overflow protection)
    
    // get the trailing delimiter
    int sender_length = strchr(&input_string[sender_start], delimiter) - input_string - sender_start;
    Serial.print("end (memory position | array position): ");
    Serial.print(int(&input_string[0]) + sender_start + sender_length);
    Serial.print(" | ");
    Serial.println(sender_start + sender_length);
    Serial.print("length: ");
    Serial.println(sender_length);
    
    if (sender_length > 0) // if < 0, no trailing char "
    {                 // if == 0, result string is empty
      if (sender_length < 24) // overflow protection
        // i wanted to use < sizeof(result_string)/sizeof(*result_string) instead
      {
        strncpy(result_string, &input_string[sender_start], sender_length);
        result_string[sender_length] = '\0';
        Serial.println(result_string);
      } else {
        result_string[0] = '\0';
        Serial.println("result: can't store result string (too long)");
      }
    } else {
      result_string[0] = '\0';
      Serial.println("result: can't find trailing delimiter, or result string empty");
    }
  } else {
    result_string[0] = '\0';
    Serial.println("result: can't find leading delimiter, or is last char");
  }
  
  result_string[0] = '\0';
  return;
}

You realize how much code this involves and the conditions I had to place in order to prevent overflows and unexpected return values… :frowning:

Thanks in advance for reading.

Sorry for posting a non-working code and output. It's fixed now ;)

I can't get sizeof() to return the proper size when I'm passing variables as pointers to a function. How to overcome that?

You can, in the called function. A pointer is always the same size. You have to determine the array size in the function that the array is defined in, and pass that size to any function that needs to know it.

The vast majority, if not all, of what your set_substring() function is doing could be done with a call to strtok() to find the string up to the delimiter and strdup() or strcpy() to make a copy of that string, depending on whether the output is a pre-defined array or not.

could be done with a call to strtok()

:open_mouth:

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  char str[] = "TOKENIZE \"ALL\" THE STRINGS!!!";
  char * pos;
  pos = strtok (str, "\""); // everything BEFORE the first " - ignore this result
  pos = strtok (NULL, "\""); // everything AFTER the first " and BEFORE the next "
  Serial.println();
  
  // stop sketch
  while (true)
  {
    delay(100);
  }
}

THANK YOU. :D