Go Down

Topic: How do I "return" a char array of unknown size from class method or function (Read 328 times) previous topic - next topic

jcmojj

I have read several posts and I didn't found an answer for my problem that is how to get and set a char array into a method of a class without knowing at programing the size of the char array. The best answer I found so far was Nick Gammon on how to send known length char array to functions. I know that I cant return an array, so I have to send an as a pointer at method argument, change the values of that array and when the method finishes I don't loose its value because the method is over and I don't waste space with static variables (that use space as it was global variable).

His code was:
Code: [Select]
void playWithArray (int (& myarray) [10] )
  {
  for (int i = 0; i < 10; i++)
     myarray [i] += 42;
  }
 
void setup ()
{
int TestArray[10]={0,0,0,0,0,0,0,0,0,0};
 
  playWithArray (TestArray);
}

void loop () {}


The problem for me with this code is that I must know the size of the array and create it. I cant declare int testArray[] and don't initialize it. It would work if i could do something like int testArray[size] = {size}; or something like it because I don't know the size of the array before the user sets the email.

What I need to do
I need to get an email, store/set it in the EEPROM by a method inside memory class. The EEPROM have 50 bytes available for this. I need also to get the email from the EEPROM with the correct '\0', in other words, I don't want to get an array of 50 bytes, but only the real size of the string recorded at the memory.

My code example:

example.ino
Code: [Select]
#include "Memory.h"
Memory memory = Memory();
setup(){
    Serial.begin(9600);
    char emailTest[] = "myemail@gmail.com";
    _memory->setUserEmail(emailTest);
    char email[50] =    // I would like to have an email not with size=50, but with size of Email at EEPROM
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    _memory->getUserEmail(email);
   Serial.print(email);

}
loop(){
}


memory.h
Code: [Select]

#ifndef Memory_h
#define Memory_h

#include "Arduino.h"
#include "Drink.h"
#include <EEPROM.h>
#define userName 50
#define userEmailBegin 0
#define userEmailEnd (userEmailBegin+userEmail-1)

class Memory{
  public:
    Memory();
    void getUserEmail(char (&email)[userEmail]);
    void setUserEmail(char (&email)[userEmail]); 
 
};


memory.ccp
Code: [Select]
#include "Memory.h"
Memory::Memory(Drink &drink, byte drinkSize){
}
void Memory::getUserEmail(char (&email)[userEmail]){
  EEPROM.begin(memorySize);
  for(byte i = 0; i<=userEmail;i++){
     email[i] = EEPROM.read(userEmailBegin+i);
  }
  EEPROM.end(); 
}
void Memory::setUserEmail(char (&email)[userEmail]){
  EEPROM.begin(memorySize);
  for(byte i = 0; (i<=userEmail)&&(email[i] != '\0');i++){
    EEPROM.write(userEmailBegin+i,email[i]);
  }
  EEPROM.end(); 
}



I don't want to use String class because I probably will have memory problem in future, so it would be useful to not use it unless it is not other way. I am using ESP8266 and Arduino. This code is for ESP, but it will compile the same way for Arduino changing little EEPROM thing.


I get this error message compiling:
Quote
Arduino: 1.8.1 (Mac OS X), Placa:"NodeMCU 1.0 (ESP-12E Module), 80 MHz, 921600, 4M (3M SPIFFS)"

example.ccp:35: error: no matching function for call to 'Memory::setUserEmail(char [17])'
   _memory->setUserEmail(emailTeste);

sketch/Memory.h:61:10: note: void Memory::setUserEmail(char (&)[50])
     void setUserEmail(char (&email)[userEmail]); 
          ^
sketch/Memory.h:61:10: note:   no known conversion for argument 1 from 'char [17]' to 'char (&)[50]'
exit status 1
no matching function for call to 'Memory::setUserEmail(char [17])'
I would appreciate Nick Gammon or PaulS answers as they have the best answers to all post since they are clear giving fast and helpful examples.

J-M-L

Read about malloc() (and associated free()) to dynamically allocate and deallocate dynamic memory. That will survive the end of the function (but has other consequences with small micro controllers with limited RAM, so we sometimes prefer a static array "big enough" to ensure you are always on top of what is happening at run time)


Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums
Pas de messages priv├ęs SVP

pert

Add a function to Memory that returns the required size of the buffer array that must be passed to getUserEmail():
Code: [Select]
char emailBuffer[memory.available() + 1];  //+1 for terminator
memory.getUserEmail(emailBuffer);


char email[50] =    // I would like to have an email not with size=50, but with size of Email at EEPROM
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};[/code]
There's no need to initialize the array like that and this could easily lead to a bug if you get the count wrong and go past the end of the array. An uninitialized local array will contain random values but that doesn't matter, just make sure your code always properly terminates the string.

Code: [Select]

    void getUserEmail(char (&email)[userEmail]);
    void setUserEmail(char (&email)[userEmail]);  

All you need is:
Code: [Select]

    void getUserEmail(char email[]);
    void setUserEmail(const char email[]);

The const is not strictly necessary but it's best practices since setUserEmail() is not intended to alter email[].

Go Up