简体   繁体   中英

c manipulating pointer to char array, confusion

I have written code manipulating pointers to a char array for formatting time and date from a NMEA RMC sentence for an arduino pro mini, like so:

char *UTC = "120435";
char *DATE = "050117";

char TIME[9];
char *ptr = TIME;
char *fieldPtr = UTC;
for (int a = 0; a < 8; a++) {
    *ptr++ = *fieldPtr++;
    if (a == 1 || a == 3) {
        *ptr = ':';
        ptr++;
    }
}
*ptr = '\0';
Serial.print("TIME: ");   
Serial.println(TIME);     //output: "12:04:35"  //-OK

char date[9];
ptr = date;
fieldPtr = DATE;
for (int a = 0; a < 8; a++) {
    *ptr++ = *fieldPtr++;
    if (a == 1 || a == 3) {
        *ptr = '.';
        ptr++;
    }
}
*ptr = '\0';
Serial.print("TIME: ");
Serial.println(TIME);        //output: "d"  //whatever follows DATE
Serial.print("date: ");
Serial.println(date);        //output: "05.01.17"  //-OK

The output of TIME in the second round appears to be some character that follows DATE in the memory.

Can anybody help me please to explain what is going on?

Your loop has too many iterations. It must copy the input strings, which are length 6, and inserts two additional characters. But that doesn't change the input length. Change your loops to:

for (int a = 0; a < 6; a++) {
   ...

You are reading and writing outside array boundaries.

Look at this part:

for (int a = 0; a < 8; a++) {
    *ptr++ = *fieldPtr++;

In the first loop you access UTC through fieldPtr . In memory UTC looks like:

'1' '2' '0' '4' '3' '5' '\0'

So when a is 0 you read 1 , when a is 1 you read 2 and so on. Like:

'1' '2' '0' '4' '3' '5' '\0' 
 ^   ^   ^   ^   ^   ^   ^   ^
a=0 a=1 a=2 a=3 a=4 a=5 a=6 a=7

For a=7 you read outside the array which is illegal (ie undefined bahvior).

For the writing part it is more or less the same. Except that you have two extra increments of ptr . So the writing is:

TIME[0] TIME[1] TIME[2] TIME[3] TIME[4] TIME[5] TIME[6] TIME[7] TIME[8]
 ^       ^       ^       ^       ^       ^       ^       ^       ^       ^
a=0     a=1     a=1     a=2     a=3     a=3     a=4     a=5     a=6     a=7

So again - when a=7 you write outside TIME . In fact you write once more after the loop: *ptr = '\\0';

So all together "Undefined behavior".

When you have undefined behavior it doesn't make sense from a language point of view to discuss what is going on.

However, you can analyse what happened on your specific system. It could be that when you write to DATE in the second loop and write outside the DATE array, the data written may end up in TIME and thereby destroying the original value and consequently you get wrong prints. Once again - notice that this would be system specific. On my system your code produce the expected output despite the undefined behavior.

To fix you problem see the answer from @PaulOgilvie

Since you are dealing with small fixed size input strings an alternative solution that avoid all the pointer stuff, could be:

  char *UTC = "120435";
  char TIME[9];
  if (strlen(UTC) == 6)
  {
      sprintf(TIME, "%c%c:%c%c:%c%c", UTC[0], UTC[1], UTC[2], UTC[3], UTC[4], UTC[5]);
      printf("%s\n", TIME);
  }
  else
  {
    printf("wrong format\n");

    // .... add error handling here ....
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM