1

Sorry if i'm asking too many silly questions but i'm really stumped on this one. I understand if I set a variable inside a loop that that variable won't be within scope from the outside of the loop.

Usually I find that variables declared outside of a loop will be accessible inside the loop, modifiable within the loop, and hold their value when exiting the loop but in this case that doesn't seem to be happening.

There are books on the sd card. I'm saving the name of each book to an array from within a while loop. When the while loop is exited the array is still null.

How can I solve this? thanks

int amtBooks = 5; //this gets set previously but im not going to show all the code

// create an array the size of the amount of books
  char* book[amtBooks] = { NULL };

// assign the name of each book to the array
  int bookNum = 0;
  while (true) {

    File entry =  root.openNextFile();
      if (! entry) {
        break; // no more files
      }

    book[bookNum] = entry.name(); 

    Serial.println(book[bookNum]); // <--------PRINTS FINE HERE

    bookNum ++;

  }

  root.close(); // close the stream


Serial.println(book[0]); <---ONCE OUT OF THE WHILE LOOP NOTHING DISPLAYS?
Serial.println(book[1]);
2
  • note: you have inconsistent indentation in your code .... the first line and the last two lines should be indented 2 spaces .... they are on the same level as the while (true) { line .... the three lines of the if block should be indented 2 spaces less .......... incorrect indentation adds confusion to debugging
    – jsotola
    Aug 20, 2018 at 23:45
  • this is not about Arduino. it is C
    – Juraj
    Aug 21, 2018 at 4:43

3 Answers 3

1

variables declared outside of a loop will be accessible inside the loop, modifiable within the loop, and hold their value when exiting the loop

This is correct.

in this case that doesn't seem to be happening.

It is happening. The reason it looks like it doesn't is that book[bookNum] is a pointer: the address of some data in memory. You can check that the pointer does hold its value by printing it:

Serial.println((uintptr_t) book[bookNum]);

However, the statement you used:

Serial.println(book[bookNum]);

has a different meaning. It doesn't print the value of the variable (i.e. the pointer): it prints the characters that are stored at the pointed-to address, up to and excluding the first NUL.

Your problem comes from the fact that when you declare

File entry =  root.openNextFile();

you have a variable that is local to the loop. Then, when calling the method

entry.name()

you get a pointer to an array of characters that belongs to the entry object. This pointer is only valid as long as the object is in scope. As soon as it gets out of scope (at the end of each loop iteration), the entry object is destroyed and all memory belonging to it is released. At this point the pointer you saved is a “dangling” pointer: it points to an area of memory that has already been deallocated.

The proper fix is to allocate yourself the memory you need to hold the character arrays, as in:

for (int bookNum = 0; bookNum < amtBooks; bookNum++) {
    File entry = root.openNextFile();
    if (!entry) break;
    const char *name = entry.name();
    book[bookNum] = (char *) malloc(strlen(name) + 1);
    strcpy(book[bookNum], name);
    Serial.println(book[bookNum]);
}

If you know in advance the maximum length of a book name, you could follow the advice of Jot and Juraj and statically allocate the maximum space you may need. That would be safer in terms of memory management.

0

You store a pointer to char array name in File variable entry. The entry goes out of scope (is deleted from stack) and your stored pointer points nowhere.

You need char book[amtBooks][13] = {{0}}; and strcpy(book[bookNum], entry.name());

-1

It helps if you know where the variables are located.

Local variables are located on the stack. They are created when entering a function and vanish when exit from a function. They can even be locally inside a if, for, while or other statement when they are declared inside that statement.

Global variables have a fixed memory location. They can be used from every function.

When a pointer is created and it points to nothing, then you may not write data to where that pointer it pointing to.
You create a array of pointers, but you need memory that you can use to store data. For example: char booknames[5][20]. An array of text is often copied with strcpy().

2
  • This entire piece of code is within the main do loop. There is something weird going on because even if I declare the array globally at the very top, setting the array values from within the while loop is not persistant. If I remove the while loop I can set the values of the array. Within the while loop the array values are present but loses the values once exiting the while loop.
    – Kara
    Aug 20, 2018 at 22:41
  • That is what I was trying to explain. It helps if you know where the variables are located. The actual text in your code is stored nowhere, since you use pointers. You have to create a memory location to store those texts. Not a pointer to something or nothing, but you need a memory location for the characters of the text.
    – Jot
    Aug 21, 2018 at 6:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.