How to copy the string from PROGMEM (Flash) to the SRAM

Hello,

I would like to copy the string from PROGMEM (Flash) to the SRAM. Is the following code the correct please

Thanks a lot

// Definition
const static char SD_FOLDER[] PROGMEM = "logs";
...

// Loading
char buffer[32];
memset( buffer, 0, 32 );
strncpy_P( buffer, SD_FOLDER, strlen_P( SD_FOLDER ) );

Please post a complete sketch

Why do you want/need to copy the string from PROGMEM ?

Why do you want/need to copy the string from PROGMEM ?

Thanks for an answer - maybe it's not necessary at all... I am creating few directories (and files) on SD card by using SDClass::mkdir(const char *filepath) method and I put all strings with directory names to the PROGMEM.

The memcpy is not necessary, as long as you copy the terminating null from the source.

// Definition
const static char SD_FOLDER[] PROGMEM = "logs";
...

// Loading
char buffer[32];
strncpy_P(buffer, SD_FOLDER, strlen_P(SD_FOLDER)  + 1);

//alternate method using sizeof() if size of SD_FOLDER is known at compile time
//strncpy_P(buffer, SD_FOLDER, sizeof(SD_FOLDER));

I believe the copy to ram is necessary in this instance, because the SD library does not support file paths stored in PROGMEM.

strncpy_P( buffer, SD_FOLDER, strlen_P( SD_FOLDER ) );

Not related to your question, but when using strncpy() and variants, the length you specify should be the length of the destination buffer, not the length of the source.

Also

No null character is implicitly appended to the end of s1, so s1 will only be terminated by a null character if the length of the string pointed to by s2 is less than n.

so tricky to use.

This does what you want using safe Arduino Strings

const char SD_FOLDER[] PROGMEM = "logs";
void setup() {
  Serial.begin(115200);
  for (int i = 10; i > 0; i--) {
    Serial.print(' '); Serial.print(i);
    delay(500);
  }
  Serial.println();
  String str(reinterpret_cast<const __FlashStringHelper *>(SD_FOLDER));
  Serial.println(str.c_str());  // the const char* setup with the data correctly terminated
  Serial.println("====");
}
void loop() {
}

Output

 10 9 8 7 6 5 4 3 2 1
logs
====
const static char SD_FOLDER[] PROGMEM = "logs";
char buffer[32];
strncpy_P(buffer, SD_FOLDER, sizeof(buffer));
buffer[sizeof(buffer)-1] = 0; // ensures buffer is null terminated in the event that the string is longer than the buffer

strlcpy_P() is better.

It turns out that strncpy() has a particular use case in mind that ISN’T avoiding buffer overflows of normal strings.

1 Like

@westfw That's a good point! I have checked the documentation and indeed the use for strncpy is not a good option for null-terminated strings, strlcpy si much better.

@westfw OMG. How I can miss that! Of course! Thanks a lot!

Unfortunately, the (mis)use of strlen(sourceString) and the inappropriate use of strncpy() are EXTREMELY common, even in professional software development environments. An edict comes down from management that strcpy() is dangerous and needs to be replaced (which is true), and strncpy() is the first thing that people find when they search for a replacement.

I wouldn't know that without the whole "been there, done that, got yelled at in code reviews, subsequently yelled at other people in code reviews..." experience.

(strncpy() is sort-of designed for filling in fixed-length character array fields, like you might find in a file descriptor block (... char fileName[8]; char fileExt[3]; ...) It fills in the whole destination space (with nulls, if appropriate) (which is unnecessary for the usual strcpy() replacement, and it does NOT guarantee that there will be a null at the end of the string, if the source is the full length of the destination.)

1 Like

strlcpy, strlcat and strlcpy_P and strlcat_P while not 'standard' C turn out be very safe and robust against buffer overflows. They also let you test if the result was truncated to prevent a buffer overflow.

Here is a short test sketch for these, which provides another simple solution to the OP question.

const char progStr2[ ] PROGMEM = "ptest_tooLong";
char result[5]; // to hold 4 char + terminating '\0'
strlcpy_P(result, progStr, sizeof(result)); // does not overflow, just truncates

strlcpy_test.ino (7.0 KB)

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.