[SOLVED] String vs Char Array

I am writing a clock program that constructs the current date as a string to scroll across a 16x8 led matrix. The code seems to be working fine but I have read posts that suggest avoiding String() as it fragments memory. Am I likely to find the clock crashing after days/weeks of continual use? A possible solution would be to use a char array but what would be the best solution to replicate String() functions below as copying them from PROGMEM complicates things. I'm no C++ programmer and do not fully understand the syntax for using pointers though I grasp the principal.

// Display Date
void doDate2(){
    String myDate;

    RTC.readClock();                                      //Read clock
    // DayOfWeek
    int x = RTC.getDayOfWeek();
    myDate=CopyProgmemMessage((prog_uchar*)pgm_read_word(&(day_table[x-1])));
    // Day
    x = RTC.getDate();
    myDate += String(x,DEC);
    myDate += " ";
    // Month
    x = RTC.getMonth();
    myDate +=CopyProgmemMessage((prog_uchar*)pgm_read_word(&(month_table[x])));
    // Year
    x = RTC.getYear();
    myDate += "20";
    myDate += String(x,DEC);
    myDate += "  \0";

    scrollRamMessage(myDate);
}
// Display Temperature
void doTemperature(){
    String myTemp =" Its ";
    float temperature=RTC.getTemperature();	//Read clock
    myTemp += String(lround(temperature));
    myTemp += ".";
    temperature = (temperature-floor(temperature))*100;
    myTemp += String(lround(temperature));
    myTemp += (char) 0x7f;
    myTemp += "  \0";
    scrollRamMessage(myTemp);
}
// Copy zero terminated string from program memory into String variable
String CopyProgmemMessage(prog_uchar * messageString){
    int counter = 0;
    char myChar;
    String myString="";

    do {
        // read back a char 
        myChar =  pgm_read_byte_near(messageString + counter); 
        if (myChar != 0){
            myString += myChar;
        }
        counter++;
    } 
    while (myChar != 0);
    return myString;
}
// Scroll Message
void scrollRamMessage(String messageString) {
    int counter = 0;
    clearDisplay();
    while (messageString[counter] !=0){
        loadBufferLong(messageString[counter]);
        for (int x=0; x<12;x++){
            rotateBufferLong();
            printBufferLong();
            delay(scrollDelay);
        }
        counter++;
    }
}

Another quick question, does using const to define a value reserve RAM space or does the compiler substitute it's reference with an immediate value? Should I be using define instead for below items?

const int DIN = 12;                     // DataIn pin (18)
const int CLK = 11;                     // Clock pin (17)
const int LOAD = 10;                    // Load pin (16)
const int numDevices = 2;               // Number of MAX7219 LED Driver Chips (1-8)

const int ldrPin = A0;                  // Select the input pin for the light dependent resistor (LDR)

const int ledMin = 3;                   // Minimum LED brightness value used in map command
const int ledMax = 12;                  // Maximum LED brightness value used in map command
const int ldrMax = 80;                  // Inital maximum reading from LDR (0-1023)
const int ldrMin = 0;                   // Initial minimum reading from LDR (0-1023)
const int fadeDelay = 30;               // Millisecond delay between each intensity step change

const int encButton = 5;                // Rotary Encoder button pin (11)
const int encoder0PinA = 6;             // Rotary Encoder A pin (12)
const int encoder0PinB = 7;             // Rotary Encoder B pin (13)

const long debounceDelay = 90;          // Button debounce time
const long adjustDelay = 15000;         // 15 Second Adjust timeout
const long buttonDelay = 3000;          // Button hold time to go into adjust mode (3 seconds)

const int scrollDelay = 35;             // Text Scroll speed delay (lower is faster)

When making up strings of data in a specific format sprintf is your friend.

As for consts, the compiler treats them just the same as #define except it has the benefit of type checking.

The String class seems easy to use, but takes a lot of SRAM. Go to http://cplusplus.com/reference/clibrary/cstring/ to see functions to handle char arrays.

If you are assembling text and then outputting that to a serial connection then stop and think;

You get serial data a character at a time and you send serial data the same way. What you assemble to an array or String could more easily just be output to serial as if it is a buffer that doesn't use ram.

When you want a drink and there is a water fountain, do you really need to fill a cup from the fountain to get a drink?

GoForSmoke:
If you are assembling text and then outputting that to a serial connection then stop and think;

I assemble the string and then call a routine to extract font pixel data from an PROGMEM array and scroll it across a LED matrix. To keep things simple and the scroll steady I cannot construct the scroll message as I go.

dkl65:
The String class seems easy to use, but takes a lot of SRAM. Go to http://cplusplus.com/reference/clibrary/cstring/ to see functions to handle char arrays.

Do all the functions mentioned here work with arduino and do they work with reading char arrays in PROGMEM

majenko:
When making up strings of data in a specific format sprintf is your friend.

As for consts, the compiler treats them just the same as #define except it has the benefit of type checking.

I cannot see how to use sprintf with PROGMEM char arrays as they hold full day and month names (Saturday / December)

Riva:

majenko:
When making up strings of data in a specific format sprintf is your friend.

As for consts, the compiler treats them just the same as #define except it has the benefit of type checking.

I cannot see how to use sprintf with PROGMEM char arrays as they hold full day and month names (Saturday / December)

I'm not certain about the Arduino, but in other C implementations you use %S as a placeholder for a string in flash (as opposed to %s for a string in RAM).

The String class seems easy to use, but takes a lot of SRAM.

The per-string overhead of using the String class is only seven or eight bytes per instance; the danger in using it lies in potential memory fragmentation after multiple String operations.

I wonder if someone could help me as I'm getting in a right pickle trying to convert routines to not use String().
The routine I'm trying to convert is this...

// Display Date
void doDate2(){
    String myDate;

    RTC.readClock();                                      //Read clock
    // DayOfWeek
    int x = RTC.getDayOfWeek();
    myDate=CopyProgmemMessage((prog_uchar*)pgm_read_word(&(day_table[x-1])));
    // Day
    x = RTC.getDate();
    myDate += String(x,DEC);
    myDate += " ";
    // Month
    x = RTC.getMonth();
    myDate +=CopyProgmemMessage((prog_uchar*)pgm_read_word(&(month_table[x])));
    // Year
    x = RTC.getYear();
    myDate += "20";
    myDate += String(x,DEC);
    myDate += "  \0";

    scrollRamMessage(myDate);
}
// Copy zero terminated string from program memory into String variable
String CopyProgmemMessage(prog_uchar * messageString){
    int counter = 0;
    char myChar;
    String myString="";

    do {
        // read back a char 
        myChar =  pgm_read_byte_near(messageString + counter); 
        if (myChar != 0){
            myString += myChar;
        }
        counter++;
    } 
    while (myChar != 0);
    return myString;
}

Below I have trimmed the sketch down to it bare minimum to get example running and show what I have tried to implement but get compile errors that I don't understand. Also I'm unsure how to convert and concatenate a integer number onto the current string

//We always have to include the libraries
#include <avr/pgmspace.h>


//Enumerations

// Month Strings
prog_uchar Month01[] PROGMEM = {
    "January \0"};
prog_uchar Month02[] PROGMEM = {
    "Febuary \0"};
prog_uchar Month03[] PROGMEM = {
    "March \0"};
prog_uchar Month04[] PROGMEM = {
    "April \0"};
prog_uchar Month05[] PROGMEM = {
    "May \0"};
prog_uchar Month06[] PROGMEM = {
    "June \0"};
prog_uchar Month07[] PROGMEM = {
    "July \0"};
prog_uchar Month08[] PROGMEM = {
    "August \0"};
prog_uchar Month09[] PROGMEM = {
    "September \0"};
prog_uchar Month10[] PROGMEM = {
    "October \0"};
prog_uchar Month11[] PROGMEM = {
    "November \0"};
prog_uchar Month12[] PROGMEM = {
    "December \0"};
//Month String Pointer Table
prog_uchar *month_table[] PROGMEM ={
    Month01,
    Month02,
    Month03,
    Month04,
    Month05,
    Month06,
    Month07,
    Month08,
    Month09,
    Month10,
    Month11,
    Month12,
};

// Day Strings
prog_uchar Day01[] PROGMEM = {
    "Sunday \0"};
prog_uchar Day02[] PROGMEM = {
    "Monday \0"};
prog_uchar Day03[] PROGMEM = {
    "Tuesday \0"};
prog_uchar Day04[] PROGMEM = {
    "Wednesday \0"};
prog_uchar Day05[] PROGMEM = {
    "Thursday \0"};
prog_uchar Day06[] PROGMEM = {
    "Friday \0"};
prog_uchar Day07[] PROGMEM = {
    "Saturday \0"};
//Month String Pointer Table
prog_uchar *day_table[] PROGMEM ={
    Day01,
    Day02,
    Day03,
    Day04,
    Day05,
    Day06,
    Day07,
};

char stringBuffer [101] = {
    0};

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

void loop(){ 
    doDate2();

    while (true){
    };
}

// Display Date
void doDate2(){

    size_t Length = 0;
    // DayOfWeek
    int x = 7; //Saturday
    Length = strlcpy_PF(stringBuffer* , (prog_uchar*)pgm_read_word(&(day_table[x-1])) , sizeof(stringBuffer));
    // Day
    x == 16; //Day
    // What Hear????
    // Month
    x == 6; //June
    Length = strlcat_PF(stringBuffer* , (prog_uchar*)pgm_read_word(&(month_table[x])) , sizeof(stringBuffer));
    // Year
    x == 12;  //Year

}

You can make an array of strings. It is just a 2 dimension char table.

char myStringTable[12][9] = { "January", "February", "March", etc... };

*myStringTable[2] ----- is "March\0\0\0\0"

Hi GoForSmoke,

I keep them as separate entries as they are stored in PROGMEM and you need a pointer table to the character arrays. My problem is pulling them from PROGMEM to build up a string of text like 'Saturday 16 June 2012'. I see there is suitable commands built in but compiling errors on this line

Length = strlcpy_PF(stringBuffer* , (prog_uchar*)pgm_read_word(&(day_table[x-1])) , sizeof(stringBuffer));

You don't -need- a pointer table if you store fixed-length strings in your table. All you need then is base address, index, and the fixed-length to find any element. Pad with zeros, ex: "March\0\0\0\0", they terminate the C string. A few bytes of flash wasted is no biggie.

Thanks for the help, have cracked the string copy from PROGMEM problem.