Data still being recorded after exiting a loop

I'm writing a code to parse GPS data, and I've successfully written a checksum routine and now I'm looking at all $GPGGA sentences.

A standard GPGGA sentence looks like this:

$GPGGA,181600.000,4043.2087,N,07436.3990,W,1,04,4.3,225.7,M,-34.1,M,,0000*61

You can find more info about what each part is here: http://aprs.gids.nl/nmea/#gga

This is the code I have written to try to extract the relevant data:

if (!strncmp(sentence,"$GPGGA,", 7))
      {
        GPAflag = 1;
        int index = 7;
        dataextract(index, sentence, time);
        dataextract(index, sentence, latitude);
        dataextract(index, sentence, signlatitude);
        dataextract(index, sentence, longitude);
//        Serial.print("longitude has been recorded as: ");
//        Serial.println(longitude);
        dataextract(index, sentence, signlongitude);
//        Serial.print("longitude has been recorded as: ");
//        Serial.println(longitude);
        dataextract(index, sentence, fix_validity);
//        Serial.print("fix_validity has been recorded as: ");
//        Serial.println(fix_validity);
        dataextract(index, sentence, numberofsatellites);
        Serial.print("numberofsatellites has been recorded as: ");
        Serial.println(numberofsatellites);
        dataextract(index, sentence, HDOP);
        Serial.print("numberofsatellites has been recorded as: ");
        Serial.println(numberofsatellites);
        dataextract(index, sentence, altitude);
        Serial.print("numberofsatellites has been recorded as: ");
        Serial.println(numberofsatellites);
}
if (GPAflag)
      {
        GSAflag = 0;
        GPAflag = 0;
        Serial.print("$PRHAL,");
        Serial.print(fix_validity);
        Serial.print(",");
        Serial.print(latitude);
        Serial.print(",");
        Serial.print(signlatitude);
        Serial.print(",");
        Serial.print(longitude);
        Serial.print(",");
        Serial.print(signlongitude);
        Serial.print(",");
        Serial.print(numberofsatellites);
        Serial.print(",");
        Serial.print(altitude);
        Serial.println("*");
      }

And the data_extract function:

char *dataextract(int &index, char * GPSdata, char data[])
{
  int j = 0;
  while (GPSdata[index] != ',')
  {
    data[j] = GPSdata[index];
    index++;
    j++;
  }
  index++;
  return data;
}

So you'll notice I'm printing the char array numberofsatellites several times, here is the result of that:

numberofsatellites has been recorded as: 04
numberofsatellites has been recorded as: 044.0
numberofsatellites has been recorded as: 044.0314.5
$PRHAL,1,4043.1907,N,07436.3918W,W,044.0314.5,314.5*
$GPGGA,180511.000,4043.1907,N,07436.3918,W,1,04,4.0,314.5,M,-34.1,M,,0F
numberofsatellites has been recorded as: 044.0314.5

So basically, it gets recorded correctly, but then more data is recorded! What's even weirder, at least for a novice programmer like me, is that sometimes a value gets recorded properly and sometimes it doesn't. Here's the current status:

Gets recorded properly: time latitude signlatitude signlongitude fix_validity altitude

Get recorded, but wit extras: longitude numberofsatellites and probably HDOP as well

Why would data continue to be recorded in these arrays after the dataextract function has already returned the value? And how can I fix it?

I should add how the variables are initialized:

char GPSbyte;
char sentence[80];
int i = 0;
int sum = 0;
int good_sentences = 0;
int bad_sentences = 0;
char message[50];
char reportedsumchar[3];
char computedsumchar[3];
char time[11];
char latitude[10];
int GPAflag = 0;
int GSAflag = 0;
char signal;
char signlatitude[2];
char longitude[10];
char signlongitude[2];
char fix_validity[2];
char numberofsatellites[2];
char HDOP[3];
char altitude[10];

I first noticed the issue when longitude was printing incorrectly, and so one of the first things I checked was the char array sizes, and sure enough they were the same. I've only posted snippets of code to try to keep everything organized, but if you think the problem might be elsewhere let me know and i'll post more.

And… a little bit of experimentation clears everything up.

Turns out the array sizes were in fact just a little too small, whereas I thought they were just right. Can anyone explain why the code arbitrarily increases the array size and keeps writing past the end of it?

I now have one more issue, although I think this one can be safely ignored based on how many times I’ve run the code.

Some sentences are getting skipped, as you see below, the seconds GPGSV sentence is missing (the 3,1 and then 3,3 means that there are 3 GPGSV messages, this is message 1 and this is message 3. There should be a 3,2, but there isn’t):

$GPGSV,3,1,09,08,71,266,,11,64,117,22,07,59,191,,24,48,138,*79
$GPGSV,3,3,09,03,06,063,*40

My main concern is that the GPGGA sentences, which contain all crucial data, will get skipped. So far, those have always shown up, and at times when I was using a different code and getting the same sentence skipped issue, those would be the ONLY sentences that showed up. Still, it would be nice to know what’s going on here.

Here’s my full code:

#include <SoftwareSerial.h>
SoftwareSerial gps = SoftwareSerial(3,4);

//#include <NewSoftSerial.h>
//NewSoftSerial gps(3,4);

char GPSbyte;
char sentence[80];
int i = 0;
int sum = 0;
int good_sentences = 0;
int bad_sentences = 0;
char message[50];
char reportedsumchar[5];
char computedsumchar[5];
char time[11];
char latitude[10];
int GPAflag = 0;
int GSAflag = 0;
char signal;
char signlatitude[2];
char longitude[11];
char signlongitude[2];
char fix_validity[2];
char numberofsatellites[3];
char HDOP[4];
char altitude[10];

void setup()
{
  gps.begin(4800); //GPS communications occur at 4800 baud
  Serial.begin(9600); //This value can be any baud rate you like, so long as you can tune to it in the serial monitor
}

void loop()
{
  GPSbyte = gps.read();
  if (GPSbyte != -1)
  {
    if (GPSbyte == '

)
    {
      i = 0;
      while (GPSbyte != 10 && i < 80)
      {
        sentence[i] = GPSbyte;
        GPSbyte = gps.read();
        i++;
      }
      checksum(sentence, computedsumchar);
      reportedsumchar[0] = sentence[i-3];
      reportedsumchar[1] = sentence[i-2];
//      Serial.print(“Reported checksum: “);
//      Serial.print(reportedsumchar);
//      Serial.print(”, Computed checksum: “);
//      Serial.print(computedsumchar);
//      Serial.print(”, Comparision yieds: “);
//      Serial.println(strcmp(computedsumchar,reportedsumchar));
      if (strcmp(computedsumchar,reportedsumchar) == 0)
      {
        if (!strncmp(sentence,”$GPGGA,”, 7))
        {
          GPAflag = 1;
          int index = 7;
          dataextract(index, sentence, time);
          dataextract(index, sentence, latitude);
          dataextract(index, sentence, signlatitude);
          dataextract(index, sentence, longitude);
          dataextract(index, sentence, signlongitude);
          dataextract(index, sentence, fix_validity);
          dataextract(index, sentence, numberofsatellites);
          dataextract(index, sentence, HDOP);
          dataextract(index, sentence, altitude);
        }
        if (GPAflag)
        {
          GSAflag = 0;
          GPAflag = 0;
          Serial.print("$PRHAL,");
          Serial.print(fix_validity);
          Serial.print(",");
          Serial.print(latitude);
          Serial.print(",");
          Serial.print(signlatitude);
          Serial.print(",");
          Serial.print(longitude);
          Serial.print(",");
          Serial.print(signlongitude);
          Serial.print(",");
          Serial.print(altitude);
          Serial.println("*");
        }
      }
      Serial.println(sentence);
      cleararray(sentence, sizeof(sentence));
    }
  }
}

char *checksum(char * GPSdata, char computedsum[3])
{
  sum = 0;
  int j = 0;
  while (j < i)
  {
    byte data = GPSdata[j];
    switch (data)
    {
    case ’


:
      break;
    case '*':
      j = i;
      break; //this indicates the end of the sentence
    default:
      if (sum == 0)
      {
        sum = GPSdata[1];
      }
      else
      {
        sum ^= data;
      }
    }
    j++;
  }
  sprintf(computedsum,"%2X",sum);
  return computedsum;
}

char *dataextract(int &index, char * GPSdata, char data[])
{
  int j = 0;
  while (GPSdata[index] != ',')
  {
    data[j] = GPSdata[index];
    index++;
    j++;
  }
  index++;
  return data;
}

char *cleararray(char *array, int arraysize)
{
  for (int k = 0; k<=arraysize; k++)
  {
    array[k] = '\0';
  }
  return array;
}

Can anyone explain why the code arbitrarily increases the array size and keeps writing past the end of it?

No - your software keeps writing past the end of it.

      while (GPSbyte != 10 && i < 80)
      {
        sentence[i] = GPSbyte;
        GPSbyte = gps.read();
        i++;
      }

There still exists the possibility that you will try to read a byte that isn’t present yet, and end up storing a -1 in sentence.

      if (strcmp(computedsumchar,reportedsumchar) == 0)

reportedsumchar is not a NULL terminated array of characters, so it should not be passed to a function that expects a NULL terminated array of characters.

          dataextract(index, sentence, time);

The dataextract() function has no idea how big the array in the third argument is, so it has no way to prevent writing past the end of the array.

None of the calls to checksum(), dataextract(), or cleararray() use the return value. These functions should not be returning a pointer to the input array. Change the return type to void, and remove the return statement.