Pointer returns garbage

I have been working on a class that returns values stored in a progmem ARRAY. The function that prints the value within the class works, however, when I try to extract a pointer to the array item from the main sketch and then try to access the content directly I get garbage. Why?

Below is a minimal case example with 3 small files, with the same structure as my actual project.

Main sketch:

#include "test.h"


fruitSalad fruitlist;

void setup(){

  Serial.begin(115200);
  delay(500);

  size_t cnt = fruitlist.showFruit(2);
  Serial.println();
  Serial.print("Bytes: ");
  Serial.println(cnt);
  Serial.println();

  char * fruit = NULL;
  cnt = fruitlist.getFruit(fruit);

  if (cnt) {
    char c;
    for (size_t i=0; i<cnt; i++){
      c = pgm_read_byte_near(fruit + i);
      Serial.write(c);
    }
    Serial.println();
  }


}



void loop(){
}

test.h:

#ifndef TEST_H
#define TEST_H

#include "Arduino.h"


#define FRUIT1 "Orange"
#define FRUIT2 "Lemon"
#define FRUIT3 "Cherry"

const char orange [] PROGMEM = {FRUIT1};
const char lemon  [] PROGMEM = {FRUIT2};
const char cherry [] PROGMEM = {FRUIT3};

const char * const fruits[] PROGMEM = {
  orange,
  lemon,
  cherry
};


class fruitSalad {

  public:

    fruitSalad();
    size_t showFruit(size_t idx);
    size_t getFruit(char * fruit);

  private:

    char * _fruitPtr;
    size_t _fruitSize;


};


#endif    // TEST_H

test.cpp:

#include "test.h"


fruitSalad::fruitSalad(){
  _fruitPtr = NULL;
  _fruitSize = 0;
}


size_t fruitSalad::showFruit(size_t idx){
  char c;
  _fruitPtr = (char *)pgm_read_ptr(fruits + idx);
  _fruitSize = strlen_P(_fruitPtr);

  for (size_t i=0; i<_fruitSize; i++){
    c = pgm_read_byte_near(_fruitPtr + i);
    Serial.write(c);
  }

  return _fruitSize;
}


size_t fruitSalad::getFruit(char * fruit){

  fruit = _fruitPtr;

  return _fruitSize;
}

That doesn't change the value of the pointer in the calling function.

Your issue is nothing to do with PROGMEM and pointers. its related to scope.

The fruit variable is local to the getFruit() method. While the program leave the method scope, the fruit value will destroyed.

Main sketch:

   cnt = fruitlist.getFruit(&fruit);

test.h

    size_t getFruit(char ** fruit);

test.cpp

size_t fruitSalad::getFruit(char **fruit) {

   *fruit = _fruitPtr;

As @b707 said The bug is in getFruit. The parameter char * fruit is passed by value, so assigning fruit = _fruitPtr inside the function only modifies the local copy. The caller’s pointer in the sketch never gets updated.
Fix it by passing a pointer to the pointer:
test.h β€” change the declaration:

size_t getFruit(char ** fruit);

test.cpp β€” change the definition:

size_t fruitSalad::getFruit(char ** fruit){
  *fruit = _fruitPtr;
  return _fruitSize;
}

Main sketch β€” change the call:

cnt = fruitlist.getFruit(&fruit);

That’s it. The rest of your PROGMEM access logic seems correct.​​​​​​​​​​​​​​​​


Edit ooops late to the party @van_der_decken got there too

Ah, that would explain it. I have passed in references to char arrays before and then modified them in the method but I guess here I am passing a pointer not a reference.

I was just about to ask whether I need to pass in a reference to the pointer.

I can't quite get my head around the double stars....

See that as a pointer to your pointer

The another option - pass pointer as reference. The only change you need is in method header:

size_t fruitSalad::getFruit(char *& fruit){
  fruit = _fruitPtr;
  return _fruitSize;
}

The call of the method still the same

see my previous comment

Yes, the solution provided by @van_der_decken worked perfectly.
I also applied it to my actual project and it works there also.
Thank you.

Hmm, so having something that points to something wasn't enough. Seems it needed something that pointed to something that already pointed to something so that the method could be passed the address of the pointer variable so that it could access it and set the address for it to point to. My head hurts!

I tried the method suggested by @b707 as well as I think I understand that a little better (it makes my head hurt less). That worked perfectly as well. Since its a reference to a pointer, I did wonder why its *&fruit and not '&*fruit' though?

The indexes can be grouped this way:
char* &fruit

where char* is a type of variable and &fruit is a reference to it

Perhaps it makes the things more understandable.

Yes, that does make it clear. Thank you.

Its unfortunate that I can't mark both posts #4 and #8 as solutions, because they both solve the problem, just in a slightly different way.

With a forward declaration, you don't even need a variable name. You can't do this

sketch_may16a.ino:1:16: error: cannot declare pointer to 'char&'
 void foo(char &*);
                ^

The * means both "pointer-to" and "dereference that pointer" (and that terminology pre-dates reference variables; even more confusing).

The & means both "address-of" and "reference-to".

For a type declaration like a function argument, they are both suffixes. So reading backwards, "reference-to pointer-to char" is valid. But the other order, as shown above, is not.

The variable name that usually comes after is then just a name for that, if it is actually used. The whitespace between all that is irrelevant and optional; people put what they think makes more sense.

I have seen something like this in header files before, where the declaration has no variable name for a simple example:

void foo(int);

but the implementation does have a variable name so something can be done with the parameter e.g.:

void foo(int val){
  return sqrt(val);
}

Your tip to ignore the variable name and read the symbols and type in reverse makes it clear why it can't be written the other way around. So with your example it would have to be:

void foo(char *&);

Incidentally have also noticed various uses of the space e.g.:

void foo(char* val);
void foo(char *val);
void foo(char * val);

There are also discussion about which is better or "proper" but AFAIKT there doesn't appear to be a defined standard. Of course, if the '&' is added then I suppose you end up with a few more permutations to debate.... Just as well that the compiler doesn't care so long as they are in the correct order.

Thanks again. Post much appreciated.

Indeed, i C++, both forms are valid in a declaration:

void process(int, double, const std::string&);                   // without names
void process(int count, double ratio, const std::string& label); // with names

My best practice is to always include parameter names in declarations. They act as inline documentation β€” void resize(int, int) tells you nothing, void resize(int width, int height) is self-explanatory without opening the implementation file.

The names in the declaration and the definition don't have to match β€” the compiler only cares about types. They are ignored entirely by the compiler; they exist purely for the human reader.

For unused parameters in the definition, there are three approaches (from old habits to modern practice):

// 1. Omit the name β€” suppresses the warning but loses documentation
void foo(int used, int) { ... }

// 2. Comment out the name β€” same compiler effect, keeps intent readable
void foo(int used, int /*unused*/) { ... }

// 3. [[maybe_unused]] β€” the standard C++17 way, preferred
void foo(int used, [[maybe_unused]] int unused) { ... }

[[maybe_unused]] is the most expressive option. It covers regular variables and functions, not just parameters, and handles cases where a parameter is only used in certain build configurations:

void foo(int i, [[maybe_unused]] int j) {
    assert(i > j); // j is used in debug builds, not in release
}

It is also worth placing [[maybe_unused]] in the declaration as well β€” it signals to the reader upfront that the parameter is intentionally unused, not an oversight.

For pre-C++17 codebases, the commented-out name style is the best fallback β€” the compiler sees no name so no warning fires, but the intent stays readable:

void foo(int used, int /*unused*/) { ... }

There a multiple ways to solve it. I think the code is still kind of ugly. You need two values returned and you're currently doing that by providing one as a return value from the function and the other by modifying one of the function's arguments. Why not use a struct containing the size variable and the pointer? Then you could either return that struct from the function or pass it in as a reference and modify it in situ.

Also, the pointer should be a const char * because it points to PROGMEM.

here is an attempt to rewrite this

// β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
// β”‚                        FRUIT                             β”‚
// β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

class Fruit : public Printable {
public:
  Fruit(const char * progmemPtr) :
    progmemAddress(progmemPtr),
    charCount(strlen_P(progmemPtr)) {}

  size_t size()  const { return charCount; }
  bool   valid() const { return progmemAddress != nullptr; }

  const __FlashStringHelper * fruitName() const {
    return (const __FlashStringHelper *)progmemAddress;
  }

  char charAt(size_t index) const {
    if (!valid() || index >= charCount) return '\0';
    return (char)pgm_read_byte_near(progmemAddress + index);
  }

  size_t printTo(Print & output) const {
    output.print((const __FlashStringHelper *)progmemAddress);
    return charCount;
  }

private:
  const char * progmemAddress;
  size_t       charCount;
};


// β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
// β”‚                      FRUIT SALAD                         β”‚
// β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

template<size_t N>
class FruitSalad : public Printable {
public:
  template<typename... Args>
  FruitSalad(Args &... args) : fruits{ &args... } {}

  size_t count() const { return N; }

  const Fruit & operator[](size_t index) const { return *fruits[index]; } // no bounds check β€” no exceptions on small Arduinos, use get() if index is uncertain

  const Fruit * get(size_t index) const {
    if (index >= N) return nullptr;
    return fruits[index];
  }

  size_t printTo(Print & output) const {
    size_t totalBytes = 0;
    for (size_t index = 0; index < N; index++) {
      output.print(index);
      output.print(F(": "));
      totalBytes += fruits[index]->printTo(output);
      output.println();
    }
    return totalBytes;
  }

private:
  const Fruit * fruits[N];
};


// β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
// β”‚                        SKETCH                            β”‚
// β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

const char orangeTxt[] PROGMEM = "Orange";
const char lemonTxt [] PROGMEM = "Lemon";
const char cherryTxt[] PROGMEM = "Cherry";

Fruit orange(orangeTxt), lemon(lemonTxt), cherry(cherryTxt);
FruitSalad<3> salad(orange, lemon, cherry);

void setup() {
  Serial.begin(115200);
  delay(500);

  Serial.println(F("-- Full salad --"));
  Serial.println(salad);

  Serial.println();

  Serial.println(F("-- Single fruit via [] --"));
  Serial.println(salad[1]);

  Serial.println();

  Serial.println(F("-- Same value via fruitName() --"));
  Serial.println(salad[1].fruitName());

  Serial.println();

  Serial.println(F("-- Single fruit via get() with bounds check --"));
  if (salad.get(1)) Serial.println(*salad.get(1));
}

void loop() {}

only thing bugging me is the <3> in FruitSalad<3> salad(orange, lemon, cherry); because we use C++11 only so can't use more advanced stuff.

@gfvalvo , point is well taken. With some inspiration from @J-M-L I have re-written my actual project code to make it simpler and neater.

@J-M-L , I did realize a bit later that I could use const __FlashStringHelper *) to print the char array instead of looping over it. The charAt() function also proved useful and I was able to use your code for inspiration in my actual project. Of course, your version of FruitSalad works perfectly as well.

Thank you for taking the time and trouble to post this example.

BTW, I didn't realise that one could make functions const e.g.:

size_t count() const { return N; }

Not seen that before. What is the purpose of the const in that position?