Error when concatenating two long Strings

Hi, I have problem with concatenating two long Strings. String "tmp" should contain "a9993e364706816aba3e25717850c26c9cd0d89d" for input "abc", but contains only "a9993e364706816aba3e2". When I try add "tmp" to "stringData" it doesn't work.
In RS-232 output:

a9993e364706816aba3e2
?btn1=OFF&btn2=ON&sha1=

My code:

void loop() {
  int buttonState1 = digitalRead(inputButton1);
  int buttonState2 = digitalRead(inputButton1);
  
  String stringData = String(200);
  stringData = "";
  
  stringData.concat("?btn1=");
  if (digitalRead(inputButton1) == HIGH) 
    stringData.concat("ON");
  else
    stringData.concat("OFF");
 
  stringData.concat("&btn2=");
  if (digitalRead(inputButton2) == HIGH) 
    stringData.concat("ON");
  else
    stringData.concat("OFF");    
  
  stringData.concat("&sha1=");
  Sha1.init();
  Sha1.print("abc");  
  uint8_t *hash = Sha1.result();
  int i;
  String tmp = String(100);
  tmp="";
  for (i=0; i<20; i++) {
    tmp += "0123456789abcdef"[hash[i]>>4];
    tmp += "0123456789abcdef"[hash[i]&0xf];
  }
  Serial.println(tmp);
  stringData.concat(tmp);

  char stringToSend[200];
  stringData.toCharArray(stringToSend, 200);
  Serial.println(stringToSend);
}

Please help me.

  String tmp = String(100);

That does not create a 100 byte string, it creates a string containing "100".

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software

Pretty much all your code can be replaced with a sprintf() call and one single char array instead of messing with the String object. I certainly wouldn't recommend using Strings (even with Nick's recommended fixes [btw, I bet you have that as a macro key now don't you Nick? :wink: ]) on a board that only has a few KiB of RAM. On the Due it's fine, but certainly not on anything smaller.

char stringToSend[70];
char tmp[41];

bzero(tmp, 41);

for (i=0; i<20; i++) {
    tmp[i*2] = "0123456789abcdef"[hash[i]>>4];
    tmp[i*2+1] = "0123456789abcdef"[hash[i]&0xf];
}

sprintf(stringToSend, "?btn1=%s&btn2=%s&sha1=%s",
    digitalRead(inputButton1) ? "ON" : "OFF",
    digitalRead(inputButton2) ? "ON" : "OFF",
    tmp
);

Serial.println(stringToSend);

... or something similar.

majenko:
I bet you have that as a macro key now don't you Nick? :wink:

Perhaps. :slight_smile:

majenko:

#include <strings.h>

...
char tmp[41];
bzero(tmp, 41);
int i=0;
for (i=0; i<20; i++) {
...

When I try your code I get this error:

Client.ino: In function ‘void loop()’:
Client:60: error: ‘bzero’ was not declared in this scope

In which library is function bzero()? Where is an error?
Thank you.

I have Arduino 1.0.5 x86_64 on Linux.

If cryptic code like "btn1=%s&btn2=%s&sha1=%s"," are not your thing yet, the below String info might have easier to understand String examples to do what you want.

martin159:

majenko:

#include <strings.h>

...
char tmp[41];
bzero(tmp, 41);
int i=0;
for (i=0; i<20; i++) {
...

When I try your code I get this error:

Client.ino: In function ‘void loop()’:

Client:60: error: ‘bzero’ was not declared in this scope




In which library is function *bzero()*? Where is an error?
Thank you.

I have Arduino 1.0.5 x86_64 on Linux.

Humph... Pesky Arduino missing standard library functions...

try memset(temp, 0, 41); instead.

majenko:
try memset(temp, 0, 41); instead.

Thank you, memset works fine.

I need put buttons status to string, create hash of this string and put hash to end of string (hash(btn1=OFF&btn2=ON&sha1=)). Now I have this working code:

void loop() {
  delay(1000);  
  int buttonState1 = digitalRead(inputButton1);
  int buttonState2 = digitalRead(inputButton1);
  
  char stringToSend[70];
  char tmp[41];  
  memset(tmp, 0, 41);

  sprintf(stringToSend, "?btn1=%s&btn2=%s&sha1=",
    digitalRead(inputButton1) ? "ON" : "OFF",
    digitalRead(inputButton2) ? "ON" : "OFF"
  );

  Sha1.init();
  Sha1.print(stringToSend);  
  uint8_t *hash = Sha1.result();
  for (int i=0; i<20; i++) {
    tmp[i*2] = "0123456789abcdef"[hash[i]>>4];
    tmp[i*2+1] = "0123456789abcdef"[hash[i]&0xf];
  }
  
  sprintf(stringToSend, "%s%s", stringToSend, tmp );
  Serial.println(stringToSend);
}

Output is ok:

?btn1=OFF&btn2=ON&sha1=65737ac78f075de8e67a5baa0cfd9eacbedc3e1a

Is it good, or I have inefficient and complicated code?

Instead of the second sprintf you could use strcat:

strcat(stringToSend, tmp);