1

大家好,我遇到了一个我无法弄清楚的堆损坏错误。

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);

上面的代码是我唯一一次在 _gcvt_s 和 pushFont() 中使用 c 指针,它只接受一个 char * 作为它的第一个参数,并将文本放在屏幕上。除此之外我不使用c。当我尝试在主循环之后释放 c(我认为我应该这样做)时,我收到一条错误消息,指出 Visual Studio 已获得堆错误(堆损坏)。

注释掉对 pushFont 的调用我仍然收到错误。

谁能向我解释为什么释放一个字符(我在堆上分配的 1 个字节)会给我一个堆损坏?

最后,我的主循环做了很多事情,我和一个伙伴正在用 WinSocket 制作乒乓球游戏,主体的其余部分是游戏的循环。我认为没有必要发帖,但如果有必要,我会用整个主循环更新我的帖子,但我相信我对 malloc() 和 free() 的理解刚刚结束。

谢谢大家,

4

4 回答 4

11

_gcvt_s 不使用第二个参数作为分配缓冲区的最大大小吗?您分配了 1 个字节,但告诉 _gcvt_s 有 100 个。所以它很乐意将多达 100 个字节写入缓冲区,从而破坏您的堆。然后免费崩溃。如果您打算访问 100 个字节,请分配 100 个字节。

编辑:听起来您需要学习 C 如何存储和操作字符串。C 将字符串作为单独的字节存储在连续的内存中,后跟一个额外的字符来指示字符串的结尾。这个额外字符的 ASCII 值为 0(不是字符“0”,即 ASCII 48)。所以如果你有一个像“HELLO”这样的字符串,它需要6个字节来存储——5个字母和终止符中的每一个。

为了让 _gcvt_s() 将值返回到缓冲区,您需要包含足够的字节用于转换和额外的终止字节。在 _gcvt_s() 的情况下,您要求 10 个字符的精度。但是您还必须为小数点(潜在的负号)保留空间。

根据这个[文档]( http://msdn.microsoft.com/en-us/library/a2a85fh5(VS.80).aspx),在标题中有一个#define 用于缓冲区的最大必要大小: _CVTBUFSIZE。那里的示例应该可以帮助您解决这个问题。

于 2009-05-25T07:42:50.550 回答
4

根据文档,我可以找到_gcvt_s()一个缓冲区和该缓冲区的长度作为前两个参数。

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

您的malloc()ed 缓冲区长 1 个字节,您告诉_gcvt_s()它长 100 个字节。我会开始在这里寻找。

于 2009-05-25T07:47:39.980 回答
3

为什么需要使用堆?如果您只需要 1 个字符的空间,您不能只使用局部变量:

char c;
_gcvt_s(&c...

?

于 2009-05-25T07:44:02.263 回答
2

您需要一个以上的字节来存储浮点数。分配比 1 字节更实用的长度...

你也真的不需要堆,尝试一个(稍微过大的)16字节缓冲区并给_gcvt_s正确的缓冲区长度(而不是你给它的神奇的100)。当你在它的时候,去魔化你的常数。

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

char c[cuFloatStringLength];

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

那么问题应该就消失了。

于 2009-05-25T10:51:44.070 回答