Problem to read string from serial

Hi,
I have write the code below in arduino ide 1.8.8. When I execute the code and type a string in the serial monitor, all the characters as printed, excluded ‘p’ char .
‘p’ char is always lost.
What do you thinks?
Thanks for reply.

#include <EEPROM.h>
struct st {
  char a[17];
  char b[26];
  char c[26];
  byte d;
  float e;
  float f;
  float g;
  float h;
  byte i;
};

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

void loop() 
{
  if(Serial.available())
  {
    String cmd=Serial.readStringUntil("\n");
    Serial.println(cmd);
    if(cmd.equals("write"))
    {
      st s1 = { "", "", "", 1, 1.0f, 1.0f, 1.0f, 1.0f, 1 };
      EEPROM.put(0, s1);
    }
  }
}

SerialInput_test_001.ino (480 Bytes)

I have explained the problem here: https://github.com/arduino/Arduino/issues/8534#issuecomment-463458321

While transferring a series of characters (a string), we usually send this ('\n') character and not this: "\n" by enabling the 'New line ending' Tab of the Serial Monitor. Therefore, while parsing the received message should we look into '\n' or this "\n" to mark the end-of-message? In C, '\n' is called the character literal and "\n" is known as string literal. What is the real difference between them? Do they have the same machine codes - '\n' is seen to have been coded into this value 00001010 (0x0A) in the ASCII chart.

I think this sketch will make it clear that "\n" and '\n' are two very different things when passed to a function as a char parameter (which is the type of the readStringUntil() parameter):

void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.print("(int)\"\\n\" == ");
  Serial.println((int)"\n");
  printASCIIvalue("\n");
  printASCIIvalue('p');
  printASCIIvalue('\n');
}

void loop() {}

void printASCIIvalue(char x) {
  Serial.print("The ASCII value of ");
  Serial.print(x);
  Serial.print(" is: ");
  Serial.println((int8_t)x);
}

"\n" is the equivalent of {'\n', 0} (a null terminated string). Now what I don't have an explanation for is why readStringUntil matches "\n" to 'p', since they have different ASCII values. I didn't actually investigate this fully when I closed the GitHub issue. I just assumed that "\n" and 'p' happened to have the same value. What I do know is that signed integer overflow is undefined behavior in C++ and you can see from the int cast of "\n" that it does overflow. When there's UB in the mix, anything can happen. It's the sort of thing that I'm usually happy to know "just don't do that and things will work properly" but now I'm a bit curious.

@pert

I'm usually happy to know "just don't do that and things will work properly" but now I'm a bit curious.

I'm curious too, but I remember some advice from Nick Gammon about not spending time trying to figure out why something didn't work (especially something obviously wrong like "\n" vs '\n') when you know code that does work and you and you why it works.

I was surprised that "\n" actually had an numerical value even if it wasn't ascii 'p'.

If you indeed run this to ground, post back here as your not the only one interested. :confused:

I was surprised that "\n" actually had an numerical value even if it wasn't ascii 'p'.

The string "\n" is stored in memory somewhere. When passed as an argument, it is the address that is passed. If the code was changed, the address in memory might change, and "equate" to a different letter.

PaulS taking time to bestow the knowledge on us as usual. Thanks!

In the specific code provided by Gionni67, "\n" happened to have the memory address that matched 'p'. In my test sketch, it has a different value. If you make a small modification to Gionni67's code then it no longer matches 'p'. If you run Gionni67's code on a Leonardo (instead of the Mega or Uno I tested with originally), it doesn't match.