Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Arduino, use of sprintf inside a method with a char pointer parameter, breaks program

I have worked for most of the day on this problem and have narrowed it down to the following simple program to replicate it: Test.ino

// the setup function runs once when you press reset or power the board
void setup() {
    Serial.begin(9600);
}

// the loop function runs over and over again until power down or reset
void loop() {
    char _message[16] = { '\0' };
    char *message = _message;
    int pins[1] = { 1 };

    //testOne(pins, 35, 5); // WORKS!!

    testTwo(pins, 35, 5, message);  // Desn't Work...
}

void testOne(int sensorPins[], int userDefault, int offset) {
    char _int_char[2];
    sprintf(_int_char, "%d", 36);
    Serial.println(_int_char);
}

void testTwo(int sensorPins[], int userDefault, int offset, char *message) {
    char _int_char[2];
    sprintf(_int_char, "%d", 37);
    Serial.println(_int_char);
}

All the above code does is call the testOne and testTwo functions.

The testOne function gives the expected outcome of the value of 36 being written to the serial window for each iteration of the loop.

The testTwo function writes the following to the serial window: "VMDPV_1|1_VMVMDPV_1|1_VM".....

This only happens when I add the char *message parameter to the function. Obviously this is a very simplified demo with hard coded values etc... in my actual code I make use of the parameters and there is a lot more going on...

It is actually the call to sprintf that causes the issues. In my actual code I use this as a part of building up the message. When I comment out the sprintf line in my actual code it works. But of course I need that line to get the value of one of the parameters into the message.

Can anyone out there tell me why sprintf doesn't work in a function that has a char *message param?

I am using an Arduino UNO and have written the code in Visual Studio using Visual Micro 1511.23.1, which does it's bulid based on the installed arduino IDE setup which is 1.6.5.

I have been able to replicate this in the arduino IDE as well, except I get different characters than "VMDPV_1..."... I got a, 3 a letter O with a upside down comma on top and a square.

I am developing all this on a Win 10 64bit PC.

Thanks for your time,

Scott

like image 877
user2109254 Avatar asked Dec 07 '25 05:12

user2109254


2 Answers

Your program produces undefined behavior due to a buffer overrun.

char _int_char[2];
sprintf(_int_char, "%d", 37); // <-- buffer overrun

Since the resulting string may occupy more than 2 characters, the excess characters overflow the _int_char array and will overwrite memory. What is at the overwritten memory before the corruption may have something to do with the parameter message.

Instead of creating a 2 character array, declare the array big enough to not produce a buffer overflow.

char _int_char[20];
sprintf(_int_char, "%d", some_integer);

Unless you have integers that have more than 19 digits, this should now not overflow the buffer.


A foolproof solution, since you're using C++, is to use C++ streams, namely std::ostringstream. Then you need not worry about buffer overruns, regardless of the length of the data to be outputted:

#include <sstream>
#include <string>
//...
std::string _int_char;
std::ostringstream strm;
strm << some_integer;
_int_char << strm.str();
like image 151
PaulMcKenzie Avatar answered Dec 09 '25 04:12

PaulMcKenzie


In C strings are 0-terminated, meaning that after the call to sprintf, _int_char contains { '3', '6', '\0' }. This is an array of 3 chars and you only reserver memory for 2

char _int_char[2];
sprintf(_int_char, "%d", 36);
like image 33
Serve Laurijssen Avatar answered Dec 09 '25 04:12

Serve Laurijssen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!