1

I'm trying to learn how to use a class to hold multiple values and return an instance from a function. The other option is to use global variables, which is probably simpler, but I'd like to learn classes in C++.

The only thing that's giving me trouble is assigning to the string field from the constructor parameter. I've tried several variations of this code, and none of it compiles.

This is the error I currently get:

In constructor 'RelayInfo::RelayInfo(int, char*)': 17: error: incompatible types in assignment of 'char*' to 'char [20]'

It's been a long time since I've dealt with pointers and such in C.

//The RelayInfo class only has public fields and a constructor. 
//Its only purpose is to hold these values.
class RelayInfo
{
  public:
    RelayInfo(int pin, char message[20]);
    int Pin;
    char Message[20];
};

RelayInfo::RelayInfo( int pin, char message[20] )
{
  Pin = pin;
  Message = message*;
}

void setup() {  
  pinMode(13, OUTPUT);
  digitalWrite( 13, LOW );
}

void loop() {

  //Construct an instance of the class:
  RelayInfo info( 13, "Hello, World!" );

  //Use the fields from the class.
  if( info.Message == "Hello, World!" )
  {
    digitalWrite( info.Pin, HIGH );
  }  
}
0

2 Answers 2

1

The definition needs to be:

RelayInfo( int pin, char* message );

or even better:

RelayInfo( int pin, const char* message );

EDIT:

Also, you should probably use:

strncpy() for copying the char pointer.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! That worked. You can see my new code below as an answer. Is there a way to avoid dynamically allocating the string field? I tried a couple of things, but got compilation errors. Since the maximum string length will be known, I theoretically could use a fixed length char array as the field that's long enough for all possible strings, but I'm not sure.
See my below comment on your solution.
0

Based on PDizzle745's suggestions, here is what I came up with:

class RelayInfo
{
  public:
    RelayInfo(int pin, const char* message);
    ~RelayInfo();
    int Pin;
    char* Message;
};

RelayInfo::RelayInfo( int pin, const char* message )
{
  Pin = pin;

  //Allocate enough memory for copying the input string.
  Message = (char*) malloc( strlen(message) * sizeof(char) + 1 );

  //Copy the input string to the class's field.
  strcpy( Message, message );
}

RelayInfo::~RelayInfo(void)
{
  free( Message );
}

void setup() {
  pinMode(13, OUTPUT);

  digitalWrite( 13, HIGH );
  delay(1000);
}

void loop() {

  RelayInfo info( 13, "Hello" );

  if( strcmp( info.Message, "Hello" ) == 0 )
  {
    digitalWrite( info.Pin, LOW );
  }
}

7 Comments

You can keep char Message[20] member, you just can't pass it as an array as you were trying to do. Also you're going to have a memory leak if you don't free that memory back up!
Also as someone stated in comments, if you don't know the size of the string being passed, you should probably use std::string.
Re: memory, you mean adding a destructor that frees up the array? I added that. Does it look good? Regarding std::string. Is that a string class? Most people in the Arduino community advise against using that due to the severe memory limitations of the Arduino (2k RAM).
Since you're avoiding std::strings for memory, remember char arrays are null terminated, so your line strlen(message) * sizeof(char) will need to be (strlen(message) * sizeof(char))+1 to make sure you have enough space for that null terminator. Also, maybe use free() since you're using malloc() instead of new.
Thanks. I read up on free() versus delete and changed the code to use free(). Regarding the strlen, that doesn't include the null? The code works as-is. If I print the value of Message to the Serial port, the string "Hello" comes through and doesn't overrun into junk data. Is that just luck because the following byte in RAM happens to be NULL?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.