A strange behaviour when printing a string using Serial.Available

Hello,
I'm a newbie with Arduino, and this is my first question. Hope I posted it in the right section, too.
The question I'm asking is more a "I don't understand why" than a "it doesn't work", and I post it after searching for the answer in other threads/via search engine, and I didn't find the exact reason why this happens. I tried also reading about the function Serial itself, but I didn't go far.
So, here's the "problem": I'm learning the basics of Arduino via a tutorial I found on YouTube, and I ended with this code:

char c;
String string1;

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

void loop(){
  if (Serial.available()){
    string1 = "";
    do{
      if (Serial.available()){   // I don't understand why this loop is necessary
        c = Serial.read();
        if (c != '\n'){
          string1 += c;
        }
      }
    }while(c != '\n');

    Serial.print(string1);
  }

}

The purpose is to simply print a string I digited previously on the Serial Monitor. The code is clear to me (it's very simple), except for one thing: the second if loop.
Example: if I try to write in the Serial Monitor a random string with this exact code, ex. "Hello there", it prints the result as it should be.
If I remove that if loop, leaving the do-while loop like

...
if (Serial.available()){
  c = Serial.read();
  if (c != '\n'){
    string1 += c;
  }
}
...

The output is this:

H⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮e⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮l⸮⸮...

(I didn't print the whole message, think you got what's up)

Now, I simply don't understand why it has this behaviour, and I don't now why, after every letter printed I get those symbols. Sorry if I can't be more specific about a possible explanation, but I don't understand neither the problem (what caused it), nor why the if loops solves it.
Hope my English wasn't that bad, it's not my native language. Hope I also explained everything clearly, and thanks to whoever will bright me up. Alternate and easier solutions are also welcomed.

NOTE: The guy who made the tutorial just inserted the loop saying it would solve the issue, but it didn't explain why.

EDIT: I forgot to specify. I use an Arduino Uno rev. 3 on Ubuntu. Don't know if it helps.

If I remove that if loop, leaving the do-while loop like

No such thing as an "if" loop, and there's no do..while in the second code you posted.

Post all the code.

There is no such thing as an "if loop", it's an "if statement".

You check if there is one character available, in the outer if statement, and then you read it. After you read it, no more characters are available to read. If you remove the inner if statement, you just try reading more characters, even though there aren't any, until the character is '\n'. When no character is available, Serial.read returns -1, which is an invalid character, and it's printed as "⸮".

The code you write runs much faster than the speed of the serial data transfer.

Pieter

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R

Okay, I think I'll have to excuse since I deleted the wrong line while reporting the code (I didn't pay enough attention since I wanted to post it without all my unnecessary comments in the original code). My bad, I'm very sorry as I probably confused you.
Here's the code that runs properly:

char c;
String string1;

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

void loop(){
  if(Serial.available()){
    string1 = "";
    do{
      if(Serial.available()){   // The if statement I don't understand
        c = Serial.read();
        if (c != '\n'){
          string1 += c;
        }
      }
    }while(c != '\n');
    
    Serial.print(string1);
  }
  
}

And this is the code that I would use (but it's not correct)

char c;
String string1;

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

void loop(){
  if(Serial.available()){
    string1 = "";
    do{
      c = Serial.read();
      if (c != '\n'){
        string1 += c;
      }
    }while(c != '\n');
    
    Serial.print(string1); 
  }
  
}

You're reading stuff even when there's nothing to read, hence the strange characters.

Probably, the OP has wanted to make the following sketch:

char c;
String string1 = "";

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

void loop()
{
  byte n = Serial.available();
  if (n != 0)
  {
    c = Serial.read();
    if (c != '\n')
    {
      string1 += c;
    }
    else
    {
      Serial.println(string1);
      String string1 = "";
    }
  }
}

sm4.png

sm4.png

    {
      Serial.println(string1);
      String string1 = "";
    }

Probably a copy and paste error. :wink: String

Whandall:

    {

Serial.println(string1);
      String string1 = "";
    }



Probably a copy and paste error. ;) ~~String~~

I don't have much experience in the use of String data type; I reset the string1 array with this code: String string1 = ""; having followed what I do to reset cstring (char myData[20] = "";).

Thanks for directing me towards correct syntax of resetting a String type array.

GolamMostafa:
I don't have much experience in the use of String data type; I reset the string1 array with this code: String string1 = ""; having followed what I do to reset cstring (char myData[20] = "";).

Thanks for directing me towards correct syntax of resetting a String type array.

It isn't a matter of knowing or not knowing about Strings, it's a simple matter of scope.

TheMemberFormerlyKnownAsAWOL:
It isn't a matter of knowing or not knowing about Strings, it's a simple matter of scope.

What is simple to you, that is a hard rock for me if not explained?

You're reading stuff even when there's nothing to read, hence the strange characters.

And is this caused by what PieterP said?

The code you write runs much faster than the speed of the serial data transfer.

Otherwise I can't find any other explanation. Imagine to execute the following code "manually" (note, this is the wrong one), this is what I think it should do:

void loop(){
  if(Serial.available()){   // first if statement
    string1 = "";
    do{
      c = Serial.read();
      if (c != '\n'){
        string1 += c;
      }
    }while(c != '\n');
   
    Serial.print(string1);
  }
 
}

I type something, ex. "Hello"
it enters the first if statement, and assigns string1 = " "
it enters the do-while cycle, reads the first char by Serial.read (in this case, the letter "H"), and assigns it to c
c is unequal to '\n', so adds it to the string
executes the do-while again with the following letter (the letter "e")

if it does not do that (and it doesn't), it seems like what PieterP says.
And adding the second if statement, like

void loop(){
  if(Serial.available()){
    string1 = "";
    do{
      if(Serial.available()){   // <--- if statement added
        c = Serial.read();
        if (c != '\n'){
          string1 += c;
        }
      }   // <--- it's relative "}"
    }while(c != '\n');
   
    Serial.print(string1);
  }
 
}

makes the code "wait" for the following correct char (in this case, the letter "e").

And why is this caused? Something about the cable? Some IDE or even the PC performance/settings? Sounds strange because my Serial Monitor is set at 9600 baud, the same as the settings in the void setup(). Guess I'll search better about this, but any further explanation or link is welcomed.
In any case, thank you all so far.

The processor doesn't know or care what you think should happen; it just executes the code you gave it at up to one instruction every 62.5ns.

In the time that a single character at 9600 bits per second takes to be transmitted...well, that's a lot of 62.5ns.

If there's nothing new to read, Serial.read just returns -1

Just to show that you are probably reading the serial input buffer faster than the characters are arriving, add a delay similar to the below and see if the strange characters go away.

if(Serial.available()){   // <--- if statement added
        c = Serial.read();
        if (c != '\n'){
          string1 += c;
          delay(3)
        }

What's wrong with telling him that the String class is not a good option and that he should use a char array instead?

char c;
char msg[20];

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

void loop(){
  int count;
  if (Serial.available()){
    count = Serial.readBytesUntil('\n', msg, sizeof(msg) - 1);
    Serial.println(count);
    msg[count] = '\0';    // Now it's a string
    Serial.print(msg);
  }   
}

econjack:
What's wrong with telling him that the String class is not a good option and that he should use a char array instead?

. One simple concept at a time, take it slow and steady.

econjack:
What's wrong with telling him that the String class is not a good option and that he should use a char array instead?

I did not specifically mention that issue but the code in the link in my Reply #3 uses a char[] array.

...R

Before other noise takes over, maybe the OP can try the below simple echo code and see if it works.

//zoomkat 6-29-14 Simple serial echo test
//type or paste text in serial monitor and send

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("Simple serial echo test"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the String readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured String 
    readString="";
  } 
}

zoomkat:
Before other noise takes over, maybe the OP can try the below simple echo code and see if it works.

...but don't let it be habit-forming.

What's wrong with telling him that the String class is not a good option and that he should use a char array instead?

Actually, that's a basic alternative that I didn't think about (I learned some basic C, but I was too focused in understanding the code the tutorial used I didn't search for alternatives).

The processor doesn't know or care what you think should happen; it just executes the code you gave it at up to one instruction every 62.5ns.

Maybe I'll have to understand better this concept, as I never cared about that aspect since now (never had problems in C).

Before other noise takes over, maybe the OP can try the below simple echo code and see if it works.

This actually works, I'll save it. Thank you!