在C语言中返回char *时如何避免内存泄漏?

How to avoid memory leak while returning char * in C?

提问人:PlsBuffMyBrain 提问时间:9/24/2023 最后编辑:ChrisPlsBuffMyBrain 更新时间:9/25/2023 访问量:78

问:

我在 C 中有一个这样的代码库,其中我有一个需要返回 char * 的函数。有没有办法修改此代码,以便我可以返回 char *而不会像这里一样导致内存泄漏?Glib 已经是一个依赖项,所以我也可以使用 Glib 函数。我知道代码很糟糕,它是由拥有物理学学位的人而不是工程师编写的。

char *func(int val) {
    char *name = malloc(300);
    if (!name) return NULL;

    switch(value) {
    case 0: 
        {
            name = "dog";
        }
        break;
   
    case 1:
        {
            name = "cat";
        }
        break;
  
    case 2:
        {
            name = "elephant";
        }
        break;

    default: 
        name = "wrong entry";
        return name;
    }

    return name;
}
c 内存泄漏 malloc glib

评论

1赞 Yunnosch 9/24/2023
请描述您认为这里发生了什么; 指针会发生什么情况?指针指向的内容会发生什么情况?提示:在这两种情况下,情况可能恰恰相反。name = "dog";
0赞 Retired Ninja 9/24/2023
在这种情况下,避免它的方法是不分配内存,然后通过用指向字符串文本的指针覆盖该指针来立即丢失该指针。更一般的情况是将 every 与 .如果您出于某种原因确实需要动态分配,例如您希望能够修改内容,那么您应该使用它来复制数据,或者它是否可用。mallocfreestrcpystrdup
1赞 Weather Vane 9/24/2023
name = "dog";— .在 C 语言中,不能复制带有 .strcpy(name, "dog");=
3赞 Vlad from Moscow 9/24/2023
@PlsBuffMyBrain 只是不要分配内存:char *name;。仅此而已.:)
0赞 n. m. could be an AI 9/24/2023
有关详细信息,请参阅 stackoverflow.com/questions/72330113/...

答:

1赞 Chris 9/24/2023 #1

您的代码显示了对字符串的非常基本的误解。您已为 300 个值动态分配了一个内存块。返回的不是动态分配的数组,而是指向该动态分配数组中第一个元素的指针。charmalloc

当您分配给指针变量时,它不再指向动态分配的内存块,而是指向字符串文本。您再也无法返回到动态分配的内存。你不能释放它,所以它被泄露了。

您可以使用 (或 ) 将字符串值正确地复制到该内存中。strcpystrncpy

char *func(int val) {
    char *name = malloc(300);
    if (!name) return NULL;

    switch(value) {
    case 0: 
        strcpy(name, "dog");
        break;
   
    case 1:
        strcpy(name, "cat");
        break;
  
    case 2:
        strcpy(name, "elephant");
        break;

    default: 
        strcpy(name, "wrong entry");
    }

    return name;
}
1赞 ptomato 9/25/2023 #2

我不知道您的实际代码中是否是这种情况,但在此示例中,您不需要返回分配的字符串,因为所有可能的返回值都是字符串文字。字符串文本存储在静态数据中,不需要释放。

const char *func(int val) {
    switch(value) {
    case 0: return "dog";
    case 1: return "cat";
    case 2: return "elephant";
    default: return "wrong entry";
}

如果在实际代码中并非所有字符串都是文字,那么由于您使用的是 GLib,请考虑使用其一些字符串操作函数,这些函数已经返回了正确大小的已分配缓冲区,因此您不必自己分配缓冲区并冒着缓冲区溢出的风险。例如:。g_strdup_printf()g_strconcat()

char *func(int val) {
    switch(value) {
    case 0: return g_strdup("dog");
    case 1: return g_strdup("cat");
    case 2: return g_strdup("elephant");
    default: return g_strdup_printf("unknown entry %d", val);
}