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 Answer 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– L_T2019年05月25日 17:24:30 +00:00Commented May 25, 2019 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– Peter2019年05月26日 14:45:51 +00:00Commented May 26, 2019 at 14:45