Problem concatenating string

Hi,

I copied a code snippet from another arduino program that works and when I put the code snippet in the new program and run, the postRequest string gets empty, I made several tests trying to concatenate in different ways and using postRequest.concat() more I did not succeed, sometimes I concatenated only part of the code or skipped a part ... I've been doing this for hours and I do not know how a code can work in one program and another not, so I come here to ask for help for you .

The string concatenation looks like this:

String postRequest = 
  "POST " + uri + " HTTP/1.1\r\n" +
  "Host: "+server+"\r\n" +
  "Accept: *"+"/"+"*\r\n" +
  "Content-Length: " + data.length() + "\r\n" +
  "Content-Type: application/x-www-form-urlencoded\r\n" +
  "Cache-Control: no-cache\r\n" +
  "\r\n"+data;

What can be wrong with this string that works in one program but does not work in another?

Do it one bit at a time. print the result. When it goes wrong you found it!

But you do not need to create one long string before sending it, you can send it one bit at a time.

Mark

Try:

String postRequest = ""; // simple constructor
postRequest =
"POST " + uri + .........

In many, with some saying most cases, you will subject yourself to misery using "String" on an Arduino. This is especially true on Uno class boards since using dynamic memory allocation on a processor with 2048 bytes of ram with any non-trivial program is destined to fail... the bigger your program gets and the more string manipulation you do, the faster it fails. It fails silently, too, since the class does not implement an error handler.

Because the String class uses dynamic memory allocation, you end up fragmenting the ram memory and sooner or later (usually sooner) you run out of contiguous blocks in which to fit your strings. You'd do far better to use arrays of chars. As in "char buffer[120];" and use the standard C functions for string handling. The resulting source isn't as pretty but it will work!

Because the String class uses dynamic memory allocation, you end up fragmenting the ram memory and sooner or later (usually sooner) you run out of contiguous blocks in which to fit your strings.

Err, a String may or may not use dynamic memory. Popular opinions here says it dies not?. Use of the heap does not lead ti memory fragmentation.

Nothing that to op was doing (including the use if String) would lead ti fragmentation!

As in "char buffer[120];" and use the standard C functions for string handling. The resulting source isn't as pretty but it will work!

You tell the op is is wrong to waste memory with string and then just waste a large %age of an uno's memory!

Mark

holmes4:
You tell the op is is wrong to waste memory with string and then just waste a large %age of an uno's memory!

I am perfectly happy when I have full control of the waste and am not wondering (as one Airbus pilot said to the other) "What's it doing now?"

...R
cstrings - char arrays terminated with 0.

If possible you should build the POST by printing, not concatenation.
A serial stream automatically concatenates, no reason to do this twice.

You should try to avoid Strings on 8 bit AVRs.
If uri never changes it could be placed in PROGMEN like the other constant strings,
joining the first two constants and simplifying the output code.

const char ptPost[] PROGMEM = "POST ";
const char ptHost[] PROGMEM = " HTTP/1.1\r\nHost: ";
const char ptAcce[] PROGMEM = "Accept: */*\r\nContent-Length: ";
const char ptCont[] PROGMEM = "Content-Type: application/x-www-form-urlencoded\r\nCache-Control: no-cache\r\n";

#define CF(x) ((const __FlashStringHelper*)x)

String data = "this is my text";
char uri[] = "/Test/takeData";
char server[] = "192.168.2.99";

void setup() {
  Serial.begin(250000);
  Serial.print(CF(ptPost));
  Serial.print(uri);
  Serial.print(CF(ptHost));
  Serial.println(server);
  Serial.print(CF(ptAcce));
  Serial.println(data.length());
  Serial.println(CF(ptCont));
  Serial.print(data);
}

void loop() {}
POST /Test/takeData HTTP/1.1
Host: 192.168.2.99
Accept: */*
Content-Length: 15
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

this is my text

holmes4:
Err, a String may or may not use dynamic memory. Popular opinions here says it dies not?.

I don't know what popular opinion you are referring to, because String does use dynamic memory (here and here).

Use of the heap does not lead ti memory fragmentation.

By definition, it is the only thing that leads to memory fragmentation; it is a result of allocating and freeing chunks of the heap (aka dynamic memory).

Nothing that to op was doing (including the use if String) would lead to fragmentation!

Actually, that one statement makes 20 allocations, requesting a total of at least 1000 bytes (not all in use at once). More, depending on the uri, server and data lengths.

You tell the op is is wrong to waste memory with string and then just waste a large %age of an uno's memory!

Using String adds at least 1600 bytes of program space, plus 10 more bytes per String variable.

* The original snippet uses ~4700 bytes of program space and 390 bytes of RAM. After building the String, the heap contains 3 chunks: 196 bytes unused (a "hole"), 150 bytes used (the final POST request), and the unused remainder of the heap.

* Whandall's good example, with one String usage and incremental printing, uses 4250 bytes of program space, 292 bytes of RAM (16 used in heap).

* The char-only version below uses 2762 bytes of program space and 348 bytes of RAM (120 for array).

Which ones waste memory?

Here's an excellent blog post by Majenko. More gory details here. We're not making this up... the industry has long recognized this problem.

Cheers,
/dev


char-only version of Whandall's sketch:

const char ptPost[] PROGMEM = "POST ";
const char ptHost[] PROGMEM = " HTTP/1.1\r\nHost: ";
const char ptAcce[] PROGMEM = "Accept: */*\r\nContent-Length: ";
const char ptCont[] PROGMEM = "Content-Type: application/x-www-form-urlencoded\r\nCache-Control: no-cache\r\n";

#define CF(x) ((const __FlashStringHelper*)x)

char data[120] = "this is my text";
char uri[] = "/Test/takeData";
char server[] = "192.168.2.99";

void setup() {
  Serial.begin(9600);
  Serial.print(CF(ptPost));
  Serial.print(uri);
  Serial.print(CF(ptHost));
  Serial.println(server);
  Serial.print(CF(ptAcce));
  Serial.println(strlen(data));
  Serial.println(CF(ptCont));
  Serial.print(data);
}

void loop() {}

Thanks for all the information you posted, I learned a lot!
I noticed the IDE log when I ran the program and saw that the amount of startup memory was low and it would probably be smaller, so I researched a way to monitor memory usage and keep track of what happens with this function:

int freeRam () {
  Serial.print("Free SRAM in bytes: ");
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

I also searched on the use of "const PROGMEM", seems to be one of the best ways to save memory, so all I have to string I created a char [] PROGMEM and actually decreased the amount of memory.

But I'm having problems with string and char, I wonder if there is a way to do something like this:

Char textPost [] = CF (constChar) + "add Information";

Has as ?
I researched and did not find anything that would help, I do not know if I researched the wrong way or if there really is not!

Have a look at the library functions that support PROGMEM data:

http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

holmes4:
Err, a String may or may not use dynamic memory. Popular opinions here says it dies not?

Sooooo.... String objects have some magic source of RAM to draw from? The character buffer in String objects can ONLY from from "dynamic memory", aka the heap.

holmes4:
Use of the heap does not lead ti memory fragmentation.

Use of the heap does not automatically lead to memory fragmentation, but it certainly CAN, and use of the heap is, by definition, the ONLY way to cause memory fragmentation. What memory does the term "memory fragmentation" refer to if NOT the heap??

Regards,
Ray L.

I wonder if there is a way to do something like this:

Your question is about "concatenating" C strings, but I'd like to ask if you really need to concatenate the C strings. It is very likely that you can use the pieces, just like the way they were printed in my previous post. I hope you can just do this:

  Serial.print( F("constChar") );
  Serial.print( anInt );  // add Information
  Serial.print( ',' );
  Serial.print( charArray ); // NUL-terminated C string in RAM
  Serial.print( '=' );
  Serial.println( aFloat );

Serial isn't the only thing you can print to. You can use the same approach with most other devices/libraries (LCD, SD files, Ethernet, etc.). If you're not sure how to do something, tell us more about what you have and what you're trying to use.

Regarding concatenation: The first "concatenation" is just an assignment or "copy". The next piece is concatenated to the first piece. Here's a snippet from a GPS sketch that shows a few techniques:

     char  text[60]; // a little bigger than 2+21+6+7+6=42 and 6 commas and a zero byte at the end (49 chars total)
      char *ptr = &text[0]; // This is the append point for each piece

      // Satellites (2 chars)
      
      itoa( fix.satellites, ptr, 10 ); // write an int at the beginning of text[]
      ptr = &ptr[ strlen(ptr) ]; // step to the end of the satellites chars

      *ptr++ = ',';  // append a comma and step 1

      dtostrf( fix.longitude(), 8, 6, ptr ); // write a float
      ptr = &ptr[ strlen(ptr) ];

      *ptr++ = ',';

The basic idea is to declare an array that's big enough to hold the result, then use the C string functions and pointers to fill the array, stepping along as you put each piece into the array.

Here are the C string functions. Quite a list, no? Some decent summaries of C string (not String) functions are here and here.

Again, it is usually more efficient to hold onto int and float variables until it's time to print them, one at a time. You may never need a concatenated "message" or the string version of a number.

Cheers,
/dev