这样在函数调用中分配的内存会怎样?

时间:2019-03-09 22:19:25

标签: c memory memory-leaks

我对以下功能和内存分配有疑问。

char    *strjoin(char const *s1, char const *s2)
{
    char    *s3;

    s3 = NULL;
    if (s1 && s2)
    {
        s3 = (char *)malloc(sizeof(char) * (strlen(s1) + strlen(s2) + 1));
        if (!s3)
            return (NULL);
        strcpy(s3, s1);
        strcat(s3, s2);
    }
    return (s3);
}

int main()
{
    char    *s1 = "my favorite animal is";
    char    *s2 = " ";
    char    *s3 = "the nyancat";
    char    *res = strjoin(strjoin(s1, s2), s3);
}

strjoins文档如下:

  

分配(使用malloc(3)),并返回以结尾的“新鲜”字符串   ‘\ 0’,是s1和s2串联的结果。如果分配   失败的函数将返回NULL。

在主函数中,该函数在以下行调用自身:

  

char * res = strjoin(strjoin(s1,s2),s3);

由于内存是在strjoin(s1,s2)中分配的,但从未分配给任何东西,并且它已在外部函数调用中使用,但从技术上讲从来没有释放过,所以该内存是否泄漏并变为未使用状态?

1 个答案:

答案 0 :(得分:1)

是的,内部调用不会泄漏内存。通过将返回值存储在适当的位置,可以轻松避免泄漏:

char    *intermediate;
char    *res = strjoin(intermediate = strjoin(s1, s2), s3);
free(intermediate);

char    *intermediate = strjoin(s1, s2);
char    *res = strjoin(intermediate, s3);
free(intermediate);

但是,如果这是一个托管系统,则操作系统main函数/在调用exit时将释放内存。除非您要对嵌入式设备,设备驱动程序或操作系统进行编程,否则很有可能瞄准的是托管平台。


现在,根据编译器是否聪明,它可能实际上不为该程序分配任何内存,因为不需要结果。

考虑稍作更改的程序:

#include <stdlib.h>
#include <string.h>

static inline __attribute__((always_inline)) char *strjoin(char const *s1, char const *s2)
{
    char    *s3; 
    s3 = NULL;

    if (s1 && s2) {
        s3 = malloc(strlen(s1) + strlen(s2) + 1);
        strcpy(s3, s1);
        strcat(s3, s2);
    }

    return s3;
}

int main()
{
    char    *s1 = "my favorite animal is";
    char    *s2 = " ";
    char    *s3 = "the nyancat";
    char    *res = strjoin(strjoin(s1, s2), s3);
}

我已向函数中添加了static inline __attribute__((always_inline)),以便只能在文件范围中看到它,而不能从其他.c文件中看到它(它不会具有外部链接),并且该功能将始终内联;我还删除了 malloc 的返回值检查,因为它似乎阻碍了GCC推断此处将发生的情况的能力。(它以某种方式认为跟踪{{ NULL的1}}状态是相关的。

如果您使用latest GCC trunk来编译具有最高优化级别的程序,则编译器会注意到所有计算都是无用的,并且会编译a much simpler program

malloc

(请参阅中间窗格中的相同程序集)将具有same observable behaviour,但甚至不会调用int main(void) { }