String Fundamentals - strcat() - const char* - char array

I am having trouble understanding the differences in my following two programs. The first one runs as expected. The second one does not compile. Thank you for your help.

Compiles and runs:

const char *constchar = "with a const char*";
  
void setup() {
  char str[300];
  strcpy (str,"these ");
  strcat (str,"strings ");
  strcat (str,"are ");
  strcat (str,"concatenated ");
  strcat (str, constchar);
  puts (str);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Does not compile:

const char *webMenu   = "<ul><li><a href=\"/\">Home</a></li><li><a href=\"/blue\">Blue</a></li><li><a href=\"/blue/on\">B_ON</a></li><li><a href=\"/blue/off\">B_OFF</a></li><li><a href=\"/red\">Red</a></li><li><a href=\"/red/on\">R_ON</a></li><li><a href=\"/red/off\">R_OFF</a></li></ul>";
const char *indexHead = "<!DOCTYPE html><html><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><head></head><body>";
const char *indexFoot = "</body></html>";

void setup() {
  char buf[2048];
  buf = strcat(buf, indexHead);
  buf = strcat(buf, webMenu);
  buf = strcat(buf, indexFoot);
}

void loop() {
  // put your main code here, to run repeatedly:

}
Arduino: 1.8.9 (Windows Store 1.8.21.0) (Windows 10), Board: "ESP32 Pico Kit, 921600, None"

C:\Users\Sean\AppData\Local\Temp\arduino_modified_sketch_993858\sketch_apr07c.ino: In function 'void setup()':

sketch_apr07c:7:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   buf = strcat(buf, indexHead);

       ^

sketch_apr07c:8:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   buf = strcat(buf, webMenu);

       ^

sketch_apr07c:9:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   buf = strcat(buf, indexFoot);

       ^

exit status 1
incompatible types in assignment of 'char*' to 'char [2048]'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

The first one starts with strcpy() which (I think) puts a terminating null at the end of the copied text. I suspect that strcat() is looking for that null.

Try the second example with this addition

void setup() {
  char buf[2048];
  buf[0] = 0;      //   <-----------------------------
  buf = strcat(buf, indexHead);
  buf = strcat(buf, webMenu);

…R

Thank you Robin2, I do believe it is something to do with ‘\0’. Or it might be my escaped strings have something weird going on. I have modified code which has really got me confused, but adding the null terminator is what got it working in this following working case.

Compiles and runs:

const char *indexHead = "<!DOCTYPE html><html><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><head></head><body>";
const char *indexFoot = "</body></html>";
const char *webMenu   = "<ul><li><a href=\"/\">Home</a></li><li><a href=\"/blue\">Blue</a></li><li><a href=\"/blue/on\">B_ON</a></li><li><a href=\"/blue/off\">B_OFF</a></li><li><a href=\"/red\">Red</a></li><li><a href=\"/red/on\">R_ON</a></li><li><a href=\"/red/off\">R_OFF</a></li></ul>";

void setup() {
  
  char str[2048] = "\0";
  strcat (str,indexHead);
  strcat (str, webMenu);
  strcat (str, indexFoot);

  delay(100);
  Serial.begin(115200);
  Serial.println(str);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Does not compile:

const char *webMenu   = "<ul><li><a href=\"/\">Home</a></li><li><a href=\"/blue\">Blue</a></li><li><a href=\"/blue/on\">B_ON</a></li><li><a href=\"/blue/off\">B_OFF</a></li><li><a href=\"/red\">Red</a></li><li><a href=\"/red/on\">R_ON</a></li><li><a href=\"/red/off\">R_OFF</a></li></ul>";
const char *indexHead = "<!DOCTYPE html><html><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><head></head><body>";
const char *indexFoot = "</body></html>";

void setup() {
  char str[2048] = "\0";
  str = strcat(str, indexHead);
  str = strcat(str, webMenu);
  str = strcat(str, indexFoot);

  delay(100);
  Serial.begin(115200);
  Serial.println(str);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Error:

Arduino: 1.8.9 (Windows Store 1.8.21.0) (Windows 10), Board: "ESP32 Pico Kit, 921600, None"

C:\Users\Sean\AppData\Local\Temp\arduino_modified_sketch_368356\sketch_apr07c.ino: In function 'void setup()':

sketch_apr07c:7:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   str = strcat(str, indexHead);

       ^

sketch_apr07c:8:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   str = strcat(str, webMenu);

       ^

sketch_apr07c:9:7: error: incompatible types in assignment of 'char*' to 'char [2048]'

   str = strcat(str, indexFoot);

       ^

exit status 1
incompatible types in assignment of 'char*' to 'char [2048]'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Robin2:
The first one starts with strcpy() which (I think) puts a terminating null at the end of the copied text. I suspect that strcat() is looking for that null.

Which is irrelevant, since it does not even compile. strcat() cannoy "look" for anything, since it never runs.
The compiler is complaining about the type of buf, which makes no sense to me. But, it can at least be worked around by casting but to char * in the strcat call:

buf = strcat((char *)buf, indexHead);

Regards,
Ray L.

You can't reassign an array pointer without doing some sneaky tricks.
strcat( ) is meant to return a new pointer which you seem to not care about. You don't have to use the result of strcat( ) if you don't need a new pointer. Just use buf. It contains the result you want.

boolrules:
You can't reassign an array pointer without doing some sneaky tricks.
strcat( ) is meant to return a new pointer which you seem to not care about. You don't have to use the result of strcat( ) if you don't need a new pointer. Just use buf. It contains the result you want.

strcat does NOT return "a new pointer". strcat, along with many other str* functions, returns the SAME pointer passed to it as the first argument, as a convenience, to make it easier to "chain" the result to another str* function.

Regards,
Ray L.

Yeah, it's the same pointer but stored at another address. In that way it's a new pointer. You can't reuse buf's storage location.

Thanks guys. This gives me some more stuff to work with. I'll try using the returned pointer and it might show me where I'm assuming the wrong thing with the array.

I'm used to allocating my own space and not using an array to do that for me. Apparently it does some other things for me I don't understand very well.

This is almost certainly not doing what you think

char str[2048] = "\0";

It will place three bytes in the array with the values 92, 48 and 0

...R

Thank you all for your help. It came down to the returned pointer being the compilation error. When I stopped assigning the returned pointer to my buffer and just let strcat do its thing, the compiler was okay with it.

Specifically what RayLivingston was illuding to and boolrules stated: The following does not work because strcpy returns a char* and you cannot assign that to a char array.

//This will not compile

const char *constchar = "string here";
char charArray[20];

void setup() {
  charArray = strcpy(charArray, constchar);
}

You can however, just let strcat do what it does:

//This will compile

const char *constchar = "string here";
char charArray[20];

void setup() {
  strcpy(charArray, constchar);
}

Thank you Robin2 for spotting things for me to fix now that it compiles! After those are fixed, then I’ll see if I can jam it back into my actual project. That way we’ll be able to tell if I actually learned anything from this mess.

const char *indexHead = "<!DOCTYPE html><html><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><head></head><body>";
const char *indexFoot = "</body></html>";
const char *webMenu   = "<ul><li><a href=\"/\">Home</a></li><li><a href=\"/blue\">Blue</a></li><li><a href=\"/blue/on\">B_ON</a></li><li><a href=\"/blue/off\">B_OFF</a></li><li><a href=\"/red\">Red</a></li><li><a href=\"/red/on\">R_ON</a></li><li><a href=\"/red/off\">R_OFF</a></li></ul>";

void setup() {
  char str[2048] = "";
  strcat (str,indexHead);
  strcat (str, webMenu);
  strcat (str, indexFoot);

  delay(100);
  Serial.begin(115200);
  Serial.println(str);
}

void loop() {
}

There are a number of points in the program that makes one wonder. First, if the processor is an Uno, the string space is pretty large. What about:

const char *webMenu   = "<ul><li><a href=\"/\">Home</a></li><li><a href=\"/blue\">Blue</a></li><li><a href=\"/blue/on\">B_ON</a></li><li><a href=\"/blue/off\">B_OFF</a></li><li><a href=\"/red\">Red</a></li><li><a href=\"/red/on\">R_ON</a></li><li><a href=\"/red/off\">R_OFF</a></li></ul>";
const char *indexHead = "<!DOCTYPE html><html><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><head></head><body>";
const char *indexFoot = "</body></html>";

void setup() {
  char buf[1000];
  Serial.begin(115200);
  strcpy(buf, indexHead);
  strcat(buf, webMenu);
  strcat(buf, indexFoot);
  Serial.println(buf);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Robin2:
This is almost certainly not doing what you think

char str[2048] = "\0";

It will place three bytes in the array with the values 92, 48 and 0

...R

?