Problem with function returning String

I have a bit of code:

String urlDecode(String input)
{
 
  input.replace("%20", " ");
  input.replace("+", " ");
  input.replace("%21", "!");
  input.replace("%22", "\"");
  input.replace("%23", "#");
  input.replace("%24", "$");
  input.replace("%25", "%");
  input.replace("%26", "&");
  input.replace("%27", "\'");
  input.replace("%28", "(");
  input.replace("%29", ")");
  input.replace("%30", "*");
  input.replace("%31", "+");
  input.replace("%2C", ",");
  input.replace("%2E", ".");
  input.replace("%2F", "/");
  input.replace("%2C", ",");
  input.replace("%3A", ":");
  input.replace("%3A", ";");
  input.replace("%3C", "<");
  input.replace("%3D", "=");
  input.replace("%3E", ">");
  input.replace("%3F", "?");
  input.replace("%40", "@");
  input.replace("%5B", "[");
  input.replace("%5C", "\\");
  input.replace("%5D", "]");
  input.replace("%5E", "^");
  input.replace("%5F", "-");
  input.replace("%60", "`");
 
  return input;
 
}

It causes a compile error:

spark/compile_server/shared/workspace/worker_2/core-firmware/build/lcd.cpp:535: undefined reference to `String::String(String&&)'
collect2: error: ld returned 1 exit status
make: *** [162ed70d8046dc5878194192c1c6e87fbd4fa441f4f0b038ed4a33e8043b.elf] Error 1

I’m not exactly sure why.

Here is the entire file: https://gist.github.com/huslage/9233323

Yes I pasted the entire LiquidCrystal library into the top of the file. I couldn’t get the external files to compile for some reason and this is such a simple piece of firmware I really didn’t care.

The firmware just has a Spark.function() to put text on a screen. There will be a web app that pushes text to the LCD when a button is pressed. This function is meant to remove the URL Encoding from the submitted text.

Change line 498 to:

void urlDecode(String &input)

and define:

String input;

Maybe this works but you have to try it out :smile:

string urlDecode(String &input)

kennethlimcp, good catch. I missed that one. :smile:

Returning String datatype may not be an ideal practice (correct me if I’m wrong). As @kennethlimcp suggested, try this:

int surf(String args) {
  lcd->clear();
  //tring decoded;
  //decoded=urlDecode(args);
  urlDecode(args);
  lcd->print(args);
  return 1;
}
 
void loop() {
  Spark.function("surf",surf);
}
 
void urlDecode(String &input)
{
  input.replace("%20", " ");
  input.replace("+", " ");
  input.replace("%21", "!");
  input.replace("%22", "\"");
  input.replace("%23", "#");
  input.replace("%24", "$");
  input.replace("%25", "%");
  input.replace("%26", "&");
  input.replace("%27", "\'");
  input.replace("%28", "(");
  input.replace("%29", ")");
  input.replace("%30", "*");
  input.replace("%31", "+");
  input.replace("%2C", ",");
  input.replace("%2E", ".");
  input.replace("%2F", "/");
  input.replace("%2C", ",");
  input.replace("%3A", ":");
  input.replace("%3A", ";");
  input.replace("%3C", "<");
  input.replace("%3D", "=");
  input.replace("%3E", ">");
  input.replace("%3F", "?");
  input.replace("%40", "@");
  input.replace("%5B", "[");
  input.replace("%5C", "\\");
  input.replace("%5D", "]");
  input.replace("%5E", "^");
  input.replace("%5F", "-");
  input.replace("%60", "`");
 
}
1 Like

Also noticed that your Spark.function call is inside your loop, I think that should live in setup?

void loop() {
  Spark.function("surf",surf);
}
1 Like

That seems to have fixed things. Why is returning a String a bad idea exactly?

Hi @huslage

Arduino Strings are objects and that means they are not small and easily passed around like the built-in datatypes such as int or char or byte, but are instead big things in memory that have to be handled differently. So the way we pass them around to functions that want to change them has to be different. It is easy to have bad memory problems and crashes if you don’t handle these right.

If you want read more about this, web search for “C++ call by reference” versus “call by value”.

2 Likes

This is where i read to come up with the possible solution :slight_smile:

http://forum.arduino.cc/index.php?topic=73078.0

1 Like

Hi @bko
So you are saying instead of returning String s (as it is an object) if I return something like Char *s or Char s[10] (Array of few characters) then that will not cause the memory issue??

1 Like

HI @bijay

You should read up on call by reference versus call by value in C/C++ first if you are not up to speed on that. Then you need to consider the memory needs on the Spark core which has limited resources.

On Spark, you can allocate dynamic memory which is what creating a String object in an automatic variable does and then return it, but if you later need to free up that memory, it is difficult and can lead to subtle bugs. So a better plan for embedded processors like Spark is to avoid using things that allocate dynamic memory as much as possible and use static allocation whenever you can.

Normally in C if you want to return a char* array, you pass a pointer to it in to a function as an argument and modify it in place rather than returning a value. A good example to look at is strcpy() but there a lots of others.

1 Like