Trouble with sprintf()

I've been attempting to display the elements of an array in a formatted way using sprintf(). My program fills a char array with the letters of the alphabet. Then I grab 4 characters at a time from that array and attempt to display them on the serial monitor. The first line of the display is correct, but that afterward is wrong. Seems that the sprintf() statement is changing things. If I run the same program with the sprintf() commented out I get the letters I was looking for. Any help? Thanks Mike

char dat[30];
char a[10];
int offSet;
int i;

void setup() {
  Serial.begin(115200);

  for (i =0; i<=25; i++){         //fill dat with letters
    dat[i] = 0x41 + i;
  }

  for (int j = 0; j<=8; j+=4){
      for (i=0; i<=3; i++){       //fills a with 4 characters from dat
        a[i] = dat[i + j]; 
        }
  sprintf(a, "%03x: %02x, %02x, %02x, %02x", j, a[0], a[1], a[2], a[3]);
  Serial.println(a);        //display the 4 characters
  }
}
void loop() {
  // put your main code here, to run repeatedly:

}

Your sprintf is overwriting the char array a. Not only that, it is writing past the end of the array a corrupting other memory.

Yup, it must be doing something, but how do I use sprintf() properly so it does not? Mike

mike_zahorik:
Yup, it must be doing something, but how do I use sprintf() properly so it does not? Mike

Just create another char array for sprintf to write to. Make sure it has enough characters to handle the write. Looking at your sprintf you will need at least 20 characters (including the null character).

Use snprintf(), which will not write past the end of the output buffer.

jremington:
Use snprintf(), which will not write past the end of the output buffer.

Even better idea!!! But he still needs a buffer with at least 20 characters.

That seems to work. Can you tell me why sprintf() was overwritting? I don't fully understand this function. Thanks Mike

This was your line of code:

  sprintf(a, "%03x: %02x, %02x, %02x, %02x", j, a[0], a[1], a[2], a[3]);

You have the char array a defined with a length of 10. Here is the the character string this sprintf would produce:

000: 41, 42, 43, 44

That is 19 characters long but you have to account for the null terminating character which makes it 20. 20 is greater than 10 so it writes past the end of a by 10 characters. Since arrays are passed by reference (pointer) sprintf has no way of knowing how long a is and assumes you know what you are doing.

So, does sprintf()fill my char a array when it runs? And that is why it overwrites. I did not see any reference to that fact in the description of the function. I sure would like to see a complete listing of these functions. Do you think that a good book covering C++ would have this? I've been searching for a good reference book for a while. Thanks for the help.

mike_zahorik:
I sure would like to see a complete listing of these functions.

https://www.nongnu.org/avr-libc/user-manual/modules.html
and especially
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html

Thank you, Mike

mike_zahorik:
So, does sprintf()fill my char a array when it runs? And that is why it overwrites. I did not see any reference to that fact in the description of the function. I sure would like to see a complete listing of these functions. Do you think that a good book covering C++ would have this? I've been searching for a good reference book for a while. Thanks for the help.

You told sprintf to write into your a array so I'm not sure I understand the question. The first parameter in the sprintf is the string to write to. Therefore, you were using a as input and output to sprintf!!!

Here is what I think is correct and seems to work. Thanks for the Help Mike

//filename = sprintf April 2, 2020
// Shows how sprintf() works. The array to be displayed is dat. The a array is used to 
// select 16 bytes to be displayed per line and is the input to sprintf. Sprintf gets data from
// the a array, formats it as shown in the "string", then saves it in buf. The Serial.print
// sends each line to Serial Monitor.

char dat[110];                    //Full array of ASCII characters
char a[110];                      //16 byte section of Full array
char buf[110];                    //Output array for sprintf

int i;
int j;

void setup() {
  Serial.begin(115200);

  for (i =0; i<=100; i++){         //fill dat with ASCII characters
    dat[i] = 0x20 + i;
  }

  for (j = 0; j<=80; j+=16){        //how many lines in the display
      for (i=0; i<=15; i++){       
        a[i] = dat[i + j];          //Grab 16 bytes to use as input for sprintf
        }
  sprintf(buf, "%03x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x",
  j, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
  a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
  Serial.println(buf);              //buf is the output display of the 16 characters
  }
}
void loop() {
  // put your main code here, to run repeatedly:

}

mike_zahorik:
Here is what I think is correct and seems to work. Thanks for the Help Mike

Yes. That will work. I would still recommend using snprintf in order to prevent writing past the end of buf.

snprintf ( char * s, size_t n, const char * format, ... );