String declaration inside loop()

Hello, I have strange behaviour in my sketch when declaring a String object inside loop(). I am reading from Serial and my program freezes(I am not sure if the right word is this because i just dont receive anything in serial_input) when i declare String serial_input this way:

void loop()                    
{
  String serial_input;
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      char pchar= Serial.read();
      serial_input += pchar;
    }
  }
  // do anything with serial_input
}

There is no problem if i declare serial_input as global variable before setup() and then clear the sting at the end of loop() using serial_input="".

What i am doing wrong? Thanks!

Sorry for asking the obvious, but how to you know there is nothing in serial_input ? Do you Serial.println() it, for example ?

Yes, to be more accurate I am using NewSoftSerial for serial connection to my phone and then Serial to read the result on my PC. I cant explain exactly whats hapening but I thing serial_input collects data only on the first loop then I stop receiving any response. I am sure that both serial connections are fine because when I move the declaration out of the scope as global variable everything is working fine.

I don't have an arduino board right now to make tests, but have you tried putting a sort of keepalive signal, like blinking the on-board led, inside loop() ? The String object is created and destroyed at every loop() invocation on the stack, could that cause memory corruption of some sort ?

Just my 2 cents :-)

Sorry, I misread your response. The stack should be managed correctly. The problem is probably related to the absence of any “protocol” between the pc and the sketch. Try using “\n” as an end-of-command marker.

HTH

I will try it tomorrow and report :) My goal is to avoid clearing the sting on every loop but create it in the beginning. I used another metod for keepalive and printed back to Serial a test string in the middle of the loop and it worked. Only the string serial_input was empty.

Ok.

Just curious, what's wrong with clearing the string every time ?

Nothing but I dont like global variables. I prefer to use them only when its really needed.

You'll get a new string for each invocation of the loop, right? Are you doing anything to make the old string go away?

IMO, Strings are a bad idea when you only have 2k of RAM and no operating system to complain to if you run out. And the Arduino implementation of Strings has bugs.

You'll get a new string for each invocation of the loop, right? Are you doing anything to make the old string go away?

Does this mean that String does not have a destructor called for each iteration of the loop?

And is it possible to declare it static?

Does this mean that String does not have a destructor called for each iteration of the loop?

Oh. I guess it could have done that automatically. I don’t know. I’m mostly a C kind of person…
(from looking at the disassembly, it looks like it does…)

Hmm i hope it has a destructor. Well is it better to use char arrays instead of String?

Let’s see if placing a String on the stack causes any problems.

int ledPin = 13;

int count = 0;
int flag = 0;

void setup() {
    Serial.begin(115200);
    pinMode(ledPin, OUTPUT);
}


void loop() {
    // the String object is placed on the stack of loop()
    String stringOnStack;
    
    // let's use it somehow
    for (int i=0; i < 100; i++) {
        stringOnStack += 'k';
    }
    
    // let the world know we're alive
    count++;
    if (count % 500 == 0) {
        count = 0;
        digitalWrite(ledPin, flag);
        flag = !flag;
        Serial.println(millis() / 1000);
    }

    // auto-variables get destroyed automatically when the function ends
}

It’s running since 8 minutes right now and it doesn’t show any problems.

And is it possible to declare it static?

If you'd declare it static, then you'd need to explicitly clear it at every loop() invocation, which is what the OP was trying to avoid, IIRC.

Later today I will undo the code to the state it was and post it here.

Hi guys,
The sketch now works with String declared inside the loop. I tried to undo it to the state that freezes but without success :slight_smile:
Is the difference between String and char array big for memory usage? Should I use array instead? What worries me is that I cannot predict how long string the phone will send. Can I use something like this:

  if (phone.available() > 0) {
    char phone_string[MAXLENGTH];  //MAXLENGTH is for example 50
    char inChar; // Where to store the character read
    int index = 0; // Index into array; where to store the character
    while(phone.available() > 0) {
      if(index < MAXLENGTH-1) {// One less than the size of the array
          inChar = phone.read(); // Read a character
          phone_string[index] = inChar; // Store it
          index++; 
          phone_string[index] = '\0';
      }
    }
    Serial.println(phone_string);

    delay(200);    
    for (int i = 0; i < MAXLENGTH; i++) { // reset the array
      phone_string[i] = '\0';
    }
  }

The phone sends responses for example:OK, but sometimes the response is more that 50 chars. CR and LF are actually chars 10 and 13.
Thanks!

I wrote an app for a PIC18 custom board that talked to a remote PC via SMS (using a GSM modem via rs232). IIRC the standard defines a maximum length for the SM. Anyway, what I did to properly determine the size of the string buffers involved was write some test code with very large buffers and "measure" the length of the strings that came from the modem. That gave me an idea of what we could call the "protocol overhead". The SM text was used to transport a custom ascii protocol that I was defining, thus I knew exactly the max number of chars that I could expect. These tests gave me the maximum string length that I had to be able to handle for the app to work in all cases. Any longer messages could be safely discarded as wrong. (Of course I also read the dev spec of the modem, but let's not state the obvious).

HTH