Do some variables not hold their value when a while loop is exited?
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 &lt; 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.