C编程,char数组内存分配问题

时间:2014-03-15 12:41:33

标签: c memory-management

我正在开发一个小型C库来教授视频游戏编程,我创建了一个简单的功能来在屏幕上绘制格式化文本(即得分,生活)。功能是:

const char *FormatText(const char *text, ...)
{
    int length = strlen(text);
    char *buffer = malloc(length + 20);

    va_list args;
    va_start(args, text);
    vsprintf(buffer, text, args);
    va_end(args);

    return buffer;
}

此功能在主游戏循环中使用,在Draw部分中,如下所示:

DrawText(FormatText("%02i", score), 10, 10, 40, BLACK);

DrawText()函数中的额外参数,只表示屏幕坐标X,Y,字体大小和颜色。

我每秒呼叫这个功能大约60次(甚至更多),所以,如果我是对的,我会在每次呼叫时分配新内存......而且我'永远不要释放那段记忆!

如何以同样的方式继续使用我的功能来解决这个问题?

我的第一个想法是在我的库上创建一个全局char *缓冲区,在初始化时分配它并一直重用它......但我不确定这是不是最好的主意,我试试避免太多全局变量。

非常感谢您的回答!

更新

再次感谢大家的回答。

最后我解决这个问题的方法是使用:

const char *FormatText(const char *text, ...)
{
    static char buffer[MAX_FORMATTEXT_LENGTH];

    va_list args;
    va_start(args, text);
    vsprintf(buffer, text, args);
    va_end(args);

    return buffer;
}

可能不是最好的解决方案,但我认为它对于lib的用户来说是最好的,而不必担心内存管理。

这是一个简单的用法示例:

#include "raylib.h"

int main()
{
    int score = 100020;
    int hiscore = 200450;
    int lives = 5;

    InitWindow(800, 450, "testing FormatText()");

    SetTargetFPS(60);

    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        BeginDrawing();

            ClearBackground(RAYWHITE);

            DrawText(FormatText("Score: %08i", score), 80, 80, 20, RED);
            DrawText(FormatText("HiScore: %08i", hiscore), 80, 120, 20, GREEN);
            DrawText(FormatText("Lives: %02i", lives), 80, 160, 40, BLUE);
            DrawText(FormatText("Elapsed Time: %02.02f ms", GetFrameTime()*1000), 80, 220, 20, BLACK);

        EndDrawing();
    }

    CloseWindow();

    return 0;
}

结果是:

testing FormatText() raylib function

2 个答案:

答案 0 :(得分:1)

我将管理内存的责任传递给父功能。它会根据需要分配和释放,而不是FormatText()本身

// somefunction
    char *buffer;
    buffer = malloc(<somesize>);
    if (buffer) {
        FormatText(buffer, "%02i", ...);
        free(buffer);
    }

答案 1 :(得分:0)

你的函数几乎已经存在于某些Libc中,如GNU libc,它被称为asprintf(3)。调用者应该free malloc - ed缓冲区。

您可以将其用作:

char* msg=NULL;
DrawText((msg=FormatText("%02i", score)), 10, 10, 40, BLACK);
free (msg);

或者,如果使用asprintf,则使用comma operator

char* msg=NULL;
DrawText((asprintf(&msg,"%02i",score),msg), 10, 10, 40, BLACK);
free (msg);

最后,如果您因为应该调用free而感到困扰,您可以决定整个程序使用Boehm garbage collector(因此您打电话给GC_MALLOC并且不要#39;打扰GC_FREE)。然后你要定义

char* GC_sprintf(const char*fmt, ...) {
   char buf[128];
   va_list ap;
   va_start (ap, fmt);
   int sz = vsnprintf(buf, sizeof(buf), fmt, ap);
   va_end (ap);
   if (sz < sizeof(buf)) return GC_strdup (buf);
   char* gcbuf = GC_MALLOC_ATOMIC (sz+1);
   memset (gcbuf, 0, sizeof (gcbuf));
   va_start (ap, fmt);
   vsnprintf(gcbuf, sz, fmt, ap);
   va_end (ap);
   return gcbuf;
}

然后直接致电

DrawText(GC_sprintf("%02i",score), 10, 10, 40, BLACK);

BTW,由于"%02i"格式产生一个短字符串,您可以使用

char locbuf[8];
snprintf (locbuf, sizeof(locbuf), "%02i", score);
DrawText(locbuf, 10, 10, 40, BLACK);

您甚至可以考虑定义可变参数DrawText_printf并调用

DrawText_printf(10, 10, 40, BLACK, "%02i", score);