1

I am trying to parse a simple string, print the result of the parsing via serial.println, and trigger a function on the basis of the received command. I wrote the code below, which perfectly works in c (see the c file attached). However, the behaviour of the same code on the arduino IDE is completely different and I really can't figure out why.

#include <string.h>

void rcv_msg(char *rcv_msg) {

  char *all_tokens[2]; 
  int i = 0;

  all_tokens[i] = strtok(rcv_msg, "{,}");
  while (all_tokens[i] != NULL) {
    all_tokens[++i] = strtok(NULL, "{,}");
  }

  char *command = all_tokens[0]; 
  char *value = all_tokens[1];


  /*
  //These printls do not work, they are ignored, why?
  Serial.println("all_tokens[0]: ");
  Serial.println(all_tokens[0]);
  Serial.println("all_tokens[1]: ");
  Serial.println(all_tokens[1]);
  */

  if (strcmp(command,"message_1") == 0 && strcmp(value,"1") == 0) {

    Serial.println("message 1: ");
    Serial.println(command);
    Serial.println(value);
    Serial.println(" ");

  }

  if (strcmp(command,"message_2") == 0 && strcmp(value,"0") == 0) {

    Serial.println("message 2: ");
    Serial.println(command);
    Serial.println(value);
    Serial.println(" ");

  }
}



void setup() {

    Serial.begin(115200);
}

void loop() {

    char msg1[] = "{message_1,1}";
    char msg2[] = "{message_2,0}";

    Serial.println("Send msg1: ");
    rcv_msg(msg1); 
    delay(5000);

    Serial.println("Send msg2: ");
    rcv_msg(msg2); 
    delay(5000);    
}

This code gives the following output on the serial monitor, which is wrong:

Send msg2: message 2: message_2 {message_2,0}

Send msg1: message 2: message_1 {message_2,0}

Send msg2: message 2: message_2 {message_2,0}

Send msg1: message 2: message_1 {message_2,0}

Firstly, I don't understand why at the beginning, message 2 is printed before message 1, although message 1 was sent first. Second it is not clear to me the comparison done with strcmp is always returning the message 2.

More importantly, why running the same code in c has instead the correct output? I wonder if there is any error in my arduino code. BTW, I am testing the code on Teensy 3.2 but I plan to use it also on Arduino Uno.

The c code (which is perfectly working is this:

#include <string.h>
#include <stdio.h>


void rcv_msg(char *rcv_msg) {

    char *all_tokens[2]; //NOTE: the message is composed by 2 tokens: command and value
    int i = 0;


    all_tokens[i] = strtok(rcv_msg, "{, }");
    while (all_tokens[i] != NULL) {
        all_tokens[++i] = strtok(NULL, "{, }");
    }

    printf("all_tokens[0] : %s \n", all_tokens[0]);
    printf("all_tokens[1] : %s \n", all_tokens[1]);

    char *command = all_tokens[0];
    char *value = all_tokens[1];

    printf("command : %s \n", command);
    printf("value : %s \n", value);



    if (strcmp(command,"message_1") == 0 && strcmp(value,"1") == 0) {
        printf("activating command : %s %s \n\n\n", command, value);
    }

    if (strcmp(command,"message_2") == 0 && strcmp(value,"0") == 0) {
        printf("activating command : %s %s \n\n\n", command, value);
    }
}



int main() {

    char msg1[] = "{message_1, 1}";
    char msg2[] = "{message_2, 0}";

    rcv_msg(msg1);
    rcv_msg(msg2);

}
1

Both versions of your code have undefined behavior. On the given input your code will call strtok three times and store its result into the array three times: for the first token, for the second token and, finally, for the null pointer. You store all three (including that null pointer!) into the all_tokens array, which has size 2.

You are obviously aware of the potential array overrun danger: you even wrote this comment in your code

char *all_tokens[2]; //NOTE: the message is composed by 2 tokens: command and value

and yet in the following cycle

int i = 0;

all_tokens[i] = strtok(rcv_msg, "{, }");
while (all_tokens[i] != NULL) {
    all_tokens[++i] = strtok(NULL, "{, }");
}

you still insist on storing more than two values into all_tokens array.


Also, the second version of your code uses completely different message key values (why is it suddenly "motor1_pattern1" instead of "message_1"?), which makes it unclear how you compared the functionality of the second version with the functionality of the first.

  • many thanks. I added while (i < 2 && all_tokens != NULL) which solved the problem. Is this the best way of doing it? Also I edited the code removing motor1_pattern with message_1 (sorry that was a bad copy-paste I did). I still wonder: Why the serial monitor still displays first the second message although the first message was sent. It seems that the first message does not reach the serial monitor... what I am missing? Finally, do you suggest to use strtok_r instead of strtok? – L_T May 25 at 17:24
  • Suggest to have a look at the message about memory usage while compiling. Arduino have only a small amount of RAM and string functions are using a lot. If your code is very small, it can work, but the more you'll increase the size of code and the more you'll get strange results. – Peter May 26 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.