Array values changing when not requested to...

Hi i have this really strange (well for me anyway) problem that the first value in one of my arrays changes for "no reason" as you can see i define 3 arrays of size 20, infoFileArray is the one that changes (first value). There are 3 functions that are called in the setup, the first one reads a SD card file and loads the data into the array infoFileArray. All the values are correct. I then call another function that has nothing to do with infoFileArray and the values are still correct but when i call the 3rd function (also not having anything to do with infoFileArray the first value of infoFileArray changes from 100 to 0!!!

// these 3 arrays are used to update the dontTouch file that stores how many kVA each power source has giving in the last period. 
int powerSource; //where the power is coming from, i.e. gen set 1,2,3... trasnformer, battery-inverter.....
int infoFileArray[20]; //where the power characteristics are stored for each power supply
float kVAarrayRead[20];
float kVAarrayWrite[20];
bool DTF = false; //used to oscillate between the two dontOpen files
int outsideTemp;
const float reductionPercent = 0.000001;

As you can see at the end of this function i have put in 3 debug statements, debug1 returns "100", debug2 returns "100" for every run of the while loop except for the last run of the while loop...!!!? then it returns "0"! debug3 also returns "0". I managed to find out that if i change int to float for the infoFileArray then it works fine... but this is very strange because all the numbers in the SD file are max 3 digits long.... can anyone tell me why this is happening and also why it happens in part of the code that has nothing to do with this array...?

void dontTouchRead()
{
  int sizeDontOpn1 = 0;
  int sizeDontOpn2 = 0;
  int j=0;
  char readLine[100]; // making an array of characters (char's) to store ecah character that is read from the file
  int middleTemp = 0;
  
  if(SD.exists("dontOpn1.csv")) { // finds out if the file exists and how big it is
    dontOpn1 = SD.open("dontOpn1.csv");
    delay(10); 
    sizeDontOpn1 = dontOpn1.size();
    dontOpn1.close();
    delay(10);  
    Serial.println(sizeDontOpn1);
  }

    if(SD.exists("dontOpn2.csv")) { // finds out if the file exists and how big it is
    dontOpn2 = SD.open("dontOpn2.csv");
    delay(10); 
    sizeDontOpn2 = dontOpn2.size();
    dontOpn2.close();
    delay(10); 
    Serial.println(sizeDontOpn2);   
  } 

if ((sizeDontOpn1 <= 1) && (sizeDontOpn2 <= 1)){ //checks that there is at least data in one of the files, jumps out of the function otherwise
  }
  else{
    if (sizeDontOpn1 > sizeDontOpn2){
      Serial.println("entered size one biggger than 2");
      dontOpn1 = SD.open("dontOpn1.csv", FILE_READ); // open "infoFile.csv" to read data
 
      if (dontOpn1) {  //checking that the file opened
        
        for (int i=0; i<100; i++) readLine[i] = dontOpn1.read();// loading characters into the char array
      dontOpn1.close();
      }  

    }
    else{
    Serial.println("entered size 2 biggger than 1");
    dontOpn2 = SD.open("dontOpn2.csv", FILE_READ); // open "infoFile.csv" to read data
 
      if (dontOpn2) {  //checking that the file opened
        
        for (int i=0; i<100; i++) readLine[i] = dontOpn2.read();// loading characters into the char array
      dontOpn2.close();
      }         
    }
  Serial.println("debug 1");
  Serial.println(infoFileArray[0]);
      char* tokenValue; //creating a pointer that will point to the first section of the array between the two ";"
      tokenValue = strtok(readLine, ";"); //there is also something going on here with putting a /0 at the end so it can find where to start next time
    
    while (tokenValue != NULL)
    {

      kVAarrayRead[j]= atof(tokenValue); // changing from char string to int and storing in array
      j=j+1;
      tokenValue = strtok (NULL, ";");
  Serial.println("debug 2");
  Serial.println(infoFileArray[0]);
   }
  Serial.println("debug 3");
  Serial.println(infoFileArray[0]);  
    
//    unixTime2000= kVAarrayRead[0];
//    depreciationTime1 = rtc.getUnixTime(rtc.getTime())-946684800 - unixTime2000;
//    middleTemp = (outsideTemp + kVAarrayRead[1])/2; //getting the average of the temp when the system went down and when it started again
//    for (int i = 0; i<18; i++){
//      kVAarrayWrite[i+2] = kVAarrayRead[i+2] - (infoFileArray[i] * reductionPercent * depreciationTime1 * ((25+100)/(middleTemp+100))); //
//    } 
//    test22 = rtc.getUnixTime(rtc.getTime())-946684800;

  }
}

Here is also the function for reading into the infoFileArray.... thanks for any help :slight_smile:

void readInfoFile() {
  int j=0;
  char readLine[30]; // making an array of characters (char's) to store ecah character that is read from the file
  File infoFile = SD.open("infoFile.csv", FILE_READ); // open "infoFile.csv" to read data

  if (infoFile) {  //checking that the file opened
        
        for (int i=0; i<30; i++){ 
          readLine[i] = infoFile.read();// loading characters into the char array
        }
    
    infoFile.close();
    }  
      char* tokenValue; //creating a pointer that will point to the first section of the array between the two ";"
      tokenValue = strtok(readLine, ";"); //there is also something going on here with putting a /0 at the end so it can find where to start next time
    
    while (tokenValue != NULL)
    {

      
      infoFileArray[j]= atoi(tokenValue); // changing from char string to int and storing in array
      j=j+1;
      tokenValue = strtok (NULL, ";");
  }
}

The likely answer is that you're overwriting an array boundary somewhere into memory that you don't own. However, not many people want to try and debug fragmented code snippets. If you'll bother to post a complete code that actually compiles, maybe someone will take a look.

Usually if variables change mysteriously it is because you indexed off the end of an array or used a pointer that was pointing to the wrong place. It could be both: you could go off the end of an array and hit an index variable or pointer that you use later.

If you don't want to share the code and data you will probably have to add a lot more debug output.

Have you set the Preferences: Compiler warnings to All? That can often point out questionable code that is not strictly illegal.

Ok thanks, here is the whole thing, just thought that i would try and only take out the bit that i thought that people would need to see to save everyone reading all of it.. :slight_smile:

Main_Code_12.ino (36.7 KB)

In readInfoFile() you read 30 characters from "infoFile.csv" and break that buffer up into tokens separated by ';'. What does the file contain? It appears that you don't put a null character at the end of the "readLine[]" buffer and you don't allow room for one. That might cause you to find more than 20 tokens in the buffer.

Ok it would appear that i really have no idea how to use the NULL character thing... i was thinking that if the char array was longer than the first line of data in the infoFile then it would automatically add the NULL thing at the end... i also tried making the array extra long and added NULL or '\0' at a point that i knew would be past the last data point but that did not work ether... this is the first line of data in the infoFile "100;100;65;65;80;80;200;200;40;30;30;1280;;;;;;;;;" there is more data in the file but that is on the next lines down (could not attach this file as csv so added it as txt). the data on the first line is always numbers between 0 and 5000.

void readInfoFile() {
  int j=0;
  char readLine[60]; // making an array of characters (char's) to store ecah character that is read from the file
  //readLine[55] = NULL;
  readLine[55] = '\0'; 
  File infoFile = SD.open("infoFile.csv", FILE_READ); // open "infoFile.csv" to read data

  if (infoFile) {  //checking that the file opened
        
        for (int i=0; i<60; i++){ 
          readLine[i] = infoFile.read();// loading characters into the char array
        }
    for (int i=0; i<90; i++) Serial.print(readLine[i]);
    infoFile.close();
    }  
      char* tokenValue; //creating a pointer that will point to the first section of the array between the two ";"
      tokenValue = strtok(readLine, ";"); //there is also something going on here with putting a /0 at the end so it can find where to start next time
    
    while (tokenValue != NULL)
    {
      Serial.println (tokenValue);
     
      infoFileArray[j]= atoi(tokenValue); // changing from char string to int and storing in array
      j=j+1;
      Serial.print(infoFileArray[j]);
      tokenValue = strtok (NULL, ";");
  }
}

Also here is a pic of the serial monitor, as you can see there is a 0 in front of all the other values but not the first one (100), would it have anything to do with that....? :confused:

Screenshot 2019-07-21 13.16.21.png

infoFile copy.txt (1.54 KB)

Screenshot 2019-07-21 13.16.21.png

Your new function creates a character array that can hold 60 characters.
You put a NULL character in the 56th position.
You read the 60 characters "100;100;65;65;80;80;200;200;40;30;30;1280;;;;;;;;;\n;;;;;;;;" into the buffer, overwriting the null character.
You print NINETY?!? characters from your buffer of 60 characters.

You split the buffer into tokens separated by ';', convert each token to a number, and store the number in the next position of infoFileArray[], which I last saw had 20 entries. THERE ARE 29 SEMICOLONS IN THOSE 60 CHARACTERS. There is no null terminator on your buffer so the code continues to look for tokens until it finds a null.

I think you want something more like this:

void readInfoFile() {
  int j = 0;
  char readLine[61]; // making an array of characters (char's) to store ecah character that is read from the file


  File infoFile = SD.open("infoFile.csv", FILE_READ); // open "infoFile.csv" to read data


  if (infoFile) {  //checking that the file opened
    // Read one line, up to 60 characters.
    for (int i = 0; i < 60; i++) {
      readLine[i] = infoFile.read();// loading characters into the char array
      readline[i + 1] = '\0'; // Add null terminator


      if (readLine[i] == '\n') // Newline
      {
        readLine[i] = '\0'; // Terminator
        break;
      }
    }


    Serial.println(readLine);
    infoFile.close();
  }
  else
  {
    Serial.println("Failed to open file infoFile.csv");
    readLie[0] = '\0';
  }


  char* tokenValue; //creating a pointer that will point to the first section of the array between the two ";"
  tokenValue = strtok(readLine, ";"); //there is also something going on here with putting a /0 at the end so it can find where to start next time


  while (tokenValue != NULL)
  {
    Serial.print("Token \"");
    Serial.print(tokenValue);


    if (j < 20)
    {
      infoFileArray[j] = atoi(tokenValue); // changing from char string to int and storing in array
      Serial.print("\" as integer is: ")
      Serial.println(infoFileArray[j]);
      j++;


      tokenValue = strtok (NULL, ";");
    }
  }

Hi John, thanks a lot for the code, i learnt quite a bit from it. After implementing it in two other places that i was reading from the SD card i got it all to work. Oh and yes the numbers for the arrays and for loops were all over the place but that was mostly because after sitting and trying to solve it for hours i was just trying anything that i could to understand what was going on... but thanks again :slight_smile: