PROGMEM and PGM_P syntax question

After much tinkering and reading of forums I found a solution to a problem I was having with PROGMEM. But I believe the solution could be simplified but I cannot figure out a working syntax which points to or copies the correct location in memory.

This works:

#include <stdint.h>
#include <avr/pgmspace.h>

#define dt_MAX_STRING_LEN 15
static char buffer[dt_MAX_STRING_LEN+1];  // must be big enough for longest string and the terminating null

const char suffixStr0[]  PROGMEM = "th";
const char suffixStr1[]  PROGMEM = "st";
const char suffixStr2[]  PROGMEM = "nd";
const char suffixStr3[]  PROGMEM = "rd";
PGM_P const suffixes[] PROGMEM = {suffixStr0,suffixStr1,suffixStr2,suffixStr3};

char*   getNumberSuffix(uint8_t number) {
  int digit = number % 10;
  int tenz = number / 10;

  if (tenz == 1)
  {
    strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixes[0]))) ;
  } else {
    switch(digit) {
      case 1:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixes[1]))) ;
        break;
      case 2:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixes[2]))) ;
        break;
      case 3:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixes[3]))) ;
        break;
      default:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixes[0]))) ;
      
    } // switch;
  } // tens == 1
  return buffer;
} // END getNumberSuffix

What I am hoping to do is eliminate line 11 (PGM_P const suffixes PROGMEM…) and use the individual character arrays. The following is just one of many syntax variations I have tried:

#include <stdint.h>
#include <avr/pgmspace.h>

#define dt_MAX_STRING_LEN 15
static char buffer[dt_MAX_STRING_LEN+1];  // must be big enough for longest string and the terminating null

const char suffixStr0[]  PROGMEM = "th";
const char suffixStr1[]  PROGMEM = "st";
const char suffixStr2[]  PROGMEM = "nd";
const char suffixStr3[]  PROGMEM = "rd";
//PGM_P const suffixes[] PROGMEM = {suffixStr0,suffixStr1,suffixStr2,suffixStr3};

char*   getNumberSuffix(uint8_t number) {
  int digit = number % 10;
  int tenz = number / 10;

  if (tenz == 1)
  {
    strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixStr0))) ;
  } else {
    switch(digit) {
      case 1:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixStr1))) ;
        break;
      case 2:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixStr2))) ;
        break;
      case 3:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixStr3))) ;
        break;
      default:
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(suffixStr0))) ;
      
    } // switch;
  } // tens == 1
  return buffer;
} // END getNumberSuffix

It compiles, but causes the Arduino to reboot. (So I must be “pointing” wrong). Can some almighty guru please tell me the correct syntax for the strcpy_P(buffer, (PGM_P)… lines?

Thanks in advance!

The strcpy_P function requires PGM_P pointer as second parameter so the statement should look like:

case 1:
  strcpy_P(buffer, suffixStr1);
  break;

to copy the "st" string from program memory into the buffer which is in SRAM.

http://gammon.com.au/progmem

Thanks Bud & Nick! Karma to you!

This is a project that had been shelved since Christmas and I am now getting back to work on it. I'm trying to remember now why I added the PGM_P and pgm_read_word. (I seem to remember I had to add them when I went from IDE 1.5.2 to 1.6.0, but it's now working without it in 1.6.) Do I need them when I'm doing the array of char arrays (as in example 1 above)?

Well if it works, probably yes. By the looks of it the pointer to the data, and the data itself, is in PROGMEM so it looks OK.