Dynamically allocate array in class

Hello everyone! I am trying to dynamically allocate an array located in a class using a method I defined. Unfortunately I got stuck in the process.
I tried to simplyfy the code to clearly show my problem. In the class I allocate the array using malloc in the constructor and in the method add_element I fill it. The method add_element get as parameters a string and the position where to put it in the array.

class myClass
{
  private:
  int arr_size;
  public:
  const String * myarr;

  myClass(int _arr_size) //Constructor
  {
    arr_size = _arr_size;
    myarr = (const String *)malloc(arr_size); //allocating the array
  }
  
  void add_element(const String *element, int pos)
  {
    myarr[pos] = element; 
  }
};

const String arr[2] = {"Obj1", "Obj2"};
myClass myclass(2); //class definition

void setup() 
{
  //filling the array
  myclass.add_element(&arr[0], 0);  
  myclass.add_element(&arr[1], 1);
}

void loop() {}

I know that it makes little sense to fill an array like that but it is part of project I am working on.
The error i get is the following:

[..]sketch_mar24a.ino: In member function 'void myClass::add_element(const String*, int)':

[..]sketch_mar24a.ino:16:16: warning: passing 'const String' as 'this' argument of 'String& String::operator=(StringSumHelper&&)' discards qualifiers [-fpermissive]

     myarr[pos] = element; 

                ^

sketch_mar24a:16: error: conversion from 'const String*' to 'StringSumHelper' is ambiguous

[..]sketch_mar24a.ino:14:34: note: candidates are:

   void add_element(const String *element, int pos)

                                  ^

In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:231:0,

                 from sketch\sketch_mar24a.ino.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:223:2: note: StringSumHelper::StringSumHelper(long unsigned int) <near match>

  StringSumHelper(unsigned long num) : String(num) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:223:2: note:   no known conversion for argument 1 from 'const String*' to 'long unsigned int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:222:2: note: StringSumHelper::StringSumHelper(long int) <near match>

  StringSumHelper(long num) : String(num) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:222:2: note:   no known conversion for argument 1 from 'const String*' to 'long int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:221:2: note: StringSumHelper::StringSumHelper(unsigned int) <near match>

  StringSumHelper(unsigned int num) : String(num) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:221:2: note:   no known conversion for argument 1 from 'const String*' to 'unsigned int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:220:2: note: StringSumHelper::StringSumHelper(int) <near match>

  StringSumHelper(int num) : String(num) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:220:2: note:   no known conversion for argument 1 from 'const String*' to 'int'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:219:2: note: StringSumHelper::StringSumHelper(unsigned char) <near match>

  StringSumHelper(unsigned char num) : String(num) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:219:2: note:   no known conversion for argument 1 from 'const String*' to 'unsigned char'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:218:2: note: StringSumHelper::StringSumHelper(char) <near match>

  StringSumHelper(char c) : String(c) {}

  ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:218:2: note:   no known conversion for argument 1 from 'const String*' to 'char'

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/WString.h:91:11: note: initializing argument 1 of 'String& String::operator=(StringSumHelper&&)'

  String & operator = (StringSumHelper &&rval);

           ^

exit status 1
conversion from 'const String*' to 'StringSumHelper' is ambiguous

Thank you for your help!

You have declared your array as a const. That means it is read-only.
Either drop the const (and fix all other references) or auto initialize the array and forget about malloc( ).
Unless you are just playing with malloc, you should forget about it anyway.

Thank you very much for your reply, i got rid of all the const but I still get the same error.

By forgetting about malloc(), do you mean not trying to allocate the array dynamically or use something else like myarr = new String * ?

fdisants:
I am trying to dynamically allocate an array located in a class...

const String * myarr;

brave soul

I'm interested to know why you would want to do this...

You need to show your new code.

...not trying to allocate the array dynamically...

Yes.

Dynamically allocating anything is risky in the small memory available on an Arduino.

...R

fdisants:
By forgetting about malloc(), do you mean not trying to allocate the array dynamically or use something else like myarr = new String * ?
[/quote]

Don't mix C and C++.
Read this.


myarr = (const String *)malloc(arr_size); //allocating the array
^^^^^^ ^^^^

  1. c - Should I cast the result of malloc? - Stack Overflow
  2. Are you sure that you need arr_size bytes? Always use the sizeof operator (e.g. arr_size * sizeof(data_type)).

You should read about malloc function:
https://linux.die.net/man/3/malloc

Thank you very much for all your replies! I am sorry to answer so late but life got in the way. :slight_smile:

Thanks to your advice a bit of thinking I managed to amend the code:

class myClass
{
  private:
  int arr_size;
  public:
  const String **myarr;
  
  myClass(int _arr_size) //Constructor
  {
    arr_size = _arr_size;
    myarr = (const String **)malloc(sizeof(const String) * arr_size); 
  }
  
  void add_element(const String *element, int pos)
  {
    myarr[pos] = element; 
  }
};

const String arr[2] = {"Obj1", "Obj2"};
myClass myclass(2); //class definition

void setup() 
{
  //allocating the array
  myclass.add_element(&arr[0], 0);  
  myclass.add_element(&arr[1], 1);
}

void loop() {}

My error was to declare myarr in the class as String *myarr and not String **myarr.
Anyway I think I am gonna follow your general advice and don't use malloc! That was more of a test .

Thank you very much!

    myarr = (const String **)malloc(sizeof(const String) * arr_size);

That is STILL wrong. Whatever you get the size of is what you need to cast the pointer that malloc() returns to a pointer to. You get the size of a String, and then cast the result to pointer to pointer to String.
One too many stars in the cast.

You are right Paul, thank you for your reply.

This might be helpful: :slight_smile:

class MyClass
{
private:
	int _arrSize;
	String *_myArr;

public:
	// Constructor
	MyClass(int arrSize) : _arrSize(arrSize)
	{
		_myArr = new String[arrSize];
	}

	// Destructor
	~MyClass()
	{
		delete []_myArr;
	}

	void addElement(const String *element, int position)
	{
		_myArr[position] = *element;
	}

	String& getElement(int position) const
	{
		return _myArr[position];
	}
};

const String array[2] = {"Obj1", "Obj2"};
MyClass myObject(2);

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

	myObject.addElement(&array[0], 0);
	myObject.addElement(&array[1], 1);

	delay(2000);

	Serial.println(myObject.getElement(0));
	Serial.println(myObject.getElement(1));
}

void loop() {}