Passing an array of char to the constructor of a class, to use it later

Hello everybody

Coming from Java, I'm new to the world of C++. I can't figure out if the problem that I get is something evident for somebody used to C++ programming of if I got into some bizarre Arduino specific problem. Here is my code : I want to send an ascii buffer to a class, which stores it as a pointer, and later do something (print...) with this buffer.

class MessagePrinter {
  private :
    char what [] ; 
  public :
    MessagePrinter (char toPrint []) {
      what = toPrint ;
    }
    void goPrint () {
      int i = 0 ;
      while (what [i] != 0) Serial.print (what [i++]) ;
      Serial.println () ;
    }
};

MessagePrinter * message ;

void setup() {
  delay (100) ;
  Serial.begin (9600) ;
  message = new MessagePrinter ("test") ;
  message->goPrint () ;
}

void loop() {}

I get this error message :

6:12: error: incompatible types in assignment of 'char*' to 'char [0]'
what = toPrint ;
^
incompatible types in assignment of 'char*' to 'char [0]'

Can somebody help to find the cause of the error and fix it ?

When you pass an array then what is actually passed is a pointer to the array

The what variable is declared as an array of chars (not pointers to char)

Try

    char * what [] ;

Thanks for your answer. It seems that I already tried this. Anyway, I tried your mod and here is the new error ;

6:12: error: incompatible types in assignment of 'char*' to 'char* [0]'
what = toPrint ;
^
exit status 1
incompatible types in assignment of 'char*' to 'char* [0]'

char* what;

With or without a space beetween "char" and "*" gives the same result.

And..?

Same result = same error message.

Post your code please, and the error message, both in code tags.

The worst you should see is a warning, not an error.

class MessagePrinter {
  private :
    char* what [] ; 
  public :
    MessagePrinter (char toPrint []) {
      what = toPrint ;
    }
    void goPrint () {
      int i = 0 ;
      while (what [i] != 0) Serial.print (what [i++]) ;
      Serial.println () ;
    }
};

MessagePrinter * message ;

void setup() {
  delay (100) ;
  Serial.begin (9600) ;
  message = new MessagePrinter ("test") ;
  message->goPrint () ;
}

void loop() {}

6:12: error: incompatible types in assignment of 'char*' to 'char* [0]'
       what = toPrint ;
            ^
exit status 1
incompatible types in assignment of 'char*' to 'char* [0]'

See reply #3.

This should compile without error or warning.

class MessagePrinter {
  private :
    const char * what ;
  public :
    MessagePrinter (const char toPrint []) : what (toPrint) 
    {  }
...etc
class MessagePrinter {
  private :
    char* what [] ; 
  public :
      MessagePrinter (const char toPrint []) : what (toPrint) {
          what = toPrint ;
    }
    void goPrint () {
      int i = 0 ;
      while (what [i] != 0) Serial.print (what [i++]) ;
      Serial.println () ;
    }
};

MessagePrinter * message ;

void setup() {
  delay (100) ;
  Serial.begin (9600) ;
  message = new MessagePrinter ("test") ;
  message->goPrint () ;
}

void loop() {}

5:61: error: incompatible types in assignment of 'const char*' to 'char* [0]'
       MessagePrinter (const char toPrint []) : what (toPrint) {
                                                             ^
6:12: error: incompatible types in assignment of 'const char*' to 'char* [0]'
       what = toPrint ;
            ^
exit status 1
incompatible types in assignment of 'const char*' to 'char* [0]'

Seems to be worse... :slight_smile: thanks for trying to help. Does anybody have an Arduino IDE and be able to test a proposed solution and check if it compiles before posting it ?

I chose to move it out of the constructor in case dynamic allocation fails.

class MessagePrinter {
  private :
    char *what ;

  public :
    MessagePrinter () {}

    ~MessagePrinter() {
      if (what != nullptr) {
        delete what;
      }
    }

    bool setString(const char * s) {
      if (what != nullptr) {
        delete what;
      }
      size_t length = strlen(s);

      what = new char[length + 1];
      if (what == nullptr) {
        return false;
      }

      strcpy(what, s);
      return true;
    }

    void goPrint () {
      if (what != nullptr) {
        Serial.println (what);
      }
    }
};

MessagePrinter *message ;

void setup() {
  Serial.begin (115200) ;
  delay(1000);
  message = new MessagePrinter;
  if (message != nullptr) {
    if (message->setString("test")) {
      Serial.print("Success: ");
      message->goPrint () ;
    }
  }
}

void loop() {}

I know you said you came from a Java background, but I'm pretty sure even Java requires a certain attention detail.

Please, look at your code, then at reply #3, then at reply #10

Since you are using a string literal, the declaration needs to be const:

class MessagePrinter {
  private :
    const char* what;
  public :
    MessagePrinter (const char toPrint[]) { //could also be MessagePrinter (const char* toPrint) 
      what = toPrint ;
    }
    void goPrint () {
      int i = 0 ;
      while (what [i] != 0) Serial.print (what [i++]) ;
      Serial.println () ;
    }
};

MessagePrinter * message ;

void setup() {
  delay (100) ;
  Serial.begin (9600) ;
  message = new MessagePrinter ("test") ;
  message->goPrint () ;
}

void loop() {}

If all you want to do is print the char array, there is no need to create a class, passing the char* to print() will treat it as a null-terminated char array.

JiPe38:
Hello everybody

Coming from Java, I'm new to the world of C++. I can't figure out if the problem that I get is something evident for somebody used to C++ programming of if I got into some bizarre Arduino specific problem. Here is my code : I want to send an ascii buffer to a class, which stores it as a pointer, and later do something (print...) with this buffer.

class MessagePrinter {

private :
    char what [] ;
  public :
    MessagePrinter (char toPrint []) {
      what = toPrint ;
    }
    void goPrint () {
      int i = 0 ;
      while (what [i] != 0) Serial.print (what [i++]) ;
      Serial.println () ;
    }
};

MessagePrinter * message ;

void setup() {
  delay (100) ;
  Serial.begin (9600) ;
  message = new MessagePrinter ("test") ;
  message->goPrint () ;
}

void loop() {}




I get this error message : 

6:12: error: incompatible types in assignment of 'char*' to 'char [0]'
what = toPrint ;
^
incompatible types in assignment of 'char*' to 'char [0]'

Can somebody help to find the cause of the error and fix it ?

You cannot directly write what = toPrint; in your class constructor.
Because, these are the addresses and not the chars themselves.
Actually, they point to the first elements in the chars arrays.
You can use strncpy or memcpy.
Basically, what you should do is iterate through the elements of the toPrint array and copy them to what elements, assuming they both have the same size.
Also, good practice recommends to declare are the source char arrays as Constant.

JiPe38:
With or without a space beetween "char" and "*" gives the same result.

For c compiler they are both the same.

@david2018 : OK it works fine. Thank you for the fix. Of course this program is just to isolate the problem, in the real stuff the ascii (and other things) are passed to a class which writes to a distant display through a bus, and writing to the bus is done concurrently with other tasks, and a task in my organization is a class.

@gfvalvo : thanks for this interesting suggestion. Could you elaborate on the fact that you don't pass any parameter to the constructor, creating a "setString" method, and the role of this second constructor with the "~" sign before it's name ?
Are these two choices linked together ?

@abdelhmimas : thank you for this explanation. Going from java to C++ is a pain, like going from a modern car to one where ignition advance must be adjusted by a knob on the dashboard. :frowning:

and the role of this second constructor with the "~" sign before it's name ?

It's not a constructor - it is the exact opposite, a destructor.

JiPe38:
@gfvalvo : thanks for this interesting suggestion. Could you elaborate on the fact that you don't pass any parameter to the constructor, creating a "setString" method, and the role of this second constructor with the "~" sign before it's name ?
Are these two choices linked together ?

Rather than saving a pointer to the passed string, the code I posted makes a copy of the string. I did this because you don't know what the user might supply as the string in your original code. If it's a local stack variable, it will cease to exist after the containing function ends and the pointer will no longer be valid. In fact, that memory will probably be used for something else. Run this example and watch what happens:

class MessagePrinter {
  private :
    const char *what;
  public :
    MessagePrinter (const char *toPrint){
      what = toPrint;
    }
    void goPrint () {
      Serial.println(what);
    }
};

void createObject();
void printObject();

MessagePrinter * message ;

void setup() {
  Serial.begin (115200) ;
  delay(1000);
  createObject();
  printObject();
  message->goPrint () ;
}

void loop() {}

void createObject(){
  char string[] = "Hello World";
  message = new MessagePrinter(string);
  message->goPrint ();
}

void printObject(){
  char string[] = "Goodbye World";
  Serial.println(string);
  message->goPrint();
}

My code used dynamic allocation to get the memory to store the copy in. That may fail and return nullptr. The user needs to know this. But, you can't return a value from the constructor. So, I made a separate function that returns a bool for pass / fail.

~MessagePrinter() is the destructor. It cleans things up when the object's lifetime expires.