views:

572

answers:

4

Hey everyone, I am getting a heap corruption error I cannot figure out.

char * c = (char *) malloc(1);
// main loop
_gcvt_s(c, 100, ball->get_X_Direction(), 10);
   if(pushFont(c, (SCREEN_WIDTH - 30), (SCREEN_HEIGHT - 40), message, screen,
font, textColor) == false)
   {
     //return 1; // error rendering text.
   }
// end main loop
free(c);

The above code is the only time I use c pointer, in _gcvt_s and pushFont() which simply accepts a char * as its first parameter, and puts the text on the screen. Other then that I do not use c. When I try to free c after the main loop (which I think I am supposed to do), I get an error saying Visual Studio has acquired an error with the heap (heap corruption).

Commenting out the call to pushFont I still receive the error.

Can anyone explain to me why freeing a character (the 1 byte I allocated on the heap) would give me a heap corruption?

Lastly my main loop does a lot of stuff, a buddy and I are making a pong game with WinSocket, the rest of the main body is the loop for the game. I didnt think it was necessary to post, but I will update my post with the entire main loop if it is necessary, but I believe I am just off with my understanding of malloc() and free().

Thanks all,

+9  A: 

Doesn't _gcvt_s use the 2nd parameter as the max size of the allocated buffer? You allocate 1 byte but tell _gcvt_s there are 100. So it happily writes up to 100 bytes into the buffer corrupting your heap. Then the free crashes. Allocate 100 bytes if you are going to potentially access 100 bytes.

EDIT: It sounds like you need to learn how C stores and manipulates strings. C stores strings as individual bytes in contiguous runs of memory followed by an extra character to indicate the end of the string. This extra character has an ASCII value of 0 (not the character '0' which is ASCII 48). So if you have a string like "HELLO", it takes 6 bytes to store - one for each of the 5 letters and the terminator.

In order for _gcvt_s() to return the value to your buffer, you need to include enough bytes for the conversion and the extra terminating byte. In the case of _gcvt_s(), you are asking for 10 characters of precision. But you also have to reserve room for the decimal point, the potential negative sign.

According to this documentation, there is a #define in the headers for the maximum necessary size of the buffer: _CVTBUFSIZE. The example there should help you with this issue.

jmucchiello
I did not want to ask two questions in one post but...My question, for the second parameter it wants the size in bytes of the buffer. With my code I wanted 10 precision when converting. My reasoning was that if it wants the number of bytes needed to store the converted character, if each char is 1 byte, then I should put 10 there. Error. For some reason I tried 100 and it works, but I have no idea what the second parameter is asking for.
Ben Adamson
It is quite simple - the second parameter is you telling the _gcvt_s function how many bytes you have allocated (using malloc) in the buffer in the first parameter. You are lying to the function because you only allocated one byte, not 100. You should pass 100 as the first parameter to malloc - this will match up with the size you have said you allocated
1800 INFORMATION
Ok, I understand all that. Thank you very much. I do have one follow up, purely for my understanding (passing 100 bytes seems quite unnecessary). Why does the following not work? _gcvt_s(c, 1, ball->get_X_Direction(), 1); I allocated 1 byte, I didn't lie about that, and in the 4th parameter I told it I only want 1 byte worth of precision.
Ben Adamson
If you pass one byte, it can't convert the value to a string ( as the one byte is used to nul terminate the string ), so I'd imagine the return value ( which you ignore ) indicates an error, and what is in the buffer is undefined.
Pete Kirkham
+3  A: 

Why do you need to use the heap? If all you need is space for 1 char can't you just use a local variable:

char c;
_gcvt_s(&c...

?

20th Century Boy
When I used a local variable I received a stack corruption error when my main function tries to unwind (I think that what was happening when I got the error, it never happens until I close the program).
Ben Adamson
Well, that will happen if _gcvt_s writes more than 1 char using the pointer. In that case you need to pass a bigger buffer.
20th Century Boy
+4  A: 

According to the documentation I can find _gcvt_s() takes a buffer and the length of that buffer as the first two arguments.

errno_t _gcvt_s( 
   char *buffer,
   size_t sizeInBytes,
   double value,
   int digits 
);

Your malloc()ed buffer is 1 byte long, you tell _gcvt_s() it is 100 bytes long. I would start looking here.

Beano
+1  A: 

You need more than one byte to store a float. Allocate a more practical length than 1 byte...

You also really don't need the heap, try a (slightly oversized) 16-byte buffer and giving _gcvt_s the correct buffer length (instead of the magical 100 you are giving it). De-magic your constants whilst you are at it.

const unsigned int cuFloatStringLength = 16;
const unsigned int cuFloatStringPrecision = 10;

char c[cuFloatStringLength];

_gcvt_s( c, cuFloatStringLength, ball->get_X_Direction(), cuFloatStringPrecision );

The problem should then be gone.

jheriko
Ok, this worked. Also I changed the cuFloatStringLength to 11 allowing for the 10 characters and the one NULL terminator. Error. 12 works with no errors, but 11 fails. Do you know what the last byte (12th) would be storing?
Ben Adamson
Is "cu" the Hungarian notation for "copper"? Show you really care and allocate your constants out of "ag" or "au" instead.
bk1e
I used "cu" for the previous posters example.
Ben Adamson