Can't use Serial.print for a string but can for String

So in the code below I get the error
error: 'mystr' was not declared in this scope
mystr +=c;

If I run the code is another IDE ( platoformIO ) I get
no suitable user-defined conversion from "String" to "std::__cxx11::string" (aka "std::__cxx11::basic_string<char, std::char_traits, std::allocator>") existsC/C++(312)
Basically I'm tring to convert String to string without success. So if anyone can help with this it would be MASSIVELY appreciated. Have tried many google searches but can't figure out how to do it, maybe it's not even possible :slightly_frowning_face:

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <string.h>
#include <fastled_config.h> 
#include <iostream>

void setup() {
 handleMorse();
}

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

}
void handleMorse() {
  String message = "my test message";
  
  Serial.println( message );
  string mystr = "";  // note this is string & NOT String

  for (int i = 0; i < message.length(); i++) {
    char c = message.charAt(i);
	mystr +=c; // error here
    if (i< 8)
    Serial.print (c);
  }
  Serial.print (mystr);  // error

 
}

Why are you using strings and/or Strings ?

Why not stick to good, old fashioned C style zero terminated arrays of chars ?

  • need Serial.begin()
  • it's String not string
// #include <WiFi.h>
// #include <WebServer.h>
// #include <ArduinoJson.h>
// #include <string.h>
// #include <fastled_config.h>
// #include <iostream>

void setup() {
    Serial.begin (9600);
    handleMorse();
}

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

void handleMorse() {
    String message = "my test message";
    Serial.println( message );

    String mystr = "";  // note this is string & NOT String

    for (unsigned i = 0; i < message.length(); i++) {
        char c = message.charAt(i);
        mystr +=c; // error here
        if (i< 8)
            Serial.print (c);
    }
    Serial.print (mystr);  // error
}

using char arrays

void setup() {
    Serial.begin (9600);
    handleMorse();
}

void loop() {
}

void handleMorse()
{
    const char *message = "my test message";
    Serial.println( message );

    char  mystr [90];
    unsigned i;
    for (i = 0; i < strlen (message); i++) {
        mystr [i] = message [i];
        if (i < 8)
            Serial.print (mystr [i]);
    }
    mystr [i] = '\0';       // terminate string with NUL
    Serial.println ();

    Serial.print ("mystr: ");
    Serial.print (mystr);
}

The reason I'm using string & String is because I'm receiving code from a app which comes in as a String but I've written code in visual studio which takes a string & I didn't actually realise at the time that they were 2 different types ( easy mistake for a noob like me ).

does this mean 1) you're copying "code" from another app or 2) you're receiving data from another app over a serial or some other interface?

wouldn't the data be ASCII chars that can be copied into either a String or char array?

'string' is not a valid data type at all

void setup() {
  string mystring = "hi";
}

void loop() {
}

does not compile !

1 Like

Yes to both - Im copying code to arduinoIDE from what i've written in visual studio ( easier because of intellisense & being able to output results to a console for debugging ). I am also receiving data from a app over wifi using http_post ( from app).

WebServer server(80);

// in setup
server.on("/morse", HTTP_POST, handleMorse);

void handleMorse() {
  String message = server.arg("message");
  Serial.println("Received message: " + message);
  

  for (int i = 0; i < message.length(); i++) {
    char c = message.charAt(i);
    if (i< 8)
    Serial.print (c);
  }
  
}

Your right 'string' is not a valid data type at all in ardino IDE & platoformIO , but it is in visual studio Code ( c++)

not sure what this is saying, don't understand why a string is being passed as an argument to a function returning a string. Is the returned value "message"

i'm sure you can receive char array strings from via Wifi

i'm passing a c-string to a WiFi routine

void
wifiSend (
    const char*  msg )
{
    if (ST_UP != state)
        return;

    if (dbgWifi)  {
        printf ("wifiSend: %s\n", msg);
    }

    udp.broadcast (msg);
}

are you saying visual studio didn't flag this as an error, or are you just using visual strudio as an editor

Hi @dazz700 ,

I understand that your main interest is to convert a String object into a zero or null terminated array of char.

The String class provides a function for this:

https://www.arduino.cc/reference/tr/language/variables/data-types/string/functions/c_str/

It's the ambiguity of the word "string" that often leads to misunderstanding:

https://en.m.wikipedia.org/wiki/Null-terminated_string

Hi @gcjr ,

if you look up the header file

https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/src/WebServer.h

you'll find this as functions of the class WebServer:

  String arg(const String &name) const;                                         // get request argument value by name
  String arg(int i) const;                                                      // get request argument value by number
  String argName(int i) const;

Assuming that the TO is using this library it explains the use of the String class.

The reason for using a String object to get another one in return is this:

String WebServer::arg(const String &name) const {
  for (int j = 0; j < _postArgsLen; ++j) {
    if (_postArgs[j].key == name) {
      return _postArgs[j].value;
    }
  }
  for (int i = 0; i < _currentArgCount; ++i) {
    if (_currentArgs[i].key == name) {
      return _currentArgs[i].value;
    }
  }
  return "";
}

The arg functions iterates through an array similar to "JSON" where _postArgs points to structs of type RequestArgument

struct RequestArgument {
    String key;
    String value;

As it's for an ESP32 the developers don't take much care about avoiding String objects ...:wink:

No it didnt flag up string as a error, I've ran the code many times with no problems.

I like to mention that there's an alternative function

https://docs.arduino.cc/language-reference/de/variablen/data-types/stringObject/Functions/toCharArray/

to convert the text content of a String object to an array of characters.

If you use the c_str() function you must take care of this

When you modify the String object, or when it is destroyed, any pointer previously returned by c_str() becomes invalid

To be safe you should always copy the content to an independent array of char.

I use it the same way.
if the argument to the function is

"message"

then the function returns

?message=thismessage
"thismessage"

Usually one would do all the parsing before the new webpage is being created but some precautions with regards to possible fragmentation should be observed.
If you store the returned String in a String then it is probably a good idea to reserve() sufficient space for it.
Still this is all happening in the callback and once the callback function is exited all String objects are destroyed and all memory will be released.

server.arg() is returning a String object by value. So, it will be a temporary, and hence an rvalue. So, this will invoke the String class's move constructor:

So there will not be another buffer allocated for the local String variable anyway. Rather it will take over the rvalue's buffer.

I’m curious as to whether visual studio is not case sensitive, and regards string and String as identical?

See: https://en.cppreference.com/w/cpp/string/basic_string

std::string is a typedef for std::basic_string<char>

EDIT:
But that doesn't explain how it compiles without:
std::string mystr = "";

Yes that is true, but since the passed argument is created beforehand, the returned String will be created further along the heap. in this scenario

String outputString = "The returned value of the HTML Argument is : ";
outputString += server.arg("message");

The object 'outputString' will be moved because there is not enough space in the original location to create the concatenated String, because both the temporary "message" as well as the return String are created after the original String. As far as i know there is no real way to prevent that fragmentation unless there is sufficient space in the String.
If all the date from the return String is discarded before anything is added to the original String there may be no problem, and even if the String is kept in tact and used for instance in a filename or something and then used it is also Ok. (in my case that is what usually happens, most of the HTML arguments are numeric values and get converted before processing)
Another option could be to convert the return String to a c-string and let the returned String go out of scope before adding it to outputString, or allocate space beforehand.

outputString.reserve(outputString.length() + MAX_MSG_LENGTH)

Of course as stated before once the callback is exited the whole thing goes out of scope and the issue does not exist anymore

Also in Arduino IDE 2.x