Array Settings disappear, set to null?

I have been trying for a while now to be able to read an SD card to gather the file names into an array so I can select them with an IR transmitter to play as midi files. I have been able to read the files’ names and place them into an array and Serial.print them to an LCD screen and debug successfully on the host computer within the inner loop, but as soon as I am out of the loop (I hate being out of the loop :~), the values previously assigned have disappeared and seem to be set to null. While I know a bit about programming there are bits (er huge amounts :slight_smile: ?)of C++ that I can’t cotton on to. Can you check this and help me please.

First of all a few declarations -

char   * fileNames[18]={"All100.mid","ASOG80.mid","Beat80.mid","Duo100.mid","sara120.mid","SCH80.mid","1oxox","2oxox","3oxox","4oxox","5oxox","6oxox"};//demo names
int     nosFiles = 0;//Stores nos of files in list
word    filePointer =0;

Followed by some code -

  //now strip all the characters for each midi file and store in a buffer
   filePointer = 0;
   char lcdBuff[] = "xxxxxxx.yyy  ";//it only works with 7.3 DOS format names
   File root = SD.open("/");
   File entry =  root.openNextFile();//get first file to begin with
   while(entry) {//keep getting entries while they exist
     fileNames[filePointer] = entry.name();
     lcdBuff[0] = 48+filePointer;//assign a prefix to the filenames
     lcdBuff[1] = 32;  //leave a space
     int tempX=-1;      // the pointer into the entry array
     int tempY=1;      // the character in the entry array
     while (tempY!=0){ //The last character in a char array is Zero
        tempX++; //point to the next character
        tempY = fileNames[filePointer][tempX]; //assign each character in turn
        lcdBuff[2+tempX] = tempY; //via tempY so we can check for 0x00
        }
     lcdLine(lcdBuff,GREEN,filePointer+1);//write the full line to the LCD
     Serial.print("Inside loop ");
     Serial.println(fileNames[filePointer]);
     filePointer ++;
     entry =  root.openNextFile();
     }
   nosFiles=filePointer;
   Serial.print("Number of Files ");
   Serial.println(nosFiles);

   for (filePointer=0;filePointer<nosFiles;filePointer++){
     Serial.print(filePointer,DEC);
      Serial.print(" Outside loop ");
      Serial.println(fileNames[filePointer]);
      }
// open the file.
  //Name must be the 7.3 Standard.
  Serial.print("File 0 Selected ");
  Serial.println(fileNames[0]);
  Serial.print("Now getting IR code for file selection = ");
  int showInt =wait4IR(filePointer,0);//get an IR response between maxIR and MinIR
  Serial.println(showInt,DEC);
  Serial.print("File Selected ");
  Serial.println(fileNames[showInt]);
  myFile = SD.open(fileNames[showInt]);
  lcdLine("Now Playing:",RED,14);
  lcdLine(fileNames[showInt], WHITE,15);
  if (myFile) { //open the file if available and process it
etc etc

This is the screen debug on the host computer -

Initializing SD card...initialization done.
Inside loop ASOG80.MID
Inside loop DUO100.MID
Inside loop SARA100.MID
Inside loop SARA120.MID
Inside loop SCH80.MID
Inside loop PARROT.BMP
Inside loop ALL100.MID
Inside loop BEAT80.MID
Number of Files 8
0 Outside loop 
1 Outside loop 
2 Outside loop 
3 Outside loop 
4 Outside loop 
5 Outside loop 
6 Outside loop 
7 Outside loop 
File 0 Selected 
Now getting IR code for file selection = 2
File Selected 
Total bytes successfully loaded =16384
---------Just get Main Info-------------- OK
Not a Midi file

Now you will notice (I hope) that in the “outside loop” nothing prints in the debug screen, yet the same reference to the array prints ok inside the loop. Any reference to fileNames[filePointer] seems to be null in the outside loop and yet in the inside loop it produces the right information. Even

Serial.print("File 0 Selected ");
Serial.println(fileNames[0]);

Produces a seemingly “null” ie nothing output.

I am feel it is something to do with array references, but I just can’t crack it, to resort to the Aussie colloquial “I am stuffed as to know what to do with it?”

Any (helpful) suggestions would be appreciated.

Cheers, Rob

PS it seems that if the SD/File library is presented with a null name to look up it returns “TRUE” and hence the last bit of the of the program attempts to load 16k Bytes that don’t exist? Is this a bug in the SD/File library?

I think it is the way you declared fileNames. Try this instead.

char   fileNames[18][14]={"All100.mid","ASOG80.mid","Beat80.mid","Duo100.mid","sara120.mid","SCH80.mid","1oxox","2oxox","3oxox","4oxox","5oxox","6oxox"};//demo names

Any (helpful) suggestions would be appreciated.

I suggest that you post ALL of your code.

As SurferTim points out, you are attempting to overwrite memory that fileNames[n] points to, but that memory is not allocated in the way that you think. There are many similarities between pointers and arrays, but there are subtle differences, too.

One of the major differences is exactly how and where the storage space is allocated. Another key difference is whether or not the storage space is then writable.

You clearly need space that is writable. Using pointers to allocate that space is not recommended.

You CAN treat the array as a pointer to do the writing, later, and to read from the memory pointed to.

Thanks guys for a prompt response. I am still struggling. Sorry but the code is about 400 lines long. No need for all the gumph as the problem is very early on before things should be getting too complicated, ie first of all set up access to SD card and read all available files into an array, use an IR controller to choose file by number (there will be less than 10 to begin with to keep it simple, so 0-9 will work as an IR response & array index), but the array data is still no longer accessible, it has disappeared.

I have tried the following adjustments using SurferTim’s advice but the problem persists -

// Declare data structures
char   * fileNames[18][14];
int     nosFiles = 0;//Stores nos of files in list
word    filePointer =0;

........

   filePointer = 0;
   char lcdBuff[] = "xxxxxxx.yyy  ";//it only works with 7.3 DOS format names
   File root = SD.open("/");
   File entry =  root.openNextFile();//get first file to begin with
   while(entry) {//keep getting entries while they exist
     *fileNames[filePointer] = entry.name();
     lcdBuff[0] = 48+filePointer;//assign a prefix to the filenames
     lcdBuff[1] = 32;  //leave a space
     int tempX=-1;      // the pointer into the entry array
     char tempY=1;      // the character in the entry array
     while (tempY!=0){ //The last character in a char array is Zero
        tempX++; //point to the next character
        tempY = *fileNames[filePointer][tempX]; //assign each character in turn
        lcdBuff[2+tempX] = tempY; //via tempY so we can check for 0x00
        }
        //fileJunk = fileNames[filePointer];
     lcdLine(lcdBuff,GREEN,filePointer+1);//write the full line to the LCD
     Serial.print("Inside loop ");
     Serial.println(*fileNames[filePointer]);//Point A: works fine :-))))
     filePointer ++;
     entry =  root.openNextFile();
     }
   nosFiles=filePointer;
   Serial.print("Number of Files ");
   Serial.println(nosFiles);
   //Now dump the array to see what is happening
   for (filePointer=0;filePointer<nosFiles;filePointer++){
     Serial.print(filePointer,DEC);
     Serial.print(" Outside loop ");
     Serial.println(*fileNames[filePointer]);//Point B: array has lost data :-(
     }
  // open the file.
  //Name must be the 7.3 Standard.
  Serial.print("Now getting IR code for file selection = ");
  int showInt =wait4IR(filePointer,0);//get an IR response between maxIR and MinIR
  Serial.println(showInt,DEC);
  Serial.print("File Selected ");
  Serial.println(*fileNames[showInt]);//Point C: array has lost data :-(
  myFile = SD.open(*fileNames[showInt]);  //this bit fails because the name is invalid
  lcdLine("Now Playing:",RED,14);
  lcdLine(*fileNames[showInt], WHITE,15);
  //Program goes on to parse the loaded file according to midi format
  //Following bit all works fine with at static name eg myFile = SD.open("All80.mid");

.......  now for the dumped output  plus   added  <=comments

Initializing SD card...initialization done.
Inside loop ASOG80.MID         <=Point A printing this list
Inside loop DUO100.MID
Inside loop SARA100.MID
Inside loop SARA120.MID
Inside loop SCH80.MID
Inside loop PARROT.BMP
Inside loop ALL100.MID
Inside loop BEAT80.MID
Number of Files 8
0 Outside loop                   <=Point B here for this list
1 Outside loop 
2 Outside loop 
3 Outside loop 
4 Outside loop 
5 Outside loop 
6 Outside loop 
7 Outside loop 
Now getting IR code for file selection = 2
File Selected                                             <=Point C here.
Total bytes successfully loaded =16384
---------Just get Main Info-------------- OK
Not a Midi file

So in the while/loop the reference to the array works fine at point A, no probs.
After and outside the while/loop at points B and C the Array no longer displays the data is showed at A. Yet the command is identical?
I fully appreciate what you are saying Pauls, in that arrays and pointers etc are very subtle and I feel like a bull in china shop at the moment. I feel in need it spelt in big letters to be able to solve it. eg have I not allowed enough space for the adjacent variables and scrambled the array?

Any help would be appreciated, the whole compiles and runs OK apart from this glitch with the names.

Cheers, Rob

I have tried the following adjustments using SurferTim's advice but the problem persists

SurferTim did NOT suggest a 2D array of pointers to characters. He suggested a 2D array of characters. Big, big, difference.

I take your point Pauls and I have come up with a solution but it appears somewhat clumsy and any help in a tidier approach would no doubt benefit my understanding considerably.

I can see now that all I was doing was assigning the fileNames array of pointers away from the separate char sequences in the initial declaration over to the current name pointer returned with entry.name(). So successive array pointers were being aligned to the same temporary variable entry, and when it disappeared after the while loop came off the stack, then all the pointers were looking at nulls (or some other random stuff).

Consequently when I was debugging at Point A the data made sense because at the time the fileNames pointer was pointing to entry.name(), but over the iteration of all the file names they all eventually had the same value. By the time it got to Point B and Point C the pointers in fileNames were meaningless.

I have attempted to write the characters from entry.name() via another array namBuff, character by character back to where the original declaration set up space for them.

   char *namBuff[1] = {"xxxxxxx.yyy  "};//it only works with 7.3 DOS format names

........
namBuff[0] = entry.name();
     int charPoint=0;
     while(namBuff[0][charPoint]!=0){
        fileNames[filePointer][charPoint] = namBuff[0][charPoint];
        charPoint++;
        }
     fileNames[filePointer][charPoint] = namBuff[0][charPoint];

I am feeling my way with arrays and this works, BUT it looks v clumsy :cold_sweat:, any suggestions?

robwlakes: Sorry but the code is about 400 lines long.

I'm optimistic that you can demonstrate the problem in considerably less than 400 lines of code. If you can't, then let that be your first challenge. :)

char *namBuff[1] = {"xxxxxxx.yyy  "};//it only works with 7.3 DOS format names
...
namBuff[0] = entry.name();

When you declare namBuff you provide an initialiser which creates a global char array and puts its pointer into the first element ( a char* ), then later on you re-assign the pointer with entry.name() effectively loosing your reference to global "xxxxxxx.yyy " leaving it dangling in memory ( memory that you cannot re-use )

It is also easier to just say.

char namBuff[] = "xxxxxxx.yyy  ";

Could remove a layer of indirection to make it seem tidier.

char *namBuff; //<< why use array if you get a pointer from entry.name();
//....
    namBuff = entry.name();

     int charPoint=0;
     char *c_File = &fileNames[filePointer][0]; //EDIT: added [0]

     while(namBuff[charPoint]!=0){
        c_File[charPoint] = namBuff[charPoint];
        charPoint++;
        }
     c_File[charPoint] = namBuff[charPoint];

Once you are comfortable with pointers you can also say:

      char  *c_File = *( fileNames + filePointer );
     int    charPoint = 0;
     char  *c_Temp = namBuff = entry.name(); 

     while( *c_Temp !=0) *c_File++ = *c_Temp++;
     *c_File = *c_Temp;
     while(namBuff[0][charPoint]!=0){
        fileNames[filePointer][charPoint] = namBuff[0][charPoint];
        charPoint++;
        }

The strlen(namBuff[0]) function would tell you where the NULL is (i.e. how long the name is). Then, you could use strncpy() with that length.

Or, simply use strcpy() and let it figure out the length. It knows how to.

Don't reinvent code that you don't need to.

Thank you pYro_65, that response is quite informative about arrays and what can be done with them. I have altered my code and now have it somewhat condensed but the last line is not quite as you suggested, but it now works!

    char *namBuff; //NB it only works with 7.3 DOS format names
    File root = SD.open("/");
    File entry = root.openNextFile(); //get first file to begin with
    while (entry) { //keep getting entries while they exist
        namBuff = entry.name();
        int charPoint = 0;
        while (namBuff[charPoint] != 0) {
            fileNames[filePointer][charPoint] = namBuff[charPoint];
            charPoint++;
        }
        fileNames[filePointer][charPoint] = namBuff[charPoint];//Get the 0x00 character

It certainly looks tidier. The second example you gave pYro_65, I think I can follow, but the above solution is far more instructional for someone at my level with arrays. I will need to use them for other purposes in other parts of the program so I am chuffed at my new skills, thanks to your help. Cheers, Rob

        int charPoint = 0;
        while (namBuff[charPoint] != 0) {
            fileNames[filePointer][charPoint] = namBuff[charPoint];
            charPoint++;
        }
        fileNames[filePointer][charPoint] = namBuff[charPoint];//Get the 0x00 character

This is still re-implementing the strcpy() function. Save the trouble, and simply call strcpy().