Why can't I declare this locally?

So I was reading this thread.

And I got to wondering about what the sprintf() was actually going to do in the example. I didn’t think the commas between the strings would actually be there and the strings would be all squished together.
So I wanted to see, and if they were not I wanted to see if I could figure out how to add them so the serial monitor output would match what the OP’s strcat() output looked like. And I wanted to see if I could do the strcat() in a loop as was suggested.

So I ended up with this code.

char data_fil[0xff];
boolean shouldPrint = true;

void setup() {
  Serial.begin(9600);
}
void loop() {
  if(shouldPrint){
  strcatWay();
  sprintfWay();
  sprintfWay2();
  tryALoop();
  }
}
void strcatWay() {
  strcat(data_fil, "header");
  strcat(data_fil, ",");
  strcat(data_fil, "string2");
  strcat(data_fil, ",");
  strcat(data_fil, "string3");
  strcat(data_fil, ",");
  strcat(data_fil, "string4");
  //strcat(data_fil, '\0');
  Serial.println(data_fil);
}
void sprintfWay() {
  sprintf( data_fil, "%s%s%s\n",  "string1", "string2", "string3" );
  Serial.print(data_fil);
}
void sprintfWay2() {
  sprintf( data_fil, "%s%s%s%s%s%s%s\n", "headera", "," , "string2" , "," , "string3" , "," , "string4" );
  Serial.print(data_fil);
}
void tryALoop() {
  char* charArray[] = {"headerb", "string2", "string3", "string4"};
  for (int i = 0; i < 4; i++) {
    strcat(data_fil, charArray[i]);
    if (i < 3) {
      strcat(data_fil, ",");
    }
  }
  Serial.println(data_fil);
  shouldPrint = false;
}

And it almost worked as I wanted.
But I would get what seemed like a double print on the serial monitor of my sprintfWay2().
So I commented out the call to sprintWay2() and then got a double print sprintWay().

Then after a bit of puzzling over this I realized that because data_fil was global the way I was using strcat() in my tryALoop() I was just concatenating to the data that was put into data_fil by the previous function which would explain why whatever function called before tryALoop() would appear to print twice.

So I get the idea to just make data_fil local to each function. That way each function gets a nice empty version to work with.

And that made a huge mess of my serial monitor output.

I couldn’t see where I had messed up pasting in char data_fil[0xff]; to each of my functions. So I decided to just start over and test each function as I go.

So I started out with this

char data_fil[0xff];
void setup() {
  Serial.begin(9600);
}
void loop() {
  tryStrcat();
  while(1);      
}
void tryStrcat(){
  strcat(data_fil,"header");
  strcat(data_fil,",");
  strcat(data_fil,"string2");
  strcat(data_fil,",");
  strcat(data_fil,"string3");
  strcat(data_fil,",");
  strcat(data_fil,"string4");
  Serial.println(data_fil);
}

And that works. So I cut and paste char data_fil[0xff]; from before void setup() to inside tryStrcat() like this

void setup() {
  Serial.begin(9600);
}
void loop() {
  tryStrcat();
  while(1);      
}
void tryStrcat(){
  char data_fil[0xff];
  strcat(data_fil,"header");
  strcat(data_fil,",");
  strcat(data_fil,"string2");
  strcat(data_fil,",");
  strcat(data_fil,"string3");
  strcat(data_fil,",");
  strcat(data_fil,"string4");
  Serial.println(data_fil);
}

And it doesn’t work. Sometimes serial monitor shows nothing, sometimes a big mess again.
So I try to add a NULL terminator

void tryStrcat(){
  char data_fil[0xff];
  strcat(data_fil,"header");
  strcat(data_fil,",");
  strcat(data_fil,"string2");
  strcat(data_fil,",");
  strcat(data_fil,"string3");
  strcat(data_fil,",");
  strcat(data_fil,"string4");
  strcat(data_fil, '\0');
  Serial.println(data_fil);
}

And I still get nothing on serial monitor.
I cut and paste char data_fil[0xff]; to back above void setup() and it prints fine on serial monitor again.

So why can’t char data_fil[0xff]; be declared in the function and work like it does when declared globally?

When data_fil is declared inside a function, it is allocated on the stack, which is not initialized. When it is declared as a global it is initialized to zero. So when you do the first strcat when data_fil is declared in the function, there is no guarantee that the first character of data_fil is a null. So strcat will concantenate your first string on the end of whatever garbage happens to be in data_fil at the time - and it doesn't even have to contain a null at all so you could concatenate the string way beyond the end of the char array.

Fix is to insert

data_fil[0] = 0;

at the beginning of the function.

Pete

That explains it very well, thank you.